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/arm64/OWNERS b/src/arm64/OWNERS
new file mode 100644
index 0000000..906a5ce
--- /dev/null
+++ b/src/arm64/OWNERS
@@ -0,0 +1 @@
+rmcilroy@chromium.org
diff --git a/src/arm64/assembler-arm64-inl.h b/src/arm64/assembler-arm64-inl.h
new file mode 100644
index 0000000..5e1bed1
--- /dev/null
+++ b/src/arm64/assembler-arm64-inl.h
@@ -0,0 +1,1272 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_ASSEMBLER_ARM64_INL_H_
+#define V8_ARM64_ASSEMBLER_ARM64_INL_H_
+
+#include "src/arm64/assembler-arm64.h"
+#include "src/assembler.h"
+#include "src/debug.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+bool CpuFeatures::SupportsCrankshaft() { return true; }
+
+
+void RelocInfo::apply(intptr_t delta, ICacheFlushMode icache_flush_mode) {
+  UNIMPLEMENTED();
+}
+
+
+void RelocInfo::set_target_address(Address target,
+                                   WriteBarrierMode write_barrier_mode,
+                                   ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
+  Assembler::set_target_address_at(pc_, host_, target, icache_flush_mode);
+  if (write_barrier_mode == UPDATE_WRITE_BARRIER && host() != NULL &&
+      IsCodeTarget(rmode_)) {
+    Object* target_code = Code::GetCodeFromTargetAddress(target);
+    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
+        host(), this, HeapObject::cast(target_code));
+  }
+}
+
+
+inline unsigned CPURegister::code() const {
+  DCHECK(IsValid());
+  return reg_code;
+}
+
+
+inline CPURegister::RegisterType CPURegister::type() const {
+  DCHECK(IsValidOrNone());
+  return reg_type;
+}
+
+
+inline RegList CPURegister::Bit() const {
+  DCHECK(reg_code < (sizeof(RegList) * kBitsPerByte));
+  return IsValid() ? 1UL << reg_code : 0;
+}
+
+
+inline unsigned CPURegister::SizeInBits() const {
+  DCHECK(IsValid());
+  return reg_size;
+}
+
+
+inline int CPURegister::SizeInBytes() const {
+  DCHECK(IsValid());
+  DCHECK(SizeInBits() % 8 == 0);
+  return reg_size / 8;
+}
+
+
+inline bool CPURegister::Is32Bits() const {
+  DCHECK(IsValid());
+  return reg_size == 32;
+}
+
+
+inline bool CPURegister::Is64Bits() const {
+  DCHECK(IsValid());
+  return reg_size == 64;
+}
+
+
+inline bool CPURegister::IsValid() const {
+  if (IsValidRegister() || IsValidFPRegister()) {
+    DCHECK(!IsNone());
+    return true;
+  } else {
+    DCHECK(IsNone());
+    return false;
+  }
+}
+
+
+inline bool CPURegister::IsValidRegister() const {
+  return IsRegister() &&
+         ((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits)) &&
+         ((reg_code < kNumberOfRegisters) || (reg_code == kSPRegInternalCode));
+}
+
+
+inline bool CPURegister::IsValidFPRegister() const {
+  return IsFPRegister() &&
+         ((reg_size == kSRegSizeInBits) || (reg_size == kDRegSizeInBits)) &&
+         (reg_code < kNumberOfFPRegisters);
+}
+
+
+inline bool CPURegister::IsNone() const {
+  // kNoRegister types should always have size 0 and code 0.
+  DCHECK((reg_type != kNoRegister) || (reg_code == 0));
+  DCHECK((reg_type != kNoRegister) || (reg_size == 0));
+
+  return reg_type == kNoRegister;
+}
+
+
+inline bool CPURegister::Is(const CPURegister& other) const {
+  DCHECK(IsValidOrNone() && other.IsValidOrNone());
+  return Aliases(other) && (reg_size == other.reg_size);
+}
+
+
+inline bool CPURegister::Aliases(const CPURegister& other) const {
+  DCHECK(IsValidOrNone() && other.IsValidOrNone());
+  return (reg_code == other.reg_code) && (reg_type == other.reg_type);
+}
+
+
+inline bool CPURegister::IsRegister() const {
+  return reg_type == kRegister;
+}
+
+
+inline bool CPURegister::IsFPRegister() const {
+  return reg_type == kFPRegister;
+}
+
+
+inline bool CPURegister::IsSameSizeAndType(const CPURegister& other) const {
+  return (reg_size == other.reg_size) && (reg_type == other.reg_type);
+}
+
+
+inline bool CPURegister::IsValidOrNone() const {
+  return IsValid() || IsNone();
+}
+
+
+inline bool CPURegister::IsZero() const {
+  DCHECK(IsValid());
+  return IsRegister() && (reg_code == kZeroRegCode);
+}
+
+
+inline bool CPURegister::IsSP() const {
+  DCHECK(IsValid());
+  return IsRegister() && (reg_code == kSPRegInternalCode);
+}
+
+
+inline void CPURegList::Combine(const CPURegList& other) {
+  DCHECK(IsValid());
+  DCHECK(other.type() == type_);
+  DCHECK(other.RegisterSizeInBits() == size_);
+  list_ |= other.list();
+}
+
+
+inline void CPURegList::Remove(const CPURegList& other) {
+  DCHECK(IsValid());
+  if (other.type() == type_) {
+    list_ &= ~other.list();
+  }
+}
+
+
+inline void CPURegList::Combine(const CPURegister& other) {
+  DCHECK(other.type() == type_);
+  DCHECK(other.SizeInBits() == size_);
+  Combine(other.code());
+}
+
+
+inline void CPURegList::Remove(const CPURegister& other1,
+                               const CPURegister& other2,
+                               const CPURegister& other3,
+                               const CPURegister& other4) {
+  if (!other1.IsNone() && (other1.type() == type_)) Remove(other1.code());
+  if (!other2.IsNone() && (other2.type() == type_)) Remove(other2.code());
+  if (!other3.IsNone() && (other3.type() == type_)) Remove(other3.code());
+  if (!other4.IsNone() && (other4.type() == type_)) Remove(other4.code());
+}
+
+
+inline void CPURegList::Combine(int code) {
+  DCHECK(IsValid());
+  DCHECK(CPURegister::Create(code, size_, type_).IsValid());
+  list_ |= (1UL << code);
+}
+
+
+inline void CPURegList::Remove(int code) {
+  DCHECK(IsValid());
+  DCHECK(CPURegister::Create(code, size_, type_).IsValid());
+  list_ &= ~(1UL << code);
+}
+
+
+inline Register Register::XRegFromCode(unsigned code) {
+  if (code == kSPRegInternalCode) {
+    return csp;
+  } else {
+    DCHECK(code < kNumberOfRegisters);
+    return Register::Create(code, kXRegSizeInBits);
+  }
+}
+
+
+inline Register Register::WRegFromCode(unsigned code) {
+  if (code == kSPRegInternalCode) {
+    return wcsp;
+  } else {
+    DCHECK(code < kNumberOfRegisters);
+    return Register::Create(code, kWRegSizeInBits);
+  }
+}
+
+
+inline FPRegister FPRegister::SRegFromCode(unsigned code) {
+  DCHECK(code < kNumberOfFPRegisters);
+  return FPRegister::Create(code, kSRegSizeInBits);
+}
+
+
+inline FPRegister FPRegister::DRegFromCode(unsigned code) {
+  DCHECK(code < kNumberOfFPRegisters);
+  return FPRegister::Create(code, kDRegSizeInBits);
+}
+
+
+inline Register CPURegister::W() const {
+  DCHECK(IsValidRegister());
+  return Register::WRegFromCode(reg_code);
+}
+
+
+inline Register CPURegister::X() const {
+  DCHECK(IsValidRegister());
+  return Register::XRegFromCode(reg_code);
+}
+
+
+inline FPRegister CPURegister::S() const {
+  DCHECK(IsValidFPRegister());
+  return FPRegister::SRegFromCode(reg_code);
+}
+
+
+inline FPRegister CPURegister::D() const {
+  DCHECK(IsValidFPRegister());
+  return FPRegister::DRegFromCode(reg_code);
+}
+
+
+// Immediate.
+// Default initializer is for int types
+template<typename T>
+struct ImmediateInitializer {
+  static const bool kIsIntType = true;
+  static inline RelocInfo::Mode rmode_for(T) {
+    return sizeof(T) == 8 ? RelocInfo::NONE64 : RelocInfo::NONE32;
+  }
+  static inline int64_t immediate_for(T t) {
+    STATIC_ASSERT(sizeof(T) <= 8);
+    return t;
+  }
+};
+
+
+template<>
+struct ImmediateInitializer<Smi*> {
+  static const bool kIsIntType = false;
+  static inline RelocInfo::Mode rmode_for(Smi* t) {
+    return RelocInfo::NONE64;
+  }
+  static inline int64_t immediate_for(Smi* t) {;
+    return reinterpret_cast<int64_t>(t);
+  }
+};
+
+
+template<>
+struct ImmediateInitializer<ExternalReference> {
+  static const bool kIsIntType = false;
+  static inline RelocInfo::Mode rmode_for(ExternalReference t) {
+    return RelocInfo::EXTERNAL_REFERENCE;
+  }
+  static inline int64_t immediate_for(ExternalReference t) {;
+    return reinterpret_cast<int64_t>(t.address());
+  }
+};
+
+
+template<typename T>
+Immediate::Immediate(Handle<T> value) {
+  InitializeHandle(value);
+}
+
+
+template<typename T>
+Immediate::Immediate(T t)
+    : value_(ImmediateInitializer<T>::immediate_for(t)),
+      rmode_(ImmediateInitializer<T>::rmode_for(t)) {}
+
+
+template<typename T>
+Immediate::Immediate(T t, RelocInfo::Mode rmode)
+    : value_(ImmediateInitializer<T>::immediate_for(t)),
+      rmode_(rmode) {
+  STATIC_ASSERT(ImmediateInitializer<T>::kIsIntType);
+}
+
+
+// Operand.
+template<typename T>
+Operand::Operand(Handle<T> value) : immediate_(value), reg_(NoReg) {}
+
+
+template<typename T>
+Operand::Operand(T t) : immediate_(t), reg_(NoReg) {}
+
+
+template<typename T>
+Operand::Operand(T t, RelocInfo::Mode rmode)
+    : immediate_(t, rmode),
+      reg_(NoReg) {}
+
+
+Operand::Operand(Register reg, Shift shift, unsigned shift_amount)
+    : immediate_(0),
+      reg_(reg),
+      shift_(shift),
+      extend_(NO_EXTEND),
+      shift_amount_(shift_amount) {
+  DCHECK(reg.Is64Bits() || (shift_amount < kWRegSizeInBits));
+  DCHECK(reg.Is32Bits() || (shift_amount < kXRegSizeInBits));
+  DCHECK(!reg.IsSP());
+}
+
+
+Operand::Operand(Register reg, Extend extend, unsigned shift_amount)
+    : immediate_(0),
+      reg_(reg),
+      shift_(NO_SHIFT),
+      extend_(extend),
+      shift_amount_(shift_amount) {
+  DCHECK(reg.IsValid());
+  DCHECK(shift_amount <= 4);
+  DCHECK(!reg.IsSP());
+
+  // Extend modes SXTX and UXTX require a 64-bit register.
+  DCHECK(reg.Is64Bits() || ((extend != SXTX) && (extend != UXTX)));
+}
+
+
+bool Operand::IsImmediate() const {
+  return reg_.Is(NoReg);
+}
+
+
+bool Operand::IsShiftedRegister() const {
+  return reg_.IsValid() && (shift_ != NO_SHIFT);
+}
+
+
+bool Operand::IsExtendedRegister() const {
+  return reg_.IsValid() && (extend_ != NO_EXTEND);
+}
+
+
+bool Operand::IsZero() const {
+  if (IsImmediate()) {
+    return ImmediateValue() == 0;
+  } else {
+    return reg().IsZero();
+  }
+}
+
+
+Operand Operand::ToExtendedRegister() const {
+  DCHECK(IsShiftedRegister());
+  DCHECK((shift_ == LSL) && (shift_amount_ <= 4));
+  return Operand(reg_, reg_.Is64Bits() ? UXTX : UXTW, shift_amount_);
+}
+
+
+Immediate Operand::immediate() const {
+  DCHECK(IsImmediate());
+  return immediate_;
+}
+
+
+int64_t Operand::ImmediateValue() const {
+  DCHECK(IsImmediate());
+  return immediate_.value();
+}
+
+
+Register Operand::reg() const {
+  DCHECK(IsShiftedRegister() || IsExtendedRegister());
+  return reg_;
+}
+
+
+Shift Operand::shift() const {
+  DCHECK(IsShiftedRegister());
+  return shift_;
+}
+
+
+Extend Operand::extend() const {
+  DCHECK(IsExtendedRegister());
+  return extend_;
+}
+
+
+unsigned Operand::shift_amount() const {
+  DCHECK(IsShiftedRegister() || IsExtendedRegister());
+  return shift_amount_;
+}
+
+
+Operand Operand::UntagSmi(Register smi) {
+  STATIC_ASSERT(kXRegSizeInBits == static_cast<unsigned>(kSmiShift +
+                                                         kSmiValueSize));
+  DCHECK(smi.Is64Bits());
+  return Operand(smi, ASR, kSmiShift);
+}
+
+
+Operand Operand::UntagSmiAndScale(Register smi, int scale) {
+  STATIC_ASSERT(kXRegSizeInBits == static_cast<unsigned>(kSmiShift +
+                                                         kSmiValueSize));
+  DCHECK(smi.Is64Bits());
+  DCHECK((scale >= 0) && (scale <= (64 - kSmiValueSize)));
+  if (scale > kSmiShift) {
+    return Operand(smi, LSL, scale - kSmiShift);
+  } else if (scale < kSmiShift) {
+    return Operand(smi, ASR, kSmiShift - scale);
+  }
+  return Operand(smi);
+}
+
+
+MemOperand::MemOperand()
+  : base_(NoReg), regoffset_(NoReg), offset_(0), addrmode_(Offset),
+    shift_(NO_SHIFT), extend_(NO_EXTEND), shift_amount_(0) {
+}
+
+
+MemOperand::MemOperand(Register base, int64_t offset, AddrMode addrmode)
+  : base_(base), regoffset_(NoReg), offset_(offset), addrmode_(addrmode),
+    shift_(NO_SHIFT), extend_(NO_EXTEND), shift_amount_(0) {
+  DCHECK(base.Is64Bits() && !base.IsZero());
+}
+
+
+MemOperand::MemOperand(Register base,
+                       Register regoffset,
+                       Extend extend,
+                       unsigned shift_amount)
+  : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
+    shift_(NO_SHIFT), extend_(extend), shift_amount_(shift_amount) {
+  DCHECK(base.Is64Bits() && !base.IsZero());
+  DCHECK(!regoffset.IsSP());
+  DCHECK((extend == UXTW) || (extend == SXTW) || (extend == SXTX));
+
+  // SXTX extend mode requires a 64-bit offset register.
+  DCHECK(regoffset.Is64Bits() || (extend != SXTX));
+}
+
+
+MemOperand::MemOperand(Register base,
+                       Register regoffset,
+                       Shift shift,
+                       unsigned shift_amount)
+  : base_(base), regoffset_(regoffset), offset_(0), addrmode_(Offset),
+    shift_(shift), extend_(NO_EXTEND), shift_amount_(shift_amount) {
+  DCHECK(base.Is64Bits() && !base.IsZero());
+  DCHECK(regoffset.Is64Bits() && !regoffset.IsSP());
+  DCHECK(shift == LSL);
+}
+
+
+MemOperand::MemOperand(Register base, const Operand& offset, AddrMode addrmode)
+  : base_(base), addrmode_(addrmode) {
+  DCHECK(base.Is64Bits() && !base.IsZero());
+
+  if (offset.IsImmediate()) {
+    offset_ = offset.ImmediateValue();
+
+    regoffset_ = NoReg;
+  } else if (offset.IsShiftedRegister()) {
+    DCHECK(addrmode == Offset);
+
+    regoffset_ = offset.reg();
+    shift_= offset.shift();
+    shift_amount_ = offset.shift_amount();
+
+    extend_ = NO_EXTEND;
+    offset_ = 0;
+
+    // These assertions match those in the shifted-register constructor.
+    DCHECK(regoffset_.Is64Bits() && !regoffset_.IsSP());
+    DCHECK(shift_ == LSL);
+  } else {
+    DCHECK(offset.IsExtendedRegister());
+    DCHECK(addrmode == Offset);
+
+    regoffset_ = offset.reg();
+    extend_ = offset.extend();
+    shift_amount_ = offset.shift_amount();
+
+    shift_= NO_SHIFT;
+    offset_ = 0;
+
+    // These assertions match those in the extended-register constructor.
+    DCHECK(!regoffset_.IsSP());
+    DCHECK((extend_ == UXTW) || (extend_ == SXTW) || (extend_ == SXTX));
+    DCHECK((regoffset_.Is64Bits() || (extend_ != SXTX)));
+  }
+}
+
+bool MemOperand::IsImmediateOffset() const {
+  return (addrmode_ == Offset) && regoffset_.Is(NoReg);
+}
+
+
+bool MemOperand::IsRegisterOffset() const {
+  return (addrmode_ == Offset) && !regoffset_.Is(NoReg);
+}
+
+
+bool MemOperand::IsPreIndex() const {
+  return addrmode_ == PreIndex;
+}
+
+
+bool MemOperand::IsPostIndex() const {
+  return addrmode_ == PostIndex;
+}
+
+Operand MemOperand::OffsetAsOperand() const {
+  if (IsImmediateOffset()) {
+    return offset();
+  } else {
+    DCHECK(IsRegisterOffset());
+    if (extend() == NO_EXTEND) {
+      return Operand(regoffset(), shift(), shift_amount());
+    } else {
+      return Operand(regoffset(), extend(), shift_amount());
+    }
+  }
+}
+
+
+void Assembler::Unreachable() {
+#ifdef USE_SIMULATOR
+  debug("UNREACHABLE", __LINE__, BREAK);
+#else
+  // Crash by branching to 0. lr now points near the fault.
+  Emit(BLR | Rn(xzr));
+#endif
+}
+
+
+Address Assembler::target_pointer_address_at(Address pc) {
+  Instruction* instr = reinterpret_cast<Instruction*>(pc);
+  DCHECK(instr->IsLdrLiteralX());
+  return reinterpret_cast<Address>(instr->ImmPCOffsetTarget());
+}
+
+
+// Read/Modify the code target address in the branch/call instruction at pc.
+Address Assembler::target_address_at(Address pc,
+                                     ConstantPoolArray* constant_pool) {
+  return Memory::Address_at(target_pointer_address_at(pc));
+}
+
+
+Address Assembler::target_address_at(Address pc, Code* code) {
+  ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
+  return target_address_at(pc, constant_pool);
+}
+
+
+Address Assembler::target_address_from_return_address(Address pc) {
+  // Returns the address of the call target from the return address that will
+  // be returned to after a call.
+  // Call sequence on ARM64 is:
+  //  ldr ip0, #... @ load from literal pool
+  //  blr ip0
+  Address candidate = pc - 2 * kInstructionSize;
+  Instruction* instr = reinterpret_cast<Instruction*>(candidate);
+  USE(instr);
+  DCHECK(instr->IsLdrLiteralX());
+  return candidate;
+}
+
+
+Address Assembler::break_address_from_return_address(Address pc) {
+  return pc - Assembler::kPatchDebugBreakSlotReturnOffset;
+}
+
+
+Address Assembler::return_address_from_call_start(Address pc) {
+  // The call, generated by MacroAssembler::Call, is one of two possible
+  // sequences:
+  //
+  // Without relocation:
+  //  movz  temp, #(target & 0x000000000000ffff)
+  //  movk  temp, #(target & 0x00000000ffff0000)
+  //  movk  temp, #(target & 0x0000ffff00000000)
+  //  blr   temp
+  //
+  // With relocation:
+  //  ldr   temp, =target
+  //  blr   temp
+  //
+  // The return address is immediately after the blr instruction in both cases,
+  // so it can be found by adding the call size to the address at the start of
+  // the call sequence.
+  STATIC_ASSERT(Assembler::kCallSizeWithoutRelocation == 4 * kInstructionSize);
+  STATIC_ASSERT(Assembler::kCallSizeWithRelocation == 2 * kInstructionSize);
+
+  Instruction* instr = reinterpret_cast<Instruction*>(pc);
+  if (instr->IsMovz()) {
+    // Verify the instruction sequence.
+    DCHECK(instr->following(1)->IsMovk());
+    DCHECK(instr->following(2)->IsMovk());
+    DCHECK(instr->following(3)->IsBranchAndLinkToRegister());
+    return pc + Assembler::kCallSizeWithoutRelocation;
+  } else {
+    // Verify the instruction sequence.
+    DCHECK(instr->IsLdrLiteralX());
+    DCHECK(instr->following(1)->IsBranchAndLinkToRegister());
+    return pc + Assembler::kCallSizeWithRelocation;
+  }
+}
+
+
+void Assembler::deserialization_set_special_target_at(
+    Address constant_pool_entry, Code* code, Address target) {
+  Memory::Address_at(constant_pool_entry) = target;
+}
+
+
+void Assembler::set_target_address_at(Address pc,
+                                      ConstantPoolArray* constant_pool,
+                                      Address target,
+                                      ICacheFlushMode icache_flush_mode) {
+  Memory::Address_at(target_pointer_address_at(pc)) = target;
+  // Intuitively, we would think it is necessary to always flush the
+  // instruction cache after patching a target address in the code as follows:
+  //   CpuFeatures::FlushICache(pc, sizeof(target));
+  // However, on ARM, an instruction is actually patched in the case of
+  // embedded constants of the form:
+  // ldr   ip, [pc, #...]
+  // since the instruction accessing this address in the constant pool remains
+  // unchanged, a flush is not required.
+}
+
+
+void Assembler::set_target_address_at(Address pc,
+                                      Code* code,
+                                      Address target,
+                                      ICacheFlushMode icache_flush_mode) {
+  ConstantPoolArray* constant_pool = code ? code->constant_pool() : NULL;
+  set_target_address_at(pc, constant_pool, target, icache_flush_mode);
+}
+
+
+int RelocInfo::target_address_size() {
+  return kPointerSize;
+}
+
+
+Address RelocInfo::target_address() {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_));
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+Address RelocInfo::target_address_address() {
+  DCHECK(IsCodeTarget(rmode_) || IsRuntimeEntry(rmode_)
+                              || rmode_ == EMBEDDED_OBJECT
+                              || rmode_ == EXTERNAL_REFERENCE);
+  return Assembler::target_pointer_address_at(pc_);
+}
+
+
+Address RelocInfo::constant_pool_entry_address() {
+  DCHECK(IsInConstantPool());
+  return Assembler::target_pointer_address_at(pc_);
+}
+
+
+Object* RelocInfo::target_object() {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return reinterpret_cast<Object*>(Assembler::target_address_at(pc_, host_));
+}
+
+
+Handle<Object> RelocInfo::target_object_handle(Assembler* origin) {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  return Handle<Object>(reinterpret_cast<Object**>(
+      Assembler::target_address_at(pc_, host_)));
+}
+
+
+void RelocInfo::set_target_object(Object* target,
+                                  WriteBarrierMode write_barrier_mode,
+                                  ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT);
+  Assembler::set_target_address_at(pc_, host_,
+                                   reinterpret_cast<Address>(target),
+                                   icache_flush_mode);
+  if (write_barrier_mode == UPDATE_WRITE_BARRIER &&
+      host() != NULL &&
+      target->IsHeapObject()) {
+    host()->GetHeap()->incremental_marking()->RecordWrite(
+        host(), &Memory::Object_at(pc_), HeapObject::cast(target));
+  }
+}
+
+
+Address RelocInfo::target_reference() {
+  DCHECK(rmode_ == EXTERNAL_REFERENCE);
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+Address RelocInfo::target_runtime_entry(Assembler* origin) {
+  DCHECK(IsRuntimeEntry(rmode_));
+  return target_address();
+}
+
+
+void RelocInfo::set_target_runtime_entry(Address target,
+                                         WriteBarrierMode write_barrier_mode,
+                                         ICacheFlushMode icache_flush_mode) {
+  DCHECK(IsRuntimeEntry(rmode_));
+  if (target_address() != target) {
+    set_target_address(target, write_barrier_mode, icache_flush_mode);
+  }
+}
+
+
+Handle<Cell> RelocInfo::target_cell_handle() {
+  UNIMPLEMENTED();
+  Cell *null_cell = NULL;
+  return Handle<Cell>(null_cell);
+}
+
+
+Cell* RelocInfo::target_cell() {
+  DCHECK(rmode_ == RelocInfo::CELL);
+  return Cell::FromValueAddress(Memory::Address_at(pc_));
+}
+
+
+void RelocInfo::set_target_cell(Cell* cell,
+                                WriteBarrierMode write_barrier_mode,
+                                ICacheFlushMode icache_flush_mode) {
+  UNIMPLEMENTED();
+}
+
+
+static const int kNoCodeAgeSequenceLength = 5 * kInstructionSize;
+static const int kCodeAgeStubEntryOffset = 3 * kInstructionSize;
+
+
+Handle<Object> RelocInfo::code_age_stub_handle(Assembler* origin) {
+  UNREACHABLE();  // This should never be reached on ARM64.
+  return Handle<Object>();
+}
+
+
+Code* RelocInfo::code_age_stub() {
+  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  // Read the stub entry point from the code age sequence.
+  Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
+  return Code::GetCodeFromTargetAddress(Memory::Address_at(stub_entry_address));
+}
+
+
+void RelocInfo::set_code_age_stub(Code* stub,
+                                  ICacheFlushMode icache_flush_mode) {
+  DCHECK(rmode_ == RelocInfo::CODE_AGE_SEQUENCE);
+  DCHECK(!Code::IsYoungSequence(stub->GetIsolate(), pc_));
+  // Overwrite the stub entry point in the code age sequence. This is loaded as
+  // a literal so there is no need to call FlushICache here.
+  Address stub_entry_address = pc_ + kCodeAgeStubEntryOffset;
+  Memory::Address_at(stub_entry_address) = stub->instruction_start();
+}
+
+
+Address RelocInfo::call_address() {
+  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+  // For the above sequences the Relocinfo points to the load literal loading
+  // the call address.
+  return Assembler::target_address_at(pc_, host_);
+}
+
+
+void RelocInfo::set_call_address(Address target) {
+  DCHECK((IsJSReturn(rmode()) && IsPatchedReturnSequence()) ||
+         (IsDebugBreakSlot(rmode()) && IsPatchedDebugBreakSlotSequence()));
+  Assembler::set_target_address_at(pc_, host_, target);
+  if (host() != NULL) {
+    Object* target_code = Code::GetCodeFromTargetAddress(target);
+    host()->GetHeap()->incremental_marking()->RecordWriteIntoCode(
+        host(), this, HeapObject::cast(target_code));
+  }
+}
+
+
+void RelocInfo::WipeOut() {
+  DCHECK(IsEmbeddedObject(rmode_) ||
+         IsCodeTarget(rmode_) ||
+         IsRuntimeEntry(rmode_) ||
+         IsExternalReference(rmode_));
+  Assembler::set_target_address_at(pc_, host_, NULL);
+}
+
+
+bool RelocInfo::IsPatchedReturnSequence() {
+  // The sequence must be:
+  //   ldr ip0, [pc, #offset]
+  //   blr ip0
+  // See arm64/debug-arm64.cc BreakLocationIterator::SetDebugBreakAtReturn().
+  Instruction* i1 = reinterpret_cast<Instruction*>(pc_);
+  Instruction* i2 = i1->following();
+  return i1->IsLdrLiteralX() && (i1->Rt() == ip0.code()) &&
+         i2->IsBranchAndLinkToRegister() && (i2->Rn() == ip0.code());
+}
+
+
+bool RelocInfo::IsPatchedDebugBreakSlotSequence() {
+  Instruction* current_instr = reinterpret_cast<Instruction*>(pc_);
+  return !current_instr->IsNop(Assembler::DEBUG_BREAK_NOP);
+}
+
+
+void RelocInfo::Visit(Isolate* isolate, ObjectVisitor* visitor) {
+  RelocInfo::Mode mode = rmode();
+  if (mode == RelocInfo::EMBEDDED_OBJECT) {
+    visitor->VisitEmbeddedPointer(this);
+  } else if (RelocInfo::IsCodeTarget(mode)) {
+    visitor->VisitCodeTarget(this);
+  } else if (mode == RelocInfo::CELL) {
+    visitor->VisitCell(this);
+  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+    visitor->VisitExternalReference(this);
+  } else if (((RelocInfo::IsJSReturn(mode) &&
+              IsPatchedReturnSequence()) ||
+             (RelocInfo::IsDebugBreakSlot(mode) &&
+              IsPatchedDebugBreakSlotSequence())) &&
+             isolate->debug()->has_break_points()) {
+    visitor->VisitDebugTarget(this);
+  } else if (RelocInfo::IsRuntimeEntry(mode)) {
+    visitor->VisitRuntimeEntry(this);
+  }
+}
+
+
+template<typename StaticVisitor>
+void RelocInfo::Visit(Heap* heap) {
+  RelocInfo::Mode mode = rmode();
+  if (mode == RelocInfo::EMBEDDED_OBJECT) {
+    StaticVisitor::VisitEmbeddedPointer(heap, this);
+  } else if (RelocInfo::IsCodeTarget(mode)) {
+    StaticVisitor::VisitCodeTarget(heap, this);
+  } else if (mode == RelocInfo::CELL) {
+    StaticVisitor::VisitCell(heap, this);
+  } else if (mode == RelocInfo::EXTERNAL_REFERENCE) {
+    StaticVisitor::VisitExternalReference(this);
+  } else if (heap->isolate()->debug()->has_break_points() &&
+             ((RelocInfo::IsJSReturn(mode) &&
+              IsPatchedReturnSequence()) ||
+             (RelocInfo::IsDebugBreakSlot(mode) &&
+              IsPatchedDebugBreakSlotSequence()))) {
+    StaticVisitor::VisitDebugTarget(heap, this);
+  } else if (RelocInfo::IsRuntimeEntry(mode)) {
+    StaticVisitor::VisitRuntimeEntry(this);
+  }
+}
+
+
+LoadStoreOp Assembler::LoadOpFor(const CPURegister& rt) {
+  DCHECK(rt.IsValid());
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? LDR_x : LDR_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? LDR_d : LDR_s;
+  }
+}
+
+
+LoadStorePairOp Assembler::LoadPairOpFor(const CPURegister& rt,
+                                         const CPURegister& rt2) {
+  DCHECK(AreSameSizeAndType(rt, rt2));
+  USE(rt2);
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? LDP_x : LDP_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? LDP_d : LDP_s;
+  }
+}
+
+
+LoadStoreOp Assembler::StoreOpFor(const CPURegister& rt) {
+  DCHECK(rt.IsValid());
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? STR_x : STR_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? STR_d : STR_s;
+  }
+}
+
+
+LoadStorePairOp Assembler::StorePairOpFor(const CPURegister& rt,
+                                          const CPURegister& rt2) {
+  DCHECK(AreSameSizeAndType(rt, rt2));
+  USE(rt2);
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? STP_x : STP_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? STP_d : STP_s;
+  }
+}
+
+
+LoadStorePairNonTemporalOp Assembler::LoadPairNonTemporalOpFor(
+    const CPURegister& rt, const CPURegister& rt2) {
+  DCHECK(AreSameSizeAndType(rt, rt2));
+  USE(rt2);
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? LDNP_x : LDNP_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? LDNP_d : LDNP_s;
+  }
+}
+
+
+LoadStorePairNonTemporalOp Assembler::StorePairNonTemporalOpFor(
+    const CPURegister& rt, const CPURegister& rt2) {
+  DCHECK(AreSameSizeAndType(rt, rt2));
+  USE(rt2);
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? STNP_x : STNP_w;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? STNP_d : STNP_s;
+  }
+}
+
+
+LoadLiteralOp Assembler::LoadLiteralOpFor(const CPURegister& rt) {
+  if (rt.IsRegister()) {
+    return rt.Is64Bits() ? LDR_x_lit : LDR_w_lit;
+  } else {
+    DCHECK(rt.IsFPRegister());
+    return rt.Is64Bits() ? LDR_d_lit : LDR_s_lit;
+  }
+}
+
+
+int Assembler::LinkAndGetInstructionOffsetTo(Label* label) {
+  DCHECK(kStartOfLabelLinkChain == 0);
+  int offset = LinkAndGetByteOffsetTo(label);
+  DCHECK(IsAligned(offset, kInstructionSize));
+  return offset >> kInstructionSizeLog2;
+}
+
+
+Instr Assembler::Flags(FlagsUpdate S) {
+  if (S == SetFlags) {
+    return 1 << FlagsUpdate_offset;
+  } else if (S == LeaveFlags) {
+    return 0 << FlagsUpdate_offset;
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+
+Instr Assembler::Cond(Condition cond) {
+  return cond << Condition_offset;
+}
+
+
+Instr Assembler::ImmPCRelAddress(int imm21) {
+  CHECK(is_int21(imm21));
+  Instr imm = static_cast<Instr>(truncate_to_int21(imm21));
+  Instr immhi = (imm >> ImmPCRelLo_width) << ImmPCRelHi_offset;
+  Instr immlo = imm << ImmPCRelLo_offset;
+  return (immhi & ImmPCRelHi_mask) | (immlo & ImmPCRelLo_mask);
+}
+
+
+Instr Assembler::ImmUncondBranch(int imm26) {
+  CHECK(is_int26(imm26));
+  return truncate_to_int26(imm26) << ImmUncondBranch_offset;
+}
+
+
+Instr Assembler::ImmCondBranch(int imm19) {
+  CHECK(is_int19(imm19));
+  return truncate_to_int19(imm19) << ImmCondBranch_offset;
+}
+
+
+Instr Assembler::ImmCmpBranch(int imm19) {
+  CHECK(is_int19(imm19));
+  return truncate_to_int19(imm19) << ImmCmpBranch_offset;
+}
+
+
+Instr Assembler::ImmTestBranch(int imm14) {
+  CHECK(is_int14(imm14));
+  return truncate_to_int14(imm14) << ImmTestBranch_offset;
+}
+
+
+Instr Assembler::ImmTestBranchBit(unsigned bit_pos) {
+  DCHECK(is_uint6(bit_pos));
+  // Subtract five from the shift offset, as we need bit 5 from bit_pos.
+  unsigned b5 = bit_pos << (ImmTestBranchBit5_offset - 5);
+  unsigned b40 = bit_pos << ImmTestBranchBit40_offset;
+  b5 &= ImmTestBranchBit5_mask;
+  b40 &= ImmTestBranchBit40_mask;
+  return b5 | b40;
+}
+
+
+Instr Assembler::SF(Register rd) {
+    return rd.Is64Bits() ? SixtyFourBits : ThirtyTwoBits;
+}
+
+
+Instr Assembler::ImmAddSub(int64_t imm) {
+  DCHECK(IsImmAddSub(imm));
+  if (is_uint12(imm)) {  // No shift required.
+    return imm << ImmAddSub_offset;
+  } else {
+    return ((imm >> 12) << ImmAddSub_offset) | (1 << ShiftAddSub_offset);
+  }
+}
+
+
+Instr Assembler::ImmS(unsigned imms, unsigned reg_size) {
+  DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(imms)) ||
+         ((reg_size == kWRegSizeInBits) && is_uint5(imms)));
+  USE(reg_size);
+  return imms << ImmS_offset;
+}
+
+
+Instr Assembler::ImmR(unsigned immr, unsigned reg_size) {
+  DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
+         ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
+  USE(reg_size);
+  DCHECK(is_uint6(immr));
+  return immr << ImmR_offset;
+}
+
+
+Instr Assembler::ImmSetBits(unsigned imms, unsigned reg_size) {
+  DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
+  DCHECK(is_uint6(imms));
+  DCHECK((reg_size == kXRegSizeInBits) || is_uint6(imms + 3));
+  USE(reg_size);
+  return imms << ImmSetBits_offset;
+}
+
+
+Instr Assembler::ImmRotate(unsigned immr, unsigned reg_size) {
+  DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
+  DCHECK(((reg_size == kXRegSizeInBits) && is_uint6(immr)) ||
+         ((reg_size == kWRegSizeInBits) && is_uint5(immr)));
+  USE(reg_size);
+  return immr << ImmRotate_offset;
+}
+
+
+Instr Assembler::ImmLLiteral(int imm19) {
+  CHECK(is_int19(imm19));
+  return truncate_to_int19(imm19) << ImmLLiteral_offset;
+}
+
+
+Instr Assembler::BitN(unsigned bitn, unsigned reg_size) {
+  DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
+  DCHECK((reg_size == kXRegSizeInBits) || (bitn == 0));
+  USE(reg_size);
+  return bitn << BitN_offset;
+}
+
+
+Instr Assembler::ShiftDP(Shift shift) {
+  DCHECK(shift == LSL || shift == LSR || shift == ASR || shift == ROR);
+  return shift << ShiftDP_offset;
+}
+
+
+Instr Assembler::ImmDPShift(unsigned amount) {
+  DCHECK(is_uint6(amount));
+  return amount << ImmDPShift_offset;
+}
+
+
+Instr Assembler::ExtendMode(Extend extend) {
+  return extend << ExtendMode_offset;
+}
+
+
+Instr Assembler::ImmExtendShift(unsigned left_shift) {
+  DCHECK(left_shift <= 4);
+  return left_shift << ImmExtendShift_offset;
+}
+
+
+Instr Assembler::ImmCondCmp(unsigned imm) {
+  DCHECK(is_uint5(imm));
+  return imm << ImmCondCmp_offset;
+}
+
+
+Instr Assembler::Nzcv(StatusFlags nzcv) {
+  return ((nzcv >> Flags_offset) & 0xf) << Nzcv_offset;
+}
+
+
+Instr Assembler::ImmLSUnsigned(int imm12) {
+  DCHECK(is_uint12(imm12));
+  return imm12 << ImmLSUnsigned_offset;
+}
+
+
+Instr Assembler::ImmLS(int imm9) {
+  DCHECK(is_int9(imm9));
+  return truncate_to_int9(imm9) << ImmLS_offset;
+}
+
+
+Instr Assembler::ImmLSPair(int imm7, LSDataSize size) {
+  DCHECK(((imm7 >> size) << size) == imm7);
+  int scaled_imm7 = imm7 >> size;
+  DCHECK(is_int7(scaled_imm7));
+  return truncate_to_int7(scaled_imm7) << ImmLSPair_offset;
+}
+
+
+Instr Assembler::ImmShiftLS(unsigned shift_amount) {
+  DCHECK(is_uint1(shift_amount));
+  return shift_amount << ImmShiftLS_offset;
+}
+
+
+Instr Assembler::ImmException(int imm16) {
+  DCHECK(is_uint16(imm16));
+  return imm16 << ImmException_offset;
+}
+
+
+Instr Assembler::ImmSystemRegister(int imm15) {
+  DCHECK(is_uint15(imm15));
+  return imm15 << ImmSystemRegister_offset;
+}
+
+
+Instr Assembler::ImmHint(int imm7) {
+  DCHECK(is_uint7(imm7));
+  return imm7 << ImmHint_offset;
+}
+
+
+Instr Assembler::ImmBarrierDomain(int imm2) {
+  DCHECK(is_uint2(imm2));
+  return imm2 << ImmBarrierDomain_offset;
+}
+
+
+Instr Assembler::ImmBarrierType(int imm2) {
+  DCHECK(is_uint2(imm2));
+  return imm2 << ImmBarrierType_offset;
+}
+
+
+LSDataSize Assembler::CalcLSDataSize(LoadStoreOp op) {
+  DCHECK((SizeLS_offset + SizeLS_width) == (kInstructionSize * 8));
+  return static_cast<LSDataSize>(op >> SizeLS_offset);
+}
+
+
+Instr Assembler::ImmMoveWide(uint64_t imm) {
+  DCHECK(is_uint16(imm));
+  return imm << ImmMoveWide_offset;
+}
+
+
+Instr Assembler::ShiftMoveWide(int64_t shift) {
+  DCHECK(is_uint2(shift));
+  return shift << ShiftMoveWide_offset;
+}
+
+
+Instr Assembler::FPType(FPRegister fd) {
+  return fd.Is64Bits() ? FP64 : FP32;
+}
+
+
+Instr Assembler::FPScale(unsigned scale) {
+  DCHECK(is_uint6(scale));
+  return scale << FPScale_offset;
+}
+
+
+const Register& Assembler::AppropriateZeroRegFor(const CPURegister& reg) const {
+  return reg.Is64Bits() ? xzr : wzr;
+}
+
+
+inline void Assembler::CheckBufferSpace() {
+  DCHECK(pc_ < (buffer_ + buffer_size_));
+  if (buffer_space() < kGap) {
+    GrowBuffer();
+  }
+}
+
+
+inline void Assembler::CheckBuffer() {
+  CheckBufferSpace();
+  if (pc_offset() >= next_veneer_pool_check_) {
+    CheckVeneerPool(false, true);
+  }
+  if (pc_offset() >= next_constant_pool_check_) {
+    CheckConstPool(false, true);
+  }
+}
+
+
+TypeFeedbackId Assembler::RecordedAstId() {
+  DCHECK(!recorded_ast_id_.IsNone());
+  return recorded_ast_id_;
+}
+
+
+void Assembler::ClearRecordedAstId() {
+  recorded_ast_id_ = TypeFeedbackId::None();
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_ASSEMBLER_ARM64_INL_H_
diff --git a/src/arm64/assembler-arm64.cc b/src/arm64/assembler-arm64.cc
new file mode 100644
index 0000000..c1213e9
--- /dev/null
+++ b/src/arm64/assembler-arm64.cc
@@ -0,0 +1,3141 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#define ARM64_DEFINE_REG_STATICS
+
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/base/bits.h"
+#include "src/base/cpu.h"
+
+namespace v8 {
+namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// CpuFeatures implementation.
+
+void CpuFeatures::ProbeImpl(bool cross_compile) {
+  if (cross_compile) {
+    // Always align csp in cross compiled code - this is safe and ensures that
+    // csp will always be aligned if it is enabled by probing at runtime.
+    if (FLAG_enable_always_align_csp) supported_ |= 1u << ALWAYS_ALIGN_CSP;
+  } else {
+    base::CPU cpu;
+    if (FLAG_enable_always_align_csp &&
+        (cpu.implementer() == base::CPU::NVIDIA || FLAG_debug_code)) {
+      supported_ |= 1u << ALWAYS_ALIGN_CSP;
+    }
+  }
+}
+
+
+void CpuFeatures::PrintTarget() { }
+void CpuFeatures::PrintFeatures() { }
+
+
+// -----------------------------------------------------------------------------
+// CPURegList utilities.
+
+CPURegister CPURegList::PopLowestIndex() {
+  DCHECK(IsValid());
+  if (IsEmpty()) {
+    return NoCPUReg;
+  }
+  int index = CountTrailingZeros(list_, kRegListSizeInBits);
+  DCHECK((1 << index) & list_);
+  Remove(index);
+  return CPURegister::Create(index, size_, type_);
+}
+
+
+CPURegister CPURegList::PopHighestIndex() {
+  DCHECK(IsValid());
+  if (IsEmpty()) {
+    return NoCPUReg;
+  }
+  int index = CountLeadingZeros(list_, kRegListSizeInBits);
+  index = kRegListSizeInBits - 1 - index;
+  DCHECK((1 << index) & list_);
+  Remove(index);
+  return CPURegister::Create(index, size_, type_);
+}
+
+
+void CPURegList::RemoveCalleeSaved() {
+  if (type() == CPURegister::kRegister) {
+    Remove(GetCalleeSaved(RegisterSizeInBits()));
+  } else if (type() == CPURegister::kFPRegister) {
+    Remove(GetCalleeSavedFP(RegisterSizeInBits()));
+  } else {
+    DCHECK(type() == CPURegister::kNoRegister);
+    DCHECK(IsEmpty());
+    // The list must already be empty, so do nothing.
+  }
+}
+
+
+CPURegList CPURegList::GetCalleeSaved(unsigned size) {
+  return CPURegList(CPURegister::kRegister, size, 19, 29);
+}
+
+
+CPURegList CPURegList::GetCalleeSavedFP(unsigned size) {
+  return CPURegList(CPURegister::kFPRegister, size, 8, 15);
+}
+
+
+CPURegList CPURegList::GetCallerSaved(unsigned size) {
+  // Registers x0-x18 and lr (x30) are caller-saved.
+  CPURegList list = CPURegList(CPURegister::kRegister, size, 0, 18);
+  list.Combine(lr);
+  return list;
+}
+
+
+CPURegList CPURegList::GetCallerSavedFP(unsigned size) {
+  // Registers d0-d7 and d16-d31 are caller-saved.
+  CPURegList list = CPURegList(CPURegister::kFPRegister, size, 0, 7);
+  list.Combine(CPURegList(CPURegister::kFPRegister, size, 16, 31));
+  return list;
+}
+
+
+// This function defines the list of registers which are associated with a
+// safepoint slot. Safepoint register slots are saved contiguously on the stack.
+// MacroAssembler::SafepointRegisterStackIndex handles mapping from register
+// code to index in the safepoint register slots. Any change here can affect
+// this mapping.
+CPURegList CPURegList::GetSafepointSavedRegisters() {
+  CPURegList list = CPURegList::GetCalleeSaved();
+  list.Combine(
+      CPURegList(CPURegister::kRegister, kXRegSizeInBits, kJSCallerSaved));
+
+  // Note that unfortunately we can't use symbolic names for registers and have
+  // to directly use register codes. This is because this function is used to
+  // initialize some static variables and we can't rely on register variables
+  // to be initialized due to static initialization order issues in C++.
+
+  // Drop ip0 and ip1 (i.e. x16 and x17), as they should not be expected to be
+  // preserved outside of the macro assembler.
+  list.Remove(16);
+  list.Remove(17);
+
+  // Add x18 to the safepoint list, as although it's not in kJSCallerSaved, it
+  // is a caller-saved register according to the procedure call standard.
+  list.Combine(18);
+
+  // Drop jssp as the stack pointer doesn't need to be included.
+  list.Remove(28);
+
+  // Add the link register (x30) to the safepoint list.
+  list.Combine(30);
+
+  return list;
+}
+
+
+// -----------------------------------------------------------------------------
+// Implementation of RelocInfo
+
+const int RelocInfo::kApplyMask = 0;
+
+
+bool RelocInfo::IsCodedSpecially() {
+  // The deserializer needs to know whether a pointer is specially coded. Being
+  // specially coded on ARM64 means that it is a movz/movk sequence. We don't
+  // generate those for relocatable pointers.
+  return false;
+}
+
+
+bool RelocInfo::IsInConstantPool() {
+  Instruction* instr = reinterpret_cast<Instruction*>(pc_);
+  return instr->IsLdrLiteralX();
+}
+
+
+void RelocInfo::PatchCode(byte* instructions, int instruction_count) {
+  // Patch the code at the current address with the supplied instructions.
+  Instr* pc = reinterpret_cast<Instr*>(pc_);
+  Instr* instr = reinterpret_cast<Instr*>(instructions);
+  for (int i = 0; i < instruction_count; i++) {
+    *(pc + i) = *(instr + i);
+  }
+
+  // Indicate that code has changed.
+  CpuFeatures::FlushICache(pc_, instruction_count * kInstructionSize);
+}
+
+
+// Patch the code at the current PC with a call to the target address.
+// Additional guard instructions can be added if required.
+void RelocInfo::PatchCodeWithCall(Address target, int guard_bytes) {
+  UNIMPLEMENTED();
+}
+
+
+Register GetAllocatableRegisterThatIsNotOneOf(Register reg1, Register reg2,
+                                              Register reg3, Register reg4) {
+  CPURegList regs(reg1, reg2, reg3, reg4);
+  for (int i = 0; i < Register::NumAllocatableRegisters(); i++) {
+    Register candidate = Register::FromAllocationIndex(i);
+    if (regs.IncludesAliasOf(candidate)) continue;
+    return candidate;
+  }
+  UNREACHABLE();
+  return NoReg;
+}
+
+
+bool AreAliased(const CPURegister& reg1, const CPURegister& reg2,
+                const CPURegister& reg3, const CPURegister& reg4,
+                const CPURegister& reg5, const CPURegister& reg6,
+                const CPURegister& reg7, const CPURegister& reg8) {
+  int number_of_valid_regs = 0;
+  int number_of_valid_fpregs = 0;
+
+  RegList unique_regs = 0;
+  RegList unique_fpregs = 0;
+
+  const CPURegister regs[] = {reg1, reg2, reg3, reg4, reg5, reg6, reg7, reg8};
+
+  for (unsigned i = 0; i < arraysize(regs); i++) {
+    if (regs[i].IsRegister()) {
+      number_of_valid_regs++;
+      unique_regs |= regs[i].Bit();
+    } else if (regs[i].IsFPRegister()) {
+      number_of_valid_fpregs++;
+      unique_fpregs |= regs[i].Bit();
+    } else {
+      DCHECK(!regs[i].IsValid());
+    }
+  }
+
+  int number_of_unique_regs =
+    CountSetBits(unique_regs, sizeof(unique_regs) * kBitsPerByte);
+  int number_of_unique_fpregs =
+    CountSetBits(unique_fpregs, sizeof(unique_fpregs) * kBitsPerByte);
+
+  DCHECK(number_of_valid_regs >= number_of_unique_regs);
+  DCHECK(number_of_valid_fpregs >= number_of_unique_fpregs);
+
+  return (number_of_valid_regs != number_of_unique_regs) ||
+         (number_of_valid_fpregs != number_of_unique_fpregs);
+}
+
+
+bool AreSameSizeAndType(const CPURegister& reg1, const CPURegister& reg2,
+                        const CPURegister& reg3, const CPURegister& reg4,
+                        const CPURegister& reg5, const CPURegister& reg6,
+                        const CPURegister& reg7, const CPURegister& reg8) {
+  DCHECK(reg1.IsValid());
+  bool match = true;
+  match &= !reg2.IsValid() || reg2.IsSameSizeAndType(reg1);
+  match &= !reg3.IsValid() || reg3.IsSameSizeAndType(reg1);
+  match &= !reg4.IsValid() || reg4.IsSameSizeAndType(reg1);
+  match &= !reg5.IsValid() || reg5.IsSameSizeAndType(reg1);
+  match &= !reg6.IsValid() || reg6.IsSameSizeAndType(reg1);
+  match &= !reg7.IsValid() || reg7.IsSameSizeAndType(reg1);
+  match &= !reg8.IsValid() || reg8.IsSameSizeAndType(reg1);
+  return match;
+}
+
+
+void Immediate::InitializeHandle(Handle<Object> handle) {
+  AllowDeferredHandleDereference using_raw_address;
+
+  // Verify all Objects referred by code are NOT in new space.
+  Object* obj = *handle;
+  if (obj->IsHeapObject()) {
+    DCHECK(!HeapObject::cast(obj)->GetHeap()->InNewSpace(obj));
+    value_ = reinterpret_cast<intptr_t>(handle.location());
+    rmode_ = RelocInfo::EMBEDDED_OBJECT;
+  } else {
+    STATIC_ASSERT(sizeof(intptr_t) == sizeof(int64_t));
+    value_ = reinterpret_cast<intptr_t>(obj);
+    rmode_ = RelocInfo::NONE64;
+  }
+}
+
+
+bool Operand::NeedsRelocation(const Assembler* assembler) const {
+  RelocInfo::Mode rmode = immediate_.rmode();
+
+  if (rmode == RelocInfo::EXTERNAL_REFERENCE) {
+    return assembler->serializer_enabled();
+  }
+
+  return !RelocInfo::IsNone(rmode);
+}
+
+
+// Constant Pool.
+void ConstPool::RecordEntry(intptr_t data,
+                            RelocInfo::Mode mode) {
+  DCHECK(mode != RelocInfo::COMMENT &&
+         mode != RelocInfo::POSITION &&
+         mode != RelocInfo::STATEMENT_POSITION &&
+         mode != RelocInfo::CONST_POOL &&
+         mode != RelocInfo::VENEER_POOL &&
+         mode != RelocInfo::CODE_AGE_SEQUENCE);
+
+  uint64_t raw_data = static_cast<uint64_t>(data);
+  int offset = assm_->pc_offset();
+  if (IsEmpty()) {
+    first_use_ = offset;
+  }
+
+  std::pair<uint64_t, int> entry = std::make_pair(raw_data, offset);
+  if (CanBeShared(mode)) {
+    shared_entries_.insert(entry);
+    if (shared_entries_.count(entry.first) == 1) {
+      shared_entries_count++;
+    }
+  } else {
+    unique_entries_.push_back(entry);
+  }
+
+  if (EntryCount() > Assembler::kApproxMaxPoolEntryCount) {
+    // Request constant pool emission after the next instruction.
+    assm_->SetNextConstPoolCheckIn(1);
+  }
+}
+
+
+int ConstPool::DistanceToFirstUse() {
+  DCHECK(first_use_ >= 0);
+  return assm_->pc_offset() - first_use_;
+}
+
+
+int ConstPool::MaxPcOffset() {
+  // There are no pending entries in the pool so we can never get out of
+  // range.
+  if (IsEmpty()) return kMaxInt;
+
+  // Entries are not necessarily emitted in the order they are added so in the
+  // worst case the first constant pool use will be accessing the last entry.
+  return first_use_ + kMaxLoadLiteralRange - WorstCaseSize();
+}
+
+
+int ConstPool::WorstCaseSize() {
+  if (IsEmpty()) return 0;
+
+  // Max size prologue:
+  //   b   over
+  //   ldr xzr, #pool_size
+  //   blr xzr
+  //   nop
+  // All entries are 64-bit for now.
+  return 4 * kInstructionSize + EntryCount() * kPointerSize;
+}
+
+
+int ConstPool::SizeIfEmittedAtCurrentPc(bool require_jump) {
+  if (IsEmpty()) return 0;
+
+  // Prologue is:
+  //   b   over  ;; if require_jump
+  //   ldr xzr, #pool_size
+  //   blr xzr
+  //   nop       ;; if not 64-bit aligned
+  int prologue_size = require_jump ? kInstructionSize : 0;
+  prologue_size += 2 * kInstructionSize;
+  prologue_size += IsAligned(assm_->pc_offset() + prologue_size, 8) ?
+                   0 : kInstructionSize;
+
+  // All entries are 64-bit for now.
+  return prologue_size + EntryCount() * kPointerSize;
+}
+
+
+void ConstPool::Emit(bool require_jump) {
+  DCHECK(!assm_->is_const_pool_blocked());
+  // Prevent recursive pool emission and protect from veneer pools.
+  Assembler::BlockPoolsScope block_pools(assm_);
+
+  int size = SizeIfEmittedAtCurrentPc(require_jump);
+  Label size_check;
+  assm_->bind(&size_check);
+
+  assm_->RecordConstPool(size);
+  // Emit the constant pool. It is preceded by an optional branch if
+  // require_jump and a header which will:
+  //  1) Encode the size of the constant pool, for use by the disassembler.
+  //  2) Terminate the program, to try to prevent execution from accidentally
+  //     flowing into the constant pool.
+  //  3) align the pool entries to 64-bit.
+  // The header is therefore made of up to three arm64 instructions:
+  //   ldr xzr, #<size of the constant pool in 32-bit words>
+  //   blr xzr
+  //   nop
+  //
+  // If executed, the header will likely segfault and lr will point to the
+  // instruction following the offending blr.
+  // TODO(all): Make the alignment part less fragile. Currently code is
+  // allocated as a byte array so there are no guarantees the alignment will
+  // be preserved on compaction. Currently it works as allocation seems to be
+  // 64-bit aligned.
+
+  // Emit branch if required
+  Label after_pool;
+  if (require_jump) {
+    assm_->b(&after_pool);
+  }
+
+  // Emit the header.
+  assm_->RecordComment("[ Constant Pool");
+  EmitMarker();
+  EmitGuard();
+  assm_->Align(8);
+
+  // Emit constant pool entries.
+  // TODO(all): currently each relocated constant is 64 bits, consider adding
+  // support for 32-bit entries.
+  EmitEntries();
+  assm_->RecordComment("]");
+
+  if (after_pool.is_linked()) {
+    assm_->bind(&after_pool);
+  }
+
+  DCHECK(assm_->SizeOfCodeGeneratedSince(&size_check) ==
+         static_cast<unsigned>(size));
+}
+
+
+void ConstPool::Clear() {
+  shared_entries_.clear();
+  shared_entries_count = 0;
+  unique_entries_.clear();
+  first_use_ = -1;
+}
+
+
+bool ConstPool::CanBeShared(RelocInfo::Mode mode) {
+  // Constant pool currently does not support 32-bit entries.
+  DCHECK(mode != RelocInfo::NONE32);
+
+  return RelocInfo::IsNone(mode) ||
+         (!assm_->serializer_enabled() && (mode >= RelocInfo::CELL));
+}
+
+
+void ConstPool::EmitMarker() {
+  // A constant pool size is expressed in number of 32-bits words.
+  // Currently all entries are 64-bit.
+  // + 1 is for the crash guard.
+  // + 0/1 for alignment.
+  int word_count = EntryCount() * 2 + 1 +
+                   (IsAligned(assm_->pc_offset(), 8) ? 0 : 1);
+  assm_->Emit(LDR_x_lit                          |
+              Assembler::ImmLLiteral(word_count) |
+              Assembler::Rt(xzr));
+}
+
+
+MemOperand::PairResult MemOperand::AreConsistentForPair(
+    const MemOperand& operandA,
+    const MemOperand& operandB,
+    int access_size_log2) {
+  DCHECK(access_size_log2 >= 0);
+  DCHECK(access_size_log2 <= 3);
+  // Step one: check that they share the same base, that the mode is Offset
+  // and that the offset is a multiple of access size.
+  if (!operandA.base().Is(operandB.base()) ||
+      (operandA.addrmode() != Offset) ||
+      (operandB.addrmode() != Offset) ||
+      ((operandA.offset() & ((1 << access_size_log2) - 1)) != 0)) {
+    return kNotPair;
+  }
+  // Step two: check that the offsets are contiguous and that the range
+  // is OK for ldp/stp.
+  if ((operandB.offset() == operandA.offset() + (1 << access_size_log2)) &&
+      is_int7(operandA.offset() >> access_size_log2)) {
+    return kPairAB;
+  }
+  if ((operandA.offset() == operandB.offset() + (1 << access_size_log2)) &&
+      is_int7(operandB.offset() >> access_size_log2)) {
+    return kPairBA;
+  }
+  return kNotPair;
+}
+
+
+void ConstPool::EmitGuard() {
+#ifdef DEBUG
+  Instruction* instr = reinterpret_cast<Instruction*>(assm_->pc());
+  DCHECK(instr->preceding()->IsLdrLiteralX() &&
+         instr->preceding()->Rt() == xzr.code());
+#endif
+  assm_->EmitPoolGuard();
+}
+
+
+void ConstPool::EmitEntries() {
+  DCHECK(IsAligned(assm_->pc_offset(), 8));
+
+  typedef std::multimap<uint64_t, int>::const_iterator SharedEntriesIterator;
+  SharedEntriesIterator value_it;
+  // Iterate through the keys (constant pool values).
+  for (value_it = shared_entries_.begin();
+       value_it != shared_entries_.end();
+       value_it = shared_entries_.upper_bound(value_it->first)) {
+    std::pair<SharedEntriesIterator, SharedEntriesIterator> range;
+    uint64_t data = value_it->first;
+    range = shared_entries_.equal_range(data);
+    SharedEntriesIterator offset_it;
+    // Iterate through the offsets of a given key.
+    for (offset_it = range.first; offset_it != range.second; offset_it++) {
+      Instruction* instr = assm_->InstructionAt(offset_it->second);
+
+      // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
+      DCHECK(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
+      instr->SetImmPCOffsetTarget(assm_->pc());
+    }
+    assm_->dc64(data);
+  }
+  shared_entries_.clear();
+  shared_entries_count = 0;
+
+  // Emit unique entries.
+  std::vector<std::pair<uint64_t, int> >::const_iterator unique_it;
+  for (unique_it = unique_entries_.begin();
+       unique_it != unique_entries_.end();
+       unique_it++) {
+    Instruction* instr = assm_->InstructionAt(unique_it->second);
+
+    // Instruction to patch must be 'ldr rd, [pc, #offset]' with offset == 0.
+    DCHECK(instr->IsLdrLiteral() && instr->ImmLLiteral() == 0);
+    instr->SetImmPCOffsetTarget(assm_->pc());
+    assm_->dc64(unique_it->first);
+  }
+  unique_entries_.clear();
+  first_use_ = -1;
+}
+
+
+// Assembler
+Assembler::Assembler(Isolate* isolate, void* buffer, int buffer_size)
+    : AssemblerBase(isolate, buffer, buffer_size),
+      constpool_(this),
+      recorded_ast_id_(TypeFeedbackId::None()),
+      unresolved_branches_(),
+      positions_recorder_(this) {
+  const_pool_blocked_nesting_ = 0;
+  veneer_pool_blocked_nesting_ = 0;
+  Reset();
+}
+
+
+Assembler::~Assembler() {
+  DCHECK(constpool_.IsEmpty());
+  DCHECK(const_pool_blocked_nesting_ == 0);
+  DCHECK(veneer_pool_blocked_nesting_ == 0);
+}
+
+
+void Assembler::Reset() {
+#ifdef DEBUG
+  DCHECK((pc_ >= buffer_) && (pc_ < buffer_ + buffer_size_));
+  DCHECK(const_pool_blocked_nesting_ == 0);
+  DCHECK(veneer_pool_blocked_nesting_ == 0);
+  DCHECK(unresolved_branches_.empty());
+  memset(buffer_, 0, pc_ - buffer_);
+#endif
+  pc_ = buffer_;
+  reloc_info_writer.Reposition(reinterpret_cast<byte*>(buffer_ + buffer_size_),
+                               reinterpret_cast<byte*>(pc_));
+  constpool_.Clear();
+  next_constant_pool_check_ = 0;
+  next_veneer_pool_check_ = kMaxInt;
+  no_const_pool_before_ = 0;
+  ClearRecordedAstId();
+}
+
+
+void Assembler::GetCode(CodeDesc* desc) {
+  // Emit constant pool if necessary.
+  CheckConstPool(true, false);
+  DCHECK(constpool_.IsEmpty());
+
+  // Set up code descriptor.
+  if (desc) {
+    desc->buffer = reinterpret_cast<byte*>(buffer_);
+    desc->buffer_size = buffer_size_;
+    desc->instr_size = pc_offset();
+    desc->reloc_size = (reinterpret_cast<byte*>(buffer_) + buffer_size_) -
+                       reloc_info_writer.pos();
+    desc->origin = this;
+  }
+}
+
+
+void Assembler::Align(int m) {
+  DCHECK(m >= 4 && base::bits::IsPowerOfTwo32(m));
+  while ((pc_offset() & (m - 1)) != 0) {
+    nop();
+  }
+}
+
+
+void Assembler::CheckLabelLinkChain(Label const * label) {
+#ifdef DEBUG
+  if (label->is_linked()) {
+    int linkoffset = label->pos();
+    bool end_of_chain = false;
+    while (!end_of_chain) {
+      Instruction * link = InstructionAt(linkoffset);
+      int linkpcoffset = link->ImmPCOffset();
+      int prevlinkoffset = linkoffset + linkpcoffset;
+
+      end_of_chain = (linkoffset == prevlinkoffset);
+      linkoffset = linkoffset + linkpcoffset;
+    }
+  }
+#endif
+}
+
+
+void Assembler::RemoveBranchFromLabelLinkChain(Instruction* branch,
+                                               Label* label,
+                                               Instruction* label_veneer) {
+  DCHECK(label->is_linked());
+
+  CheckLabelLinkChain(label);
+
+  Instruction* link = InstructionAt(label->pos());
+  Instruction* prev_link = link;
+  Instruction* next_link;
+  bool end_of_chain = false;
+
+  while (link != branch && !end_of_chain) {
+    next_link = link->ImmPCOffsetTarget();
+    end_of_chain = (link == next_link);
+    prev_link = link;
+    link = next_link;
+  }
+
+  DCHECK(branch == link);
+  next_link = branch->ImmPCOffsetTarget();
+
+  if (branch == prev_link) {
+    // The branch is the first instruction in the chain.
+    if (branch == next_link) {
+      // It is also the last instruction in the chain, so it is the only branch
+      // currently referring to this label.
+      label->Unuse();
+    } else {
+      label->link_to(reinterpret_cast<byte*>(next_link) - buffer_);
+    }
+
+  } else if (branch == next_link) {
+    // The branch is the last (but not also the first) instruction in the chain.
+    prev_link->SetImmPCOffsetTarget(prev_link);
+
+  } else {
+    // The branch is in the middle of the chain.
+    if (prev_link->IsTargetInImmPCOffsetRange(next_link)) {
+      prev_link->SetImmPCOffsetTarget(next_link);
+    } else if (label_veneer != NULL) {
+      // Use the veneer for all previous links in the chain.
+      prev_link->SetImmPCOffsetTarget(prev_link);
+
+      end_of_chain = false;
+      link = next_link;
+      while (!end_of_chain) {
+        next_link = link->ImmPCOffsetTarget();
+        end_of_chain = (link == next_link);
+        link->SetImmPCOffsetTarget(label_veneer);
+        link = next_link;
+      }
+    } else {
+      // The assert below will fire.
+      // Some other work could be attempted to fix up the chain, but it would be
+      // rather complicated. If we crash here, we may want to consider using an
+      // other mechanism than a chain of branches.
+      //
+      // Note that this situation currently should not happen, as we always call
+      // this function with a veneer to the target label.
+      // However this could happen with a MacroAssembler in the following state:
+      //    [previous code]
+      //    B(label);
+      //    [20KB code]
+      //    Tbz(label);   // First tbz. Pointing to unconditional branch.
+      //    [20KB code]
+      //    Tbz(label);   // Second tbz. Pointing to the first tbz.
+      //    [more code]
+      // and this function is called to remove the first tbz from the label link
+      // chain. Since tbz has a range of +-32KB, the second tbz cannot point to
+      // the unconditional branch.
+      CHECK(prev_link->IsTargetInImmPCOffsetRange(next_link));
+      UNREACHABLE();
+    }
+  }
+
+  CheckLabelLinkChain(label);
+}
+
+
+void Assembler::bind(Label* label) {
+  // Bind label to the address at pc_. All instructions (most likely branches)
+  // that are linked to this label will be updated to point to the newly-bound
+  // label.
+
+  DCHECK(!label->is_near_linked());
+  DCHECK(!label->is_bound());
+
+  DeleteUnresolvedBranchInfoForLabel(label);
+
+  // If the label is linked, the link chain looks something like this:
+  //
+  // |--I----I-------I-------L
+  // |---------------------->| pc_offset
+  // |-------------->|         linkoffset = label->pos()
+  //         |<------|         link->ImmPCOffset()
+  // |------>|                 prevlinkoffset = linkoffset + link->ImmPCOffset()
+  //
+  // On each iteration, the last link is updated and then removed from the
+  // chain until only one remains. At that point, the label is bound.
+  //
+  // If the label is not linked, no preparation is required before binding.
+  while (label->is_linked()) {
+    int linkoffset = label->pos();
+    Instruction* link = InstructionAt(linkoffset);
+    int prevlinkoffset = linkoffset + link->ImmPCOffset();
+
+    CheckLabelLinkChain(label);
+
+    DCHECK(linkoffset >= 0);
+    DCHECK(linkoffset < pc_offset());
+    DCHECK((linkoffset > prevlinkoffset) ||
+           (linkoffset - prevlinkoffset == kStartOfLabelLinkChain));
+    DCHECK(prevlinkoffset >= 0);
+
+    // Update the link to point to the label.
+    link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_));
+
+    // Link the label to the previous link in the chain.
+    if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) {
+      // We hit kStartOfLabelLinkChain, so the chain is fully processed.
+      label->Unuse();
+    } else {
+      // Update the label for the next iteration.
+      label->link_to(prevlinkoffset);
+    }
+  }
+  label->bind_to(pc_offset());
+
+  DCHECK(label->is_bound());
+  DCHECK(!label->is_linked());
+}
+
+
+int Assembler::LinkAndGetByteOffsetTo(Label* label) {
+  DCHECK(sizeof(*pc_) == 1);
+  CheckLabelLinkChain(label);
+
+  int offset;
+  if (label->is_bound()) {
+    // The label is bound, so it does not need to be updated. Referring
+    // instructions must link directly to the label as they will not be
+    // updated.
+    //
+    // In this case, label->pos() returns the offset of the label from the
+    // start of the buffer.
+    //
+    // Note that offset can be zero for self-referential instructions. (This
+    // could be useful for ADR, for example.)
+    offset = label->pos() - pc_offset();
+    DCHECK(offset <= 0);
+  } else {
+    if (label->is_linked()) {
+      // The label is linked, so the referring instruction should be added onto
+      // the end of the label's link chain.
+      //
+      // In this case, label->pos() returns the offset of the last linked
+      // instruction from the start of the buffer.
+      offset = label->pos() - pc_offset();
+      DCHECK(offset != kStartOfLabelLinkChain);
+      // Note that the offset here needs to be PC-relative only so that the
+      // first instruction in a buffer can link to an unbound label. Otherwise,
+      // the offset would be 0 for this case, and 0 is reserved for
+      // kStartOfLabelLinkChain.
+    } else {
+      // The label is unused, so it now becomes linked and the referring
+      // instruction is at the start of the new link chain.
+      offset = kStartOfLabelLinkChain;
+    }
+    // The instruction at pc is now the last link in the label's chain.
+    label->link_to(pc_offset());
+  }
+
+  return offset;
+}
+
+
+void Assembler::DeleteUnresolvedBranchInfoForLabelTraverse(Label* label) {
+  DCHECK(label->is_linked());
+  CheckLabelLinkChain(label);
+
+  int link_offset = label->pos();
+  int link_pcoffset;
+  bool end_of_chain = false;
+
+  while (!end_of_chain) {
+    Instruction * link = InstructionAt(link_offset);
+    link_pcoffset = link->ImmPCOffset();
+
+    // ADR instructions are not handled by veneers.
+    if (link->IsImmBranch()) {
+      int max_reachable_pc = InstructionOffset(link) +
+          Instruction::ImmBranchRange(link->BranchType());
+      typedef std::multimap<int, FarBranchInfo>::iterator unresolved_info_it;
+      std::pair<unresolved_info_it, unresolved_info_it> range;
+      range = unresolved_branches_.equal_range(max_reachable_pc);
+      unresolved_info_it it;
+      for (it = range.first; it != range.second; ++it) {
+        if (it->second.pc_offset_ == link_offset) {
+          unresolved_branches_.erase(it);
+          break;
+        }
+      }
+    }
+
+    end_of_chain = (link_pcoffset == 0);
+    link_offset = link_offset + link_pcoffset;
+  }
+}
+
+
+void Assembler::DeleteUnresolvedBranchInfoForLabel(Label* label) {
+  if (unresolved_branches_.empty()) {
+    DCHECK(next_veneer_pool_check_ == kMaxInt);
+    return;
+  }
+
+  if (label->is_linked()) {
+    // Branches to this label will be resolved when the label is bound, normally
+    // just after all the associated info has been deleted.
+    DeleteUnresolvedBranchInfoForLabelTraverse(label);
+  }
+  if (unresolved_branches_.empty()) {
+    next_veneer_pool_check_ = kMaxInt;
+  } else {
+    next_veneer_pool_check_ =
+      unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
+  }
+}
+
+
+void Assembler::StartBlockConstPool() {
+  if (const_pool_blocked_nesting_++ == 0) {
+    // Prevent constant pool checks happening by setting the next check to
+    // the biggest possible offset.
+    next_constant_pool_check_ = kMaxInt;
+  }
+}
+
+
+void Assembler::EndBlockConstPool() {
+  if (--const_pool_blocked_nesting_ == 0) {
+    // Check the constant pool hasn't been blocked for too long.
+    DCHECK(pc_offset() < constpool_.MaxPcOffset());
+    // Two cases:
+    //  * no_const_pool_before_ >= next_constant_pool_check_ and the emission is
+    //    still blocked
+    //  * no_const_pool_before_ < next_constant_pool_check_ and the next emit
+    //    will trigger a check.
+    next_constant_pool_check_ = no_const_pool_before_;
+  }
+}
+
+
+bool Assembler::is_const_pool_blocked() const {
+  return (const_pool_blocked_nesting_ > 0) ||
+         (pc_offset() < no_const_pool_before_);
+}
+
+
+bool Assembler::IsConstantPoolAt(Instruction* instr) {
+  // The constant pool marker is made of two instructions. These instructions
+  // will never be emitted by the JIT, so checking for the first one is enough:
+  // 0: ldr xzr, #<size of pool>
+  bool result = instr->IsLdrLiteralX() && (instr->Rt() == xzr.code());
+
+  // It is still worth asserting the marker is complete.
+  // 4: blr xzr
+  DCHECK(!result || (instr->following()->IsBranchAndLinkToRegister() &&
+                     instr->following()->Rn() == xzr.code()));
+
+  return result;
+}
+
+
+int Assembler::ConstantPoolSizeAt(Instruction* instr) {
+#ifdef USE_SIMULATOR
+  // Assembler::debug() embeds constants directly into the instruction stream.
+  // Although this is not a genuine constant pool, treat it like one to avoid
+  // disassembling the constants.
+  if ((instr->Mask(ExceptionMask) == HLT) &&
+      (instr->ImmException() == kImmExceptionIsDebug)) {
+    const char* message =
+        reinterpret_cast<const char*>(
+            instr->InstructionAtOffset(kDebugMessageOffset));
+    int size = kDebugMessageOffset + strlen(message) + 1;
+    return RoundUp(size, kInstructionSize) / kInstructionSize;
+  }
+  // Same for printf support, see MacroAssembler::CallPrintf().
+  if ((instr->Mask(ExceptionMask) == HLT) &&
+      (instr->ImmException() == kImmExceptionIsPrintf)) {
+    return kPrintfLength / kInstructionSize;
+  }
+#endif
+  if (IsConstantPoolAt(instr)) {
+    return instr->ImmLLiteral();
+  } else {
+    return -1;
+  }
+}
+
+
+void Assembler::EmitPoolGuard() {
+  // We must generate only one instruction as this is used in scopes that
+  // control the size of the code generated.
+  Emit(BLR | Rn(xzr));
+}
+
+
+void Assembler::StartBlockVeneerPool() {
+  ++veneer_pool_blocked_nesting_;
+}
+
+
+void Assembler::EndBlockVeneerPool() {
+  if (--veneer_pool_blocked_nesting_ == 0) {
+    // Check the veneer pool hasn't been blocked for too long.
+    DCHECK(unresolved_branches_.empty() ||
+           (pc_offset() < unresolved_branches_first_limit()));
+  }
+}
+
+
+void Assembler::br(const Register& xn) {
+  positions_recorder()->WriteRecordedPositions();
+  DCHECK(xn.Is64Bits());
+  Emit(BR | Rn(xn));
+}
+
+
+void Assembler::blr(const Register& xn) {
+  positions_recorder()->WriteRecordedPositions();
+  DCHECK(xn.Is64Bits());
+  // The pattern 'blr xzr' is used as a guard to detect when execution falls
+  // through the constant pool. It should not be emitted.
+  DCHECK(!xn.Is(xzr));
+  Emit(BLR | Rn(xn));
+}
+
+
+void Assembler::ret(const Register& xn) {
+  positions_recorder()->WriteRecordedPositions();
+  DCHECK(xn.Is64Bits());
+  Emit(RET | Rn(xn));
+}
+
+
+void Assembler::b(int imm26) {
+  Emit(B | ImmUncondBranch(imm26));
+}
+
+
+void Assembler::b(Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  b(LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::b(int imm19, Condition cond) {
+  Emit(B_cond | ImmCondBranch(imm19) | cond);
+}
+
+
+void Assembler::b(Label* label, Condition cond) {
+  positions_recorder()->WriteRecordedPositions();
+  b(LinkAndGetInstructionOffsetTo(label), cond);
+}
+
+
+void Assembler::bl(int imm26) {
+  positions_recorder()->WriteRecordedPositions();
+  Emit(BL | ImmUncondBranch(imm26));
+}
+
+
+void Assembler::bl(Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  bl(LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::cbz(const Register& rt,
+                    int imm19) {
+  positions_recorder()->WriteRecordedPositions();
+  Emit(SF(rt) | CBZ | ImmCmpBranch(imm19) | Rt(rt));
+}
+
+
+void Assembler::cbz(const Register& rt,
+                    Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  cbz(rt, LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::cbnz(const Register& rt,
+                     int imm19) {
+  positions_recorder()->WriteRecordedPositions();
+  Emit(SF(rt) | CBNZ | ImmCmpBranch(imm19) | Rt(rt));
+}
+
+
+void Assembler::cbnz(const Register& rt,
+                     Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  cbnz(rt, LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::tbz(const Register& rt,
+                    unsigned bit_pos,
+                    int imm14) {
+  positions_recorder()->WriteRecordedPositions();
+  DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
+  Emit(TBZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
+}
+
+
+void Assembler::tbz(const Register& rt,
+                    unsigned bit_pos,
+                    Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  tbz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::tbnz(const Register& rt,
+                     unsigned bit_pos,
+                     int imm14) {
+  positions_recorder()->WriteRecordedPositions();
+  DCHECK(rt.Is64Bits() || (rt.Is32Bits() && (bit_pos < kWRegSizeInBits)));
+  Emit(TBNZ | ImmTestBranchBit(bit_pos) | ImmTestBranch(imm14) | Rt(rt));
+}
+
+
+void Assembler::tbnz(const Register& rt,
+                     unsigned bit_pos,
+                     Label* label) {
+  positions_recorder()->WriteRecordedPositions();
+  tbnz(rt, bit_pos, LinkAndGetInstructionOffsetTo(label));
+}
+
+
+void Assembler::adr(const Register& rd, int imm21) {
+  DCHECK(rd.Is64Bits());
+  Emit(ADR | ImmPCRelAddress(imm21) | Rd(rd));
+}
+
+
+void Assembler::adr(const Register& rd, Label* label) {
+  adr(rd, LinkAndGetByteOffsetTo(label));
+}
+
+
+void Assembler::add(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  AddSub(rd, rn, operand, LeaveFlags, ADD);
+}
+
+
+void Assembler::adds(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  AddSub(rd, rn, operand, SetFlags, ADD);
+}
+
+
+void Assembler::cmn(const Register& rn,
+                    const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rn);
+  adds(zr, rn, operand);
+}
+
+
+void Assembler::sub(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  AddSub(rd, rn, operand, LeaveFlags, SUB);
+}
+
+
+void Assembler::subs(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  AddSub(rd, rn, operand, SetFlags, SUB);
+}
+
+
+void Assembler::cmp(const Register& rn, const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rn);
+  subs(zr, rn, operand);
+}
+
+
+void Assembler::neg(const Register& rd, const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rd);
+  sub(rd, zr, operand);
+}
+
+
+void Assembler::negs(const Register& rd, const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rd);
+  subs(rd, zr, operand);
+}
+
+
+void Assembler::adc(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  AddSubWithCarry(rd, rn, operand, LeaveFlags, ADC);
+}
+
+
+void Assembler::adcs(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  AddSubWithCarry(rd, rn, operand, SetFlags, ADC);
+}
+
+
+void Assembler::sbc(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  AddSubWithCarry(rd, rn, operand, LeaveFlags, SBC);
+}
+
+
+void Assembler::sbcs(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  AddSubWithCarry(rd, rn, operand, SetFlags, SBC);
+}
+
+
+void Assembler::ngc(const Register& rd, const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rd);
+  sbc(rd, zr, operand);
+}
+
+
+void Assembler::ngcs(const Register& rd, const Operand& operand) {
+  Register zr = AppropriateZeroRegFor(rd);
+  sbcs(rd, zr, operand);
+}
+
+
+// Logical instructions.
+void Assembler::and_(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  Logical(rd, rn, operand, AND);
+}
+
+
+void Assembler::ands(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  Logical(rd, rn, operand, ANDS);
+}
+
+
+void Assembler::tst(const Register& rn,
+                    const Operand& operand) {
+  ands(AppropriateZeroRegFor(rn), rn, operand);
+}
+
+
+void Assembler::bic(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  Logical(rd, rn, operand, BIC);
+}
+
+
+void Assembler::bics(const Register& rd,
+                     const Register& rn,
+                     const Operand& operand) {
+  Logical(rd, rn, operand, BICS);
+}
+
+
+void Assembler::orr(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  Logical(rd, rn, operand, ORR);
+}
+
+
+void Assembler::orn(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  Logical(rd, rn, operand, ORN);
+}
+
+
+void Assembler::eor(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  Logical(rd, rn, operand, EOR);
+}
+
+
+void Assembler::eon(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand) {
+  Logical(rd, rn, operand, EON);
+}
+
+
+void Assembler::lslv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | LSLV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::lsrv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | LSRV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::asrv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | ASRV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::rorv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | RORV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+// Bitfield operations.
+void Assembler::bfm(const Register& rd,
+                     const Register& rn,
+                     unsigned immr,
+                     unsigned imms) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
+  Emit(SF(rd) | BFM | N |
+       ImmR(immr, rd.SizeInBits()) |
+       ImmS(imms, rn.SizeInBits()) |
+       Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::sbfm(const Register& rd,
+                     const Register& rn,
+                     unsigned immr,
+                     unsigned imms) {
+  DCHECK(rd.Is64Bits() || rn.Is32Bits());
+  Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
+  Emit(SF(rd) | SBFM | N |
+       ImmR(immr, rd.SizeInBits()) |
+       ImmS(imms, rn.SizeInBits()) |
+       Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::ubfm(const Register& rd,
+                     const Register& rn,
+                     unsigned immr,
+                     unsigned imms) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
+  Emit(SF(rd) | UBFM | N |
+       ImmR(immr, rd.SizeInBits()) |
+       ImmS(imms, rn.SizeInBits()) |
+       Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::extr(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     unsigned lsb) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Instr N = SF(rd) >> (kSFOffset - kBitfieldNOffset);
+  Emit(SF(rd) | EXTR | N | Rm(rm) |
+       ImmS(lsb, rn.SizeInBits()) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::csel(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     Condition cond) {
+  ConditionalSelect(rd, rn, rm, cond, CSEL);
+}
+
+
+void Assembler::csinc(const Register& rd,
+                      const Register& rn,
+                      const Register& rm,
+                      Condition cond) {
+  ConditionalSelect(rd, rn, rm, cond, CSINC);
+}
+
+
+void Assembler::csinv(const Register& rd,
+                      const Register& rn,
+                      const Register& rm,
+                      Condition cond) {
+  ConditionalSelect(rd, rn, rm, cond, CSINV);
+}
+
+
+void Assembler::csneg(const Register& rd,
+                      const Register& rn,
+                      const Register& rm,
+                      Condition cond) {
+  ConditionalSelect(rd, rn, rm, cond, CSNEG);
+}
+
+
+void Assembler::cset(const Register &rd, Condition cond) {
+  DCHECK((cond != al) && (cond != nv));
+  Register zr = AppropriateZeroRegFor(rd);
+  csinc(rd, zr, zr, NegateCondition(cond));
+}
+
+
+void Assembler::csetm(const Register &rd, Condition cond) {
+  DCHECK((cond != al) && (cond != nv));
+  Register zr = AppropriateZeroRegFor(rd);
+  csinv(rd, zr, zr, NegateCondition(cond));
+}
+
+
+void Assembler::cinc(const Register &rd, const Register &rn, Condition cond) {
+  DCHECK((cond != al) && (cond != nv));
+  csinc(rd, rn, rn, NegateCondition(cond));
+}
+
+
+void Assembler::cinv(const Register &rd, const Register &rn, Condition cond) {
+  DCHECK((cond != al) && (cond != nv));
+  csinv(rd, rn, rn, NegateCondition(cond));
+}
+
+
+void Assembler::cneg(const Register &rd, const Register &rn, Condition cond) {
+  DCHECK((cond != al) && (cond != nv));
+  csneg(rd, rn, rn, NegateCondition(cond));
+}
+
+
+void Assembler::ConditionalSelect(const Register& rd,
+                                  const Register& rn,
+                                  const Register& rm,
+                                  Condition cond,
+                                  ConditionalSelectOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | op | Rm(rm) | Cond(cond) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::ccmn(const Register& rn,
+                     const Operand& operand,
+                     StatusFlags nzcv,
+                     Condition cond) {
+  ConditionalCompare(rn, operand, nzcv, cond, CCMN);
+}
+
+
+void Assembler::ccmp(const Register& rn,
+                     const Operand& operand,
+                     StatusFlags nzcv,
+                     Condition cond) {
+  ConditionalCompare(rn, operand, nzcv, cond, CCMP);
+}
+
+
+void Assembler::DataProcessing3Source(const Register& rd,
+                                      const Register& rn,
+                                      const Register& rm,
+                                      const Register& ra,
+                                      DataProcessing3SourceOp op) {
+  Emit(SF(rd) | op | Rm(rm) | Ra(ra) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::mul(const Register& rd,
+                    const Register& rn,
+                    const Register& rm) {
+  DCHECK(AreSameSizeAndType(rd, rn, rm));
+  Register zr = AppropriateZeroRegFor(rn);
+  DataProcessing3Source(rd, rn, rm, zr, MADD);
+}
+
+
+void Assembler::madd(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra) {
+  DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
+  DataProcessing3Source(rd, rn, rm, ra, MADD);
+}
+
+
+void Assembler::mneg(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(AreSameSizeAndType(rd, rn, rm));
+  Register zr = AppropriateZeroRegFor(rn);
+  DataProcessing3Source(rd, rn, rm, zr, MSUB);
+}
+
+
+void Assembler::msub(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra) {
+  DCHECK(AreSameSizeAndType(rd, rn, rm, ra));
+  DataProcessing3Source(rd, rn, rm, ra, MSUB);
+}
+
+
+void Assembler::smaddl(const Register& rd,
+                       const Register& rn,
+                       const Register& rm,
+                       const Register& ra) {
+  DCHECK(rd.Is64Bits() && ra.Is64Bits());
+  DCHECK(rn.Is32Bits() && rm.Is32Bits());
+  DataProcessing3Source(rd, rn, rm, ra, SMADDL_x);
+}
+
+
+void Assembler::smsubl(const Register& rd,
+                       const Register& rn,
+                       const Register& rm,
+                       const Register& ra) {
+  DCHECK(rd.Is64Bits() && ra.Is64Bits());
+  DCHECK(rn.Is32Bits() && rm.Is32Bits());
+  DataProcessing3Source(rd, rn, rm, ra, SMSUBL_x);
+}
+
+
+void Assembler::umaddl(const Register& rd,
+                       const Register& rn,
+                       const Register& rm,
+                       const Register& ra) {
+  DCHECK(rd.Is64Bits() && ra.Is64Bits());
+  DCHECK(rn.Is32Bits() && rm.Is32Bits());
+  DataProcessing3Source(rd, rn, rm, ra, UMADDL_x);
+}
+
+
+void Assembler::umsubl(const Register& rd,
+                       const Register& rn,
+                       const Register& rm,
+                       const Register& ra) {
+  DCHECK(rd.Is64Bits() && ra.Is64Bits());
+  DCHECK(rn.Is32Bits() && rm.Is32Bits());
+  DataProcessing3Source(rd, rn, rm, ra, UMSUBL_x);
+}
+
+
+void Assembler::smull(const Register& rd,
+                      const Register& rn,
+                      const Register& rm) {
+  DCHECK(rd.Is64Bits());
+  DCHECK(rn.Is32Bits() && rm.Is32Bits());
+  DataProcessing3Source(rd, rn, rm, xzr, SMADDL_x);
+}
+
+
+void Assembler::smulh(const Register& rd,
+                      const Register& rn,
+                      const Register& rm) {
+  DCHECK(AreSameSizeAndType(rd, rn, rm));
+  DataProcessing3Source(rd, rn, rm, xzr, SMULH_x);
+}
+
+
+void Assembler::sdiv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | SDIV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::udiv(const Register& rd,
+                     const Register& rn,
+                     const Register& rm) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == rm.SizeInBits());
+  Emit(SF(rd) | UDIV | Rm(rm) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::rbit(const Register& rd,
+                     const Register& rn) {
+  DataProcessing1Source(rd, rn, RBIT);
+}
+
+
+void Assembler::rev16(const Register& rd,
+                      const Register& rn) {
+  DataProcessing1Source(rd, rn, REV16);
+}
+
+
+void Assembler::rev32(const Register& rd,
+                      const Register& rn) {
+  DCHECK(rd.Is64Bits());
+  DataProcessing1Source(rd, rn, REV);
+}
+
+
+void Assembler::rev(const Register& rd,
+                    const Register& rn) {
+  DataProcessing1Source(rd, rn, rd.Is64Bits() ? REV_x : REV_w);
+}
+
+
+void Assembler::clz(const Register& rd,
+                    const Register& rn) {
+  DataProcessing1Source(rd, rn, CLZ);
+}
+
+
+void Assembler::cls(const Register& rd,
+                    const Register& rn) {
+  DataProcessing1Source(rd, rn, CLS);
+}
+
+
+void Assembler::ldp(const CPURegister& rt,
+                    const CPURegister& rt2,
+                    const MemOperand& src) {
+  LoadStorePair(rt, rt2, src, LoadPairOpFor(rt, rt2));
+}
+
+
+void Assembler::stp(const CPURegister& rt,
+                    const CPURegister& rt2,
+                    const MemOperand& dst) {
+  LoadStorePair(rt, rt2, dst, StorePairOpFor(rt, rt2));
+}
+
+
+void Assembler::ldpsw(const Register& rt,
+                      const Register& rt2,
+                      const MemOperand& src) {
+  DCHECK(rt.Is64Bits());
+  LoadStorePair(rt, rt2, src, LDPSW_x);
+}
+
+
+void Assembler::LoadStorePair(const CPURegister& rt,
+                              const CPURegister& rt2,
+                              const MemOperand& addr,
+                              LoadStorePairOp op) {
+  // 'rt' and 'rt2' can only be aliased for stores.
+  DCHECK(((op & LoadStorePairLBit) == 0) || !rt.Is(rt2));
+  DCHECK(AreSameSizeAndType(rt, rt2));
+
+  Instr memop = op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
+                ImmLSPair(addr.offset(), CalcLSPairDataSize(op));
+
+  Instr addrmodeop;
+  if (addr.IsImmediateOffset()) {
+    addrmodeop = LoadStorePairOffsetFixed;
+  } else {
+    // Pre-index and post-index modes.
+    DCHECK(!rt.Is(addr.base()));
+    DCHECK(!rt2.Is(addr.base()));
+    DCHECK(addr.offset() != 0);
+    if (addr.IsPreIndex()) {
+      addrmodeop = LoadStorePairPreIndexFixed;
+    } else {
+      DCHECK(addr.IsPostIndex());
+      addrmodeop = LoadStorePairPostIndexFixed;
+    }
+  }
+  Emit(addrmodeop | memop);
+}
+
+
+void Assembler::ldnp(const CPURegister& rt,
+                     const CPURegister& rt2,
+                     const MemOperand& src) {
+  LoadStorePairNonTemporal(rt, rt2, src,
+                           LoadPairNonTemporalOpFor(rt, rt2));
+}
+
+
+void Assembler::stnp(const CPURegister& rt,
+                     const CPURegister& rt2,
+                     const MemOperand& dst) {
+  LoadStorePairNonTemporal(rt, rt2, dst,
+                           StorePairNonTemporalOpFor(rt, rt2));
+}
+
+
+void Assembler::LoadStorePairNonTemporal(const CPURegister& rt,
+                                         const CPURegister& rt2,
+                                         const MemOperand& addr,
+                                         LoadStorePairNonTemporalOp op) {
+  DCHECK(!rt.Is(rt2));
+  DCHECK(AreSameSizeAndType(rt, rt2));
+  DCHECK(addr.IsImmediateOffset());
+
+  LSDataSize size = CalcLSPairDataSize(
+    static_cast<LoadStorePairOp>(op & LoadStorePairMask));
+  Emit(op | Rt(rt) | Rt2(rt2) | RnSP(addr.base()) |
+       ImmLSPair(addr.offset(), size));
+}
+
+
+// Memory instructions.
+void Assembler::ldrb(const Register& rt, const MemOperand& src) {
+  LoadStore(rt, src, LDRB_w);
+}
+
+
+void Assembler::strb(const Register& rt, const MemOperand& dst) {
+  LoadStore(rt, dst, STRB_w);
+}
+
+
+void Assembler::ldrsb(const Register& rt, const MemOperand& src) {
+  LoadStore(rt, src, rt.Is64Bits() ? LDRSB_x : LDRSB_w);
+}
+
+
+void Assembler::ldrh(const Register& rt, const MemOperand& src) {
+  LoadStore(rt, src, LDRH_w);
+}
+
+
+void Assembler::strh(const Register& rt, const MemOperand& dst) {
+  LoadStore(rt, dst, STRH_w);
+}
+
+
+void Assembler::ldrsh(const Register& rt, const MemOperand& src) {
+  LoadStore(rt, src, rt.Is64Bits() ? LDRSH_x : LDRSH_w);
+}
+
+
+void Assembler::ldr(const CPURegister& rt, const MemOperand& src) {
+  LoadStore(rt, src, LoadOpFor(rt));
+}
+
+
+void Assembler::str(const CPURegister& rt, const MemOperand& src) {
+  LoadStore(rt, src, StoreOpFor(rt));
+}
+
+
+void Assembler::ldrsw(const Register& rt, const MemOperand& src) {
+  DCHECK(rt.Is64Bits());
+  LoadStore(rt, src, LDRSW_x);
+}
+
+
+void Assembler::ldr_pcrel(const CPURegister& rt, int imm19) {
+  // The pattern 'ldr xzr, #offset' is used to indicate the beginning of a
+  // constant pool. It should not be emitted.
+  DCHECK(!rt.IsZero());
+  Emit(LoadLiteralOpFor(rt) | ImmLLiteral(imm19) | Rt(rt));
+}
+
+
+void Assembler::ldr(const CPURegister& rt, const Immediate& imm) {
+  // Currently we only support 64-bit literals.
+  DCHECK(rt.Is64Bits());
+
+  RecordRelocInfo(imm.rmode(), imm.value());
+  BlockConstPoolFor(1);
+  // The load will be patched when the constpool is emitted, patching code
+  // expect a load literal with offset 0.
+  ldr_pcrel(rt, 0);
+}
+
+
+void Assembler::mov(const Register& rd, const Register& rm) {
+  // Moves involving the stack pointer are encoded as add immediate with
+  // second operand of zero. Otherwise, orr with first operand zr is
+  // used.
+  if (rd.IsSP() || rm.IsSP()) {
+    add(rd, rm, 0);
+  } else {
+    orr(rd, AppropriateZeroRegFor(rd), rm);
+  }
+}
+
+
+void Assembler::mvn(const Register& rd, const Operand& operand) {
+  orn(rd, AppropriateZeroRegFor(rd), operand);
+}
+
+
+void Assembler::mrs(const Register& rt, SystemRegister sysreg) {
+  DCHECK(rt.Is64Bits());
+  Emit(MRS | ImmSystemRegister(sysreg) | Rt(rt));
+}
+
+
+void Assembler::msr(SystemRegister sysreg, const Register& rt) {
+  DCHECK(rt.Is64Bits());
+  Emit(MSR | Rt(rt) | ImmSystemRegister(sysreg));
+}
+
+
+void Assembler::hint(SystemHint code) {
+  Emit(HINT | ImmHint(code) | Rt(xzr));
+}
+
+
+void Assembler::dmb(BarrierDomain domain, BarrierType type) {
+  Emit(DMB | ImmBarrierDomain(domain) | ImmBarrierType(type));
+}
+
+
+void Assembler::dsb(BarrierDomain domain, BarrierType type) {
+  Emit(DSB | ImmBarrierDomain(domain) | ImmBarrierType(type));
+}
+
+
+void Assembler::isb() {
+  Emit(ISB | ImmBarrierDomain(FullSystem) | ImmBarrierType(BarrierAll));
+}
+
+
+void Assembler::fmov(FPRegister fd, double imm) {
+  DCHECK(fd.Is64Bits());
+  DCHECK(IsImmFP64(imm));
+  Emit(FMOV_d_imm | Rd(fd) | ImmFP64(imm));
+}
+
+
+void Assembler::fmov(FPRegister fd, float imm) {
+  DCHECK(fd.Is32Bits());
+  DCHECK(IsImmFP32(imm));
+  Emit(FMOV_s_imm | Rd(fd) | ImmFP32(imm));
+}
+
+
+void Assembler::fmov(Register rd, FPRegister fn) {
+  DCHECK(rd.SizeInBits() == fn.SizeInBits());
+  FPIntegerConvertOp op = rd.Is32Bits() ? FMOV_ws : FMOV_xd;
+  Emit(op | Rd(rd) | Rn(fn));
+}
+
+
+void Assembler::fmov(FPRegister fd, Register rn) {
+  DCHECK(fd.SizeInBits() == rn.SizeInBits());
+  FPIntegerConvertOp op = fd.Is32Bits() ? FMOV_sw : FMOV_dx;
+  Emit(op | Rd(fd) | Rn(rn));
+}
+
+
+void Assembler::fmov(FPRegister fd, FPRegister fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  Emit(FPType(fd) | FMOV | Rd(fd) | Rn(fn));
+}
+
+
+void Assembler::fadd(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FADD);
+}
+
+
+void Assembler::fsub(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FSUB);
+}
+
+
+void Assembler::fmul(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FMUL);
+}
+
+
+void Assembler::fmadd(const FPRegister& fd,
+                      const FPRegister& fn,
+                      const FPRegister& fm,
+                      const FPRegister& fa) {
+  FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMADD_s : FMADD_d);
+}
+
+
+void Assembler::fmsub(const FPRegister& fd,
+                      const FPRegister& fn,
+                      const FPRegister& fm,
+                      const FPRegister& fa) {
+  FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FMSUB_s : FMSUB_d);
+}
+
+
+void Assembler::fnmadd(const FPRegister& fd,
+                       const FPRegister& fn,
+                       const FPRegister& fm,
+                       const FPRegister& fa) {
+  FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMADD_s : FNMADD_d);
+}
+
+
+void Assembler::fnmsub(const FPRegister& fd,
+                       const FPRegister& fn,
+                       const FPRegister& fm,
+                       const FPRegister& fa) {
+  FPDataProcessing3Source(fd, fn, fm, fa, fd.Is32Bits() ? FNMSUB_s : FNMSUB_d);
+}
+
+
+void Assembler::fdiv(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FDIV);
+}
+
+
+void Assembler::fmax(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FMAX);
+}
+
+
+void Assembler::fmaxnm(const FPRegister& fd,
+                       const FPRegister& fn,
+                       const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FMAXNM);
+}
+
+
+void Assembler::fmin(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FMIN);
+}
+
+
+void Assembler::fminnm(const FPRegister& fd,
+                       const FPRegister& fn,
+                       const FPRegister& fm) {
+  FPDataProcessing2Source(fd, fn, fm, FMINNM);
+}
+
+
+void Assembler::fabs(const FPRegister& fd,
+                     const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FABS);
+}
+
+
+void Assembler::fneg(const FPRegister& fd,
+                     const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FNEG);
+}
+
+
+void Assembler::fsqrt(const FPRegister& fd,
+                      const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FSQRT);
+}
+
+
+void Assembler::frinta(const FPRegister& fd,
+                       const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTA);
+}
+
+
+void Assembler::frintm(const FPRegister& fd,
+                       const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTM);
+}
+
+
+void Assembler::frintn(const FPRegister& fd,
+                       const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTN);
+}
+
+
+void Assembler::frintz(const FPRegister& fd,
+                       const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTZ);
+}
+
+
+void Assembler::fcmp(const FPRegister& fn,
+                     const FPRegister& fm) {
+  DCHECK(fn.SizeInBits() == fm.SizeInBits());
+  Emit(FPType(fn) | FCMP | Rm(fm) | Rn(fn));
+}
+
+
+void Assembler::fcmp(const FPRegister& fn,
+                     double value) {
+  USE(value);
+  // Although the fcmp instruction can strictly only take an immediate value of
+  // +0.0, we don't need to check for -0.0 because the sign of 0.0 doesn't
+  // affect the result of the comparison.
+  DCHECK(value == 0.0);
+  Emit(FPType(fn) | FCMP_zero | Rn(fn));
+}
+
+
+void Assembler::fccmp(const FPRegister& fn,
+                      const FPRegister& fm,
+                      StatusFlags nzcv,
+                      Condition cond) {
+  DCHECK(fn.SizeInBits() == fm.SizeInBits());
+  Emit(FPType(fn) | FCCMP | Rm(fm) | Cond(cond) | Rn(fn) | Nzcv(nzcv));
+}
+
+
+void Assembler::fcsel(const FPRegister& fd,
+                      const FPRegister& fn,
+                      const FPRegister& fm,
+                      Condition cond) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  DCHECK(fd.SizeInBits() == fm.SizeInBits());
+  Emit(FPType(fd) | FCSEL | Rm(fm) | Cond(cond) | Rn(fn) | Rd(fd));
+}
+
+
+void Assembler::FPConvertToInt(const Register& rd,
+                               const FPRegister& fn,
+                               FPIntegerConvertOp op) {
+  Emit(SF(rd) | FPType(fn) | op | Rn(fn) | Rd(rd));
+}
+
+
+void Assembler::fcvt(const FPRegister& fd,
+                     const FPRegister& fn) {
+  if (fd.Is64Bits()) {
+    // Convert float to double.
+    DCHECK(fn.Is32Bits());
+    FPDataProcessing1Source(fd, fn, FCVT_ds);
+  } else {
+    // Convert double to float.
+    DCHECK(fn.Is64Bits());
+    FPDataProcessing1Source(fd, fn, FCVT_sd);
+  }
+}
+
+
+void Assembler::fcvtau(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTAU);
+}
+
+
+void Assembler::fcvtas(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTAS);
+}
+
+
+void Assembler::fcvtmu(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTMU);
+}
+
+
+void Assembler::fcvtms(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTMS);
+}
+
+
+void Assembler::fcvtnu(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTNU);
+}
+
+
+void Assembler::fcvtns(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTNS);
+}
+
+
+void Assembler::fcvtzu(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTZU);
+}
+
+
+void Assembler::fcvtzs(const Register& rd, const FPRegister& fn) {
+  FPConvertToInt(rd, fn, FCVTZS);
+}
+
+
+void Assembler::scvtf(const FPRegister& fd,
+                      const Register& rn,
+                      unsigned fbits) {
+  if (fbits == 0) {
+    Emit(SF(rn) | FPType(fd) | SCVTF | Rn(rn) | Rd(fd));
+  } else {
+    Emit(SF(rn) | FPType(fd) | SCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
+         Rd(fd));
+  }
+}
+
+
+void Assembler::ucvtf(const FPRegister& fd,
+                      const Register& rn,
+                      unsigned fbits) {
+  if (fbits == 0) {
+    Emit(SF(rn) | FPType(fd) | UCVTF | Rn(rn) | Rd(fd));
+  } else {
+    Emit(SF(rn) | FPType(fd) | UCVTF_fixed | FPScale(64 - fbits) | Rn(rn) |
+         Rd(fd));
+  }
+}
+
+
+// Note:
+// Below, a difference in case for the same letter indicates a
+// negated bit.
+// If b is 1, then B is 0.
+Instr Assembler::ImmFP32(float imm) {
+  DCHECK(IsImmFP32(imm));
+  // bits: aBbb.bbbc.defg.h000.0000.0000.0000.0000
+  uint32_t bits = float_to_rawbits(imm);
+  // bit7: a000.0000
+  uint32_t bit7 = ((bits >> 31) & 0x1) << 7;
+  // bit6: 0b00.0000
+  uint32_t bit6 = ((bits >> 29) & 0x1) << 6;
+  // bit5_to_0: 00cd.efgh
+  uint32_t bit5_to_0 = (bits >> 19) & 0x3f;
+
+  return (bit7 | bit6 | bit5_to_0) << ImmFP_offset;
+}
+
+
+Instr Assembler::ImmFP64(double imm) {
+  DCHECK(IsImmFP64(imm));
+  // bits: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+  //       0000.0000.0000.0000.0000.0000.0000.0000
+  uint64_t bits = double_to_rawbits(imm);
+  // bit7: a000.0000
+  uint32_t bit7 = ((bits >> 63) & 0x1) << 7;
+  // bit6: 0b00.0000
+  uint32_t bit6 = ((bits >> 61) & 0x1) << 6;
+  // bit5_to_0: 00cd.efgh
+  uint32_t bit5_to_0 = (bits >> 48) & 0x3f;
+
+  return (bit7 | bit6 | bit5_to_0) << ImmFP_offset;
+}
+
+
+// Code generation helpers.
+void Assembler::MoveWide(const Register& rd,
+                         uint64_t imm,
+                         int shift,
+                         MoveWideImmediateOp mov_op) {
+  // Ignore the top 32 bits of an immediate if we're moving to a W register.
+  if (rd.Is32Bits()) {
+    // Check that the top 32 bits are zero (a positive 32-bit number) or top
+    // 33 bits are one (a negative 32-bit number, sign extended to 64 bits).
+    DCHECK(((imm >> kWRegSizeInBits) == 0) ||
+           ((imm >> (kWRegSizeInBits - 1)) == 0x1ffffffff));
+    imm &= kWRegMask;
+  }
+
+  if (shift >= 0) {
+    // Explicit shift specified.
+    DCHECK((shift == 0) || (shift == 16) || (shift == 32) || (shift == 48));
+    DCHECK(rd.Is64Bits() || (shift == 0) || (shift == 16));
+    shift /= 16;
+  } else {
+    // Calculate a new immediate and shift combination to encode the immediate
+    // argument.
+    shift = 0;
+    if ((imm & ~0xffffUL) == 0) {
+      // Nothing to do.
+    } else if ((imm & ~(0xffffUL << 16)) == 0) {
+      imm >>= 16;
+      shift = 1;
+    } else if ((imm & ~(0xffffUL << 32)) == 0) {
+      DCHECK(rd.Is64Bits());
+      imm >>= 32;
+      shift = 2;
+    } else if ((imm & ~(0xffffUL << 48)) == 0) {
+      DCHECK(rd.Is64Bits());
+      imm >>= 48;
+      shift = 3;
+    }
+  }
+
+  DCHECK(is_uint16(imm));
+
+  Emit(SF(rd) | MoveWideImmediateFixed | mov_op |
+       Rd(rd) | ImmMoveWide(imm) | ShiftMoveWide(shift));
+}
+
+
+void Assembler::AddSub(const Register& rd,
+                       const Register& rn,
+                       const Operand& operand,
+                       FlagsUpdate S,
+                       AddSubOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(!operand.NeedsRelocation(this));
+  if (operand.IsImmediate()) {
+    int64_t immediate = operand.ImmediateValue();
+    DCHECK(IsImmAddSub(immediate));
+    Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
+    Emit(SF(rd) | AddSubImmediateFixed | op | Flags(S) |
+         ImmAddSub(immediate) | dest_reg | RnSP(rn));
+  } else if (operand.IsShiftedRegister()) {
+    DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
+    DCHECK(operand.shift() != ROR);
+
+    // For instructions of the form:
+    //   add/sub   wsp, <Wn>, <Wm> [, LSL #0-3 ]
+    //   add/sub   <Wd>, wsp, <Wm> [, LSL #0-3 ]
+    //   add/sub   wsp, wsp, <Wm> [, LSL #0-3 ]
+    //   adds/subs <Wd>, wsp, <Wm> [, LSL #0-3 ]
+    // or their 64-bit register equivalents, convert the operand from shifted to
+    // extended register mode, and emit an add/sub extended instruction.
+    if (rn.IsSP() || rd.IsSP()) {
+      DCHECK(!(rd.IsSP() && (S == SetFlags)));
+      DataProcExtendedRegister(rd, rn, operand.ToExtendedRegister(), S,
+                               AddSubExtendedFixed | op);
+    } else {
+      DataProcShiftedRegister(rd, rn, operand, S, AddSubShiftedFixed | op);
+    }
+  } else {
+    DCHECK(operand.IsExtendedRegister());
+    DataProcExtendedRegister(rd, rn, operand, S, AddSubExtendedFixed | op);
+  }
+}
+
+
+void Assembler::AddSubWithCarry(const Register& rd,
+                                const Register& rn,
+                                const Operand& operand,
+                                FlagsUpdate S,
+                                AddSubWithCarryOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(rd.SizeInBits() == operand.reg().SizeInBits());
+  DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
+  DCHECK(!operand.NeedsRelocation(this));
+  Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::hlt(int code) {
+  DCHECK(is_uint16(code));
+  Emit(HLT | ImmException(code));
+}
+
+
+void Assembler::brk(int code) {
+  DCHECK(is_uint16(code));
+  Emit(BRK | ImmException(code));
+}
+
+
+void Assembler::EmitStringData(const char* string) {
+  size_t len = strlen(string) + 1;
+  DCHECK(RoundUp(len, kInstructionSize) <= static_cast<size_t>(kGap));
+  EmitData(string, len);
+  // Pad with NULL characters until pc_ is aligned.
+  const char pad[] = {'\0', '\0', '\0', '\0'};
+  STATIC_ASSERT(sizeof(pad) == kInstructionSize);
+  EmitData(pad, RoundUp(pc_offset(), kInstructionSize) - pc_offset());
+}
+
+
+void Assembler::debug(const char* message, uint32_t code, Instr params) {
+#ifdef USE_SIMULATOR
+  // Don't generate simulator specific code if we are building a snapshot, which
+  // might be run on real hardware.
+  if (!serializer_enabled()) {
+    // The arguments to the debug marker need to be contiguous in memory, so
+    // make sure we don't try to emit pools.
+    BlockPoolsScope scope(this);
+
+    Label start;
+    bind(&start);
+
+    // Refer to instructions-arm64.h for a description of the marker and its
+    // arguments.
+    hlt(kImmExceptionIsDebug);
+    DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugCodeOffset);
+    dc32(code);
+    DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugParamsOffset);
+    dc32(params);
+    DCHECK(SizeOfCodeGeneratedSince(&start) == kDebugMessageOffset);
+    EmitStringData(message);
+    hlt(kImmExceptionIsUnreachable);
+
+    return;
+  }
+  // Fall through if Serializer is enabled.
+#endif
+
+  if (params & BREAK) {
+    hlt(kImmExceptionIsDebug);
+  }
+}
+
+
+void Assembler::Logical(const Register& rd,
+                        const Register& rn,
+                        const Operand& operand,
+                        LogicalOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  DCHECK(!operand.NeedsRelocation(this));
+  if (operand.IsImmediate()) {
+    int64_t immediate = operand.ImmediateValue();
+    unsigned reg_size = rd.SizeInBits();
+
+    DCHECK(immediate != 0);
+    DCHECK(immediate != -1);
+    DCHECK(rd.Is64Bits() || is_uint32(immediate));
+
+    // If the operation is NOT, invert the operation and immediate.
+    if ((op & NOT) == NOT) {
+      op = static_cast<LogicalOp>(op & ~NOT);
+      immediate = rd.Is64Bits() ? ~immediate : (~immediate & kWRegMask);
+    }
+
+    unsigned n, imm_s, imm_r;
+    if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
+      // Immediate can be encoded in the instruction.
+      LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
+    } else {
+      // This case is handled in the macro assembler.
+      UNREACHABLE();
+    }
+  } else {
+    DCHECK(operand.IsShiftedRegister());
+    DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
+    Instr dp_op = static_cast<Instr>(op | LogicalShiftedFixed);
+    DataProcShiftedRegister(rd, rn, operand, LeaveFlags, dp_op);
+  }
+}
+
+
+void Assembler::LogicalImmediate(const Register& rd,
+                                 const Register& rn,
+                                 unsigned n,
+                                 unsigned imm_s,
+                                 unsigned imm_r,
+                                 LogicalOp op) {
+  unsigned reg_size = rd.SizeInBits();
+  Instr dest_reg = (op == ANDS) ? Rd(rd) : RdSP(rd);
+  Emit(SF(rd) | LogicalImmediateFixed | op | BitN(n, reg_size) |
+       ImmSetBits(imm_s, reg_size) | ImmRotate(imm_r, reg_size) | dest_reg |
+       Rn(rn));
+}
+
+
+void Assembler::ConditionalCompare(const Register& rn,
+                                   const Operand& operand,
+                                   StatusFlags nzcv,
+                                   Condition cond,
+                                   ConditionalCompareOp op) {
+  Instr ccmpop;
+  DCHECK(!operand.NeedsRelocation(this));
+  if (operand.IsImmediate()) {
+    int64_t immediate = operand.ImmediateValue();
+    DCHECK(IsImmConditionalCompare(immediate));
+    ccmpop = ConditionalCompareImmediateFixed | op | ImmCondCmp(immediate);
+  } else {
+    DCHECK(operand.IsShiftedRegister() && (operand.shift_amount() == 0));
+    ccmpop = ConditionalCompareRegisterFixed | op | Rm(operand.reg());
+  }
+  Emit(SF(rn) | ccmpop | Cond(cond) | Rn(rn) | Nzcv(nzcv));
+}
+
+
+void Assembler::DataProcessing1Source(const Register& rd,
+                                      const Register& rn,
+                                      DataProcessing1SourceOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  Emit(SF(rn) | op | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::FPDataProcessing1Source(const FPRegister& fd,
+                                        const FPRegister& fn,
+                                        FPDataProcessing1SourceOp op) {
+  Emit(FPType(fn) | op | Rn(fn) | Rd(fd));
+}
+
+
+void Assembler::FPDataProcessing2Source(const FPRegister& fd,
+                                        const FPRegister& fn,
+                                        const FPRegister& fm,
+                                        FPDataProcessing2SourceOp op) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  DCHECK(fd.SizeInBits() == fm.SizeInBits());
+  Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd));
+}
+
+
+void Assembler::FPDataProcessing3Source(const FPRegister& fd,
+                                        const FPRegister& fn,
+                                        const FPRegister& fm,
+                                        const FPRegister& fa,
+                                        FPDataProcessing3SourceOp op) {
+  DCHECK(AreSameSizeAndType(fd, fn, fm, fa));
+  Emit(FPType(fd) | op | Rm(fm) | Rn(fn) | Rd(fd) | Ra(fa));
+}
+
+
+void Assembler::EmitShift(const Register& rd,
+                          const Register& rn,
+                          Shift shift,
+                          unsigned shift_amount) {
+  switch (shift) {
+    case LSL:
+      lsl(rd, rn, shift_amount);
+      break;
+    case LSR:
+      lsr(rd, rn, shift_amount);
+      break;
+    case ASR:
+      asr(rd, rn, shift_amount);
+      break;
+    case ROR:
+      ror(rd, rn, shift_amount);
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Assembler::EmitExtendShift(const Register& rd,
+                                const Register& rn,
+                                Extend extend,
+                                unsigned left_shift) {
+  DCHECK(rd.SizeInBits() >= rn.SizeInBits());
+  unsigned reg_size = rd.SizeInBits();
+  // Use the correct size of register.
+  Register rn_ = Register::Create(rn.code(), rd.SizeInBits());
+  // Bits extracted are high_bit:0.
+  unsigned high_bit = (8 << (extend & 0x3)) - 1;
+  // Number of bits left in the result that are not introduced by the shift.
+  unsigned non_shift_bits = (reg_size - left_shift) & (reg_size - 1);
+
+  if ((non_shift_bits > high_bit) || (non_shift_bits == 0)) {
+    switch (extend) {
+      case UXTB:
+      case UXTH:
+      case UXTW: ubfm(rd, rn_, non_shift_bits, high_bit); break;
+      case SXTB:
+      case SXTH:
+      case SXTW: sbfm(rd, rn_, non_shift_bits, high_bit); break;
+      case UXTX:
+      case SXTX: {
+        DCHECK(rn.SizeInBits() == kXRegSizeInBits);
+        // Nothing to extend. Just shift.
+        lsl(rd, rn_, left_shift);
+        break;
+      }
+      default: UNREACHABLE();
+    }
+  } else {
+    // No need to extend as the extended bits would be shifted away.
+    lsl(rd, rn_, left_shift);
+  }
+}
+
+
+void Assembler::DataProcShiftedRegister(const Register& rd,
+                                        const Register& rn,
+                                        const Operand& operand,
+                                        FlagsUpdate S,
+                                        Instr op) {
+  DCHECK(operand.IsShiftedRegister());
+  DCHECK(rn.Is64Bits() || (rn.Is32Bits() && is_uint5(operand.shift_amount())));
+  DCHECK(!operand.NeedsRelocation(this));
+  Emit(SF(rd) | op | Flags(S) |
+       ShiftDP(operand.shift()) | ImmDPShift(operand.shift_amount()) |
+       Rm(operand.reg()) | Rn(rn) | Rd(rd));
+}
+
+
+void Assembler::DataProcExtendedRegister(const Register& rd,
+                                         const Register& rn,
+                                         const Operand& operand,
+                                         FlagsUpdate S,
+                                         Instr op) {
+  DCHECK(!operand.NeedsRelocation(this));
+  Instr dest_reg = (S == SetFlags) ? Rd(rd) : RdSP(rd);
+  Emit(SF(rd) | op | Flags(S) | Rm(operand.reg()) |
+       ExtendMode(operand.extend()) | ImmExtendShift(operand.shift_amount()) |
+       dest_reg | RnSP(rn));
+}
+
+
+bool Assembler::IsImmAddSub(int64_t immediate) {
+  return is_uint12(immediate) ||
+         (is_uint12(immediate >> 12) && ((immediate & 0xfff) == 0));
+}
+
+void Assembler::LoadStore(const CPURegister& rt,
+                          const MemOperand& addr,
+                          LoadStoreOp op) {
+  Instr memop = op | Rt(rt) | RnSP(addr.base());
+  int64_t offset = addr.offset();
+
+  if (addr.IsImmediateOffset()) {
+    LSDataSize size = CalcLSDataSize(op);
+    if (IsImmLSScaled(offset, size)) {
+      // Use the scaled addressing mode.
+      Emit(LoadStoreUnsignedOffsetFixed | memop |
+           ImmLSUnsigned(offset >> size));
+    } else if (IsImmLSUnscaled(offset)) {
+      // Use the unscaled addressing mode.
+      Emit(LoadStoreUnscaledOffsetFixed | memop | ImmLS(offset));
+    } else {
+      // This case is handled in the macro assembler.
+      UNREACHABLE();
+    }
+  } else if (addr.IsRegisterOffset()) {
+    Extend ext = addr.extend();
+    Shift shift = addr.shift();
+    unsigned shift_amount = addr.shift_amount();
+
+    // LSL is encoded in the option field as UXTX.
+    if (shift == LSL) {
+      ext = UXTX;
+    }
+
+    // Shifts are encoded in one bit, indicating a left shift by the memory
+    // access size.
+    DCHECK((shift_amount == 0) ||
+           (shift_amount == static_cast<unsigned>(CalcLSDataSize(op))));
+    Emit(LoadStoreRegisterOffsetFixed | memop | Rm(addr.regoffset()) |
+         ExtendMode(ext) | ImmShiftLS((shift_amount > 0) ? 1 : 0));
+  } else {
+    // Pre-index and post-index modes.
+    DCHECK(!rt.Is(addr.base()));
+    if (IsImmLSUnscaled(offset)) {
+      if (addr.IsPreIndex()) {
+        Emit(LoadStorePreIndexFixed | memop | ImmLS(offset));
+      } else {
+        DCHECK(addr.IsPostIndex());
+        Emit(LoadStorePostIndexFixed | memop | ImmLS(offset));
+      }
+    } else {
+      // This case is handled in the macro assembler.
+      UNREACHABLE();
+    }
+  }
+}
+
+
+bool Assembler::IsImmLSUnscaled(int64_t offset) {
+  return is_int9(offset);
+}
+
+
+bool Assembler::IsImmLSScaled(int64_t offset, LSDataSize size) {
+  bool offset_is_size_multiple = (((offset >> size) << size) == offset);
+  return offset_is_size_multiple && is_uint12(offset >> size);
+}
+
+
+bool Assembler::IsImmLSPair(int64_t offset, LSDataSize size) {
+  bool offset_is_size_multiple = (((offset >> size) << size) == offset);
+  return offset_is_size_multiple && is_int7(offset >> size);
+}
+
+
+// Test if a given value can be encoded in the immediate field of a logical
+// instruction.
+// If it can be encoded, the function returns true, and values pointed to by n,
+// imm_s and imm_r are updated with immediates encoded in the format required
+// by the corresponding fields in the logical instruction.
+// If it can not be encoded, the function returns false, and the values pointed
+// to by n, imm_s and imm_r are undefined.
+bool Assembler::IsImmLogical(uint64_t value,
+                             unsigned width,
+                             unsigned* n,
+                             unsigned* imm_s,
+                             unsigned* imm_r) {
+  DCHECK((n != NULL) && (imm_s != NULL) && (imm_r != NULL));
+  DCHECK((width == kWRegSizeInBits) || (width == kXRegSizeInBits));
+
+  bool negate = false;
+
+  // Logical immediates are encoded using parameters n, imm_s and imm_r using
+  // the following table:
+  //
+  //    N   imms    immr    size        S             R
+  //    1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
+  //    0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
+  //    0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
+  //    0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
+  //    0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
+  //    0  11110s  xxxxxr     2    UInt(s)       UInt(r)
+  // (s bits must not be all set)
+  //
+  // A pattern is constructed of size bits, where the least significant S+1 bits
+  // are set. The pattern is rotated right by R, and repeated across a 32 or
+  // 64-bit value, depending on destination register width.
+  //
+  // Put another way: the basic format of a logical immediate is a single
+  // contiguous stretch of 1 bits, repeated across the whole word at intervals
+  // given by a power of 2. To identify them quickly, we first locate the
+  // lowest stretch of 1 bits, then the next 1 bit above that; that combination
+  // is different for every logical immediate, so it gives us all the
+  // information we need to identify the only logical immediate that our input
+  // could be, and then we simply check if that's the value we actually have.
+  //
+  // (The rotation parameter does give the possibility of the stretch of 1 bits
+  // going 'round the end' of the word. To deal with that, we observe that in
+  // any situation where that happens the bitwise NOT of the value is also a
+  // valid logical immediate. So we simply invert the input whenever its low bit
+  // is set, and then we know that the rotated case can't arise.)
+
+  if (value & 1) {
+    // If the low bit is 1, negate the value, and set a flag to remember that we
+    // did (so that we can adjust the return values appropriately).
+    negate = true;
+    value = ~value;
+  }
+
+  if (width == kWRegSizeInBits) {
+    // To handle 32-bit logical immediates, the very easiest thing is to repeat
+    // the input value twice to make a 64-bit word. The correct encoding of that
+    // as a logical immediate will also be the correct encoding of the 32-bit
+    // value.
+
+    // The most-significant 32 bits may not be zero (ie. negate is true) so
+    // shift the value left before duplicating it.
+    value <<= kWRegSizeInBits;
+    value |= value >> kWRegSizeInBits;
+  }
+
+  // The basic analysis idea: imagine our input word looks like this.
+  //
+  //    0011111000111110001111100011111000111110001111100011111000111110
+  //                                                          c  b    a
+  //                                                          |<--d-->|
+  //
+  // We find the lowest set bit (as an actual power-of-2 value, not its index)
+  // and call it a. Then we add a to our original number, which wipes out the
+  // bottommost stretch of set bits and replaces it with a 1 carried into the
+  // next zero bit. Then we look for the new lowest set bit, which is in
+  // position b, and subtract it, so now our number is just like the original
+  // but with the lowest stretch of set bits completely gone. Now we find the
+  // lowest set bit again, which is position c in the diagram above. Then we'll
+  // measure the distance d between bit positions a and c (using CLZ), and that
+  // tells us that the only valid logical immediate that could possibly be equal
+  // to this number is the one in which a stretch of bits running from a to just
+  // below b is replicated every d bits.
+  uint64_t a = LargestPowerOf2Divisor(value);
+  uint64_t value_plus_a = value + a;
+  uint64_t b = LargestPowerOf2Divisor(value_plus_a);
+  uint64_t value_plus_a_minus_b = value_plus_a - b;
+  uint64_t c = LargestPowerOf2Divisor(value_plus_a_minus_b);
+
+  int d, clz_a, out_n;
+  uint64_t mask;
+
+  if (c != 0) {
+    // The general case, in which there is more than one stretch of set bits.
+    // Compute the repeat distance d, and set up a bitmask covering the basic
+    // unit of repetition (i.e. a word with the bottom d bits set). Also, in all
+    // of these cases the N bit of the output will be zero.
+    clz_a = CountLeadingZeros(a, kXRegSizeInBits);
+    int clz_c = CountLeadingZeros(c, kXRegSizeInBits);
+    d = clz_a - clz_c;
+    mask = ((V8_UINT64_C(1) << d) - 1);
+    out_n = 0;
+  } else {
+    // Handle degenerate cases.
+    //
+    // If any of those 'find lowest set bit' operations didn't find a set bit at
+    // all, then the word will have been zero thereafter, so in particular the
+    // last lowest_set_bit operation will have returned zero. So we can test for
+    // all the special case conditions in one go by seeing if c is zero.
+    if (a == 0) {
+      // The input was zero (or all 1 bits, which will come to here too after we
+      // inverted it at the start of the function), for which we just return
+      // false.
+      return false;
+    } else {
+      // Otherwise, if c was zero but a was not, then there's just one stretch
+      // of set bits in our word, meaning that we have the trivial case of
+      // d == 64 and only one 'repetition'. Set up all the same variables as in
+      // the general case above, and set the N bit in the output.
+      clz_a = CountLeadingZeros(a, kXRegSizeInBits);
+      d = 64;
+      mask = ~V8_UINT64_C(0);
+      out_n = 1;
+    }
+  }
+
+  // If the repeat period d is not a power of two, it can't be encoded.
+  if (!IS_POWER_OF_TWO(d)) {
+    return false;
+  }
+
+  if (((b - a) & ~mask) != 0) {
+    // If the bit stretch (b - a) does not fit within the mask derived from the
+    // repeat period, then fail.
+    return false;
+  }
+
+  // The only possible option is b - a repeated every d bits. Now we're going to
+  // actually construct the valid logical immediate derived from that
+  // specification, and see if it equals our original input.
+  //
+  // To repeat a value every d bits, we multiply it by a number of the form
+  // (1 + 2^d + 2^(2d) + ...), i.e. 0x0001000100010001 or similar. These can
+  // be derived using a table lookup on CLZ(d).
+  static const uint64_t multipliers[] = {
+    0x0000000000000001UL,
+    0x0000000100000001UL,
+    0x0001000100010001UL,
+    0x0101010101010101UL,
+    0x1111111111111111UL,
+    0x5555555555555555UL,
+  };
+  int multiplier_idx = CountLeadingZeros(d, kXRegSizeInBits) - 57;
+  // Ensure that the index to the multipliers array is within bounds.
+  DCHECK((multiplier_idx >= 0) &&
+         (static_cast<size_t>(multiplier_idx) < arraysize(multipliers)));
+  uint64_t multiplier = multipliers[multiplier_idx];
+  uint64_t candidate = (b - a) * multiplier;
+
+  if (value != candidate) {
+    // The candidate pattern doesn't match our input value, so fail.
+    return false;
+  }
+
+  // We have a match! This is a valid logical immediate, so now we have to
+  // construct the bits and pieces of the instruction encoding that generates
+  // it.
+
+  // Count the set bits in our basic stretch. The special case of clz(0) == -1
+  // makes the answer come out right for stretches that reach the very top of
+  // the word (e.g. numbers like 0xffffc00000000000).
+  int clz_b = (b == 0) ? -1 : CountLeadingZeros(b, kXRegSizeInBits);
+  int s = clz_a - clz_b;
+
+  // Decide how many bits to rotate right by, to put the low bit of that basic
+  // stretch in position a.
+  int r;
+  if (negate) {
+    // If we inverted the input right at the start of this function, here's
+    // where we compensate: the number of set bits becomes the number of clear
+    // bits, and the rotation count is based on position b rather than position
+    // a (since b is the location of the 'lowest' 1 bit after inversion).
+    s = d - s;
+    r = (clz_b + 1) & (d - 1);
+  } else {
+    r = (clz_a + 1) & (d - 1);
+  }
+
+  // Now we're done, except for having to encode the S output in such a way that
+  // it gives both the number of set bits and the length of the repeated
+  // segment. The s field is encoded like this:
+  //
+  //     imms    size        S
+  //    ssssss    64    UInt(ssssss)
+  //    0sssss    32    UInt(sssss)
+  //    10ssss    16    UInt(ssss)
+  //    110sss     8    UInt(sss)
+  //    1110ss     4    UInt(ss)
+  //    11110s     2    UInt(s)
+  //
+  // So we 'or' (-d << 1) with our computed s to form imms.
+  *n = out_n;
+  *imm_s = ((-d << 1) | (s - 1)) & 0x3f;
+  *imm_r = r;
+
+  return true;
+}
+
+
+bool Assembler::IsImmConditionalCompare(int64_t immediate) {
+  return is_uint5(immediate);
+}
+
+
+bool Assembler::IsImmFP32(float imm) {
+  // Valid values will have the form:
+  // aBbb.bbbc.defg.h000.0000.0000.0000.0000
+  uint32_t bits = float_to_rawbits(imm);
+  // bits[19..0] are cleared.
+  if ((bits & 0x7ffff) != 0) {
+    return false;
+  }
+
+  // bits[29..25] are all set or all cleared.
+  uint32_t b_pattern = (bits >> 16) & 0x3e00;
+  if (b_pattern != 0 && b_pattern != 0x3e00) {
+    return false;
+  }
+
+  // bit[30] and bit[29] are opposite.
+  if (((bits ^ (bits << 1)) & 0x40000000) == 0) {
+    return false;
+  }
+
+  return true;
+}
+
+
+bool Assembler::IsImmFP64(double imm) {
+  // Valid values will have the form:
+  // aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+  // 0000.0000.0000.0000.0000.0000.0000.0000
+  uint64_t bits = double_to_rawbits(imm);
+  // bits[47..0] are cleared.
+  if ((bits & 0xffffffffffffL) != 0) {
+    return false;
+  }
+
+  // bits[61..54] are all set or all cleared.
+  uint32_t b_pattern = (bits >> 48) & 0x3fc0;
+  if (b_pattern != 0 && b_pattern != 0x3fc0) {
+    return false;
+  }
+
+  // bit[62] and bit[61] are opposite.
+  if (((bits ^ (bits << 1)) & 0x4000000000000000L) == 0) {
+    return false;
+  }
+
+  return true;
+}
+
+
+void Assembler::GrowBuffer() {
+  if (!own_buffer_) FATAL("external code buffer is too small");
+
+  // Compute new buffer size.
+  CodeDesc desc;  // the new buffer
+  if (buffer_size_ < 1 * MB) {
+    desc.buffer_size = 2 * buffer_size_;
+  } else {
+    desc.buffer_size = buffer_size_ + 1 * MB;
+  }
+  CHECK_GT(desc.buffer_size, 0);  // No overflow.
+
+  byte* buffer = reinterpret_cast<byte*>(buffer_);
+
+  // Set up new buffer.
+  desc.buffer = NewArray<byte>(desc.buffer_size);
+
+  desc.instr_size = pc_offset();
+  desc.reloc_size = (buffer + buffer_size_) - reloc_info_writer.pos();
+
+  // Copy the data.
+  intptr_t pc_delta = desc.buffer - buffer;
+  intptr_t rc_delta = (desc.buffer + desc.buffer_size) -
+                      (buffer + buffer_size_);
+  memmove(desc.buffer, buffer, desc.instr_size);
+  memmove(reloc_info_writer.pos() + rc_delta,
+          reloc_info_writer.pos(), desc.reloc_size);
+
+  // Switch buffers.
+  DeleteArray(buffer_);
+  buffer_ = desc.buffer;
+  buffer_size_ = desc.buffer_size;
+  pc_ = reinterpret_cast<byte*>(pc_) + pc_delta;
+  reloc_info_writer.Reposition(reloc_info_writer.pos() + rc_delta,
+                               reloc_info_writer.last_pc() + pc_delta);
+
+  // None of our relocation types are pc relative pointing outside the code
+  // buffer nor pc absolute pointing inside the code buffer, so there is no need
+  // to relocate any emitted relocation entries.
+
+  // Pending relocation entries are also relative, no need to relocate.
+}
+
+
+void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) {
+  // We do not try to reuse pool constants.
+  RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL);
+  if (((rmode >= RelocInfo::JS_RETURN) &&
+       (rmode <= RelocInfo::DEBUG_BREAK_SLOT)) ||
+      (rmode == RelocInfo::CONST_POOL) ||
+      (rmode == RelocInfo::VENEER_POOL)) {
+    // Adjust code for new modes.
+    DCHECK(RelocInfo::IsDebugBreakSlot(rmode)
+           || RelocInfo::IsJSReturn(rmode)
+           || RelocInfo::IsComment(rmode)
+           || RelocInfo::IsPosition(rmode)
+           || RelocInfo::IsConstPool(rmode)
+           || RelocInfo::IsVeneerPool(rmode));
+    // These modes do not need an entry in the constant pool.
+  } else {
+    constpool_.RecordEntry(data, rmode);
+    // Make sure the constant pool is not emitted in place of the next
+    // instruction for which we just recorded relocation info.
+    BlockConstPoolFor(1);
+  }
+
+  if (!RelocInfo::IsNone(rmode)) {
+    // Don't record external references unless the heap will be serialized.
+    if (rmode == RelocInfo::EXTERNAL_REFERENCE &&
+        !serializer_enabled() && !emit_debug_code()) {
+      return;
+    }
+    DCHECK(buffer_space() >= kMaxRelocSize);  // too late to grow buffer here
+    if (rmode == RelocInfo::CODE_TARGET_WITH_ID) {
+      RelocInfo reloc_info_with_ast_id(
+          reinterpret_cast<byte*>(pc_), rmode, RecordedAstId().ToInt(), NULL);
+      ClearRecordedAstId();
+      reloc_info_writer.Write(&reloc_info_with_ast_id);
+    } else {
+      reloc_info_writer.Write(&rinfo);
+    }
+  }
+}
+
+
+void Assembler::BlockConstPoolFor(int instructions) {
+  int pc_limit = pc_offset() + instructions * kInstructionSize;
+  if (no_const_pool_before_ < pc_limit) {
+    no_const_pool_before_ = pc_limit;
+    // Make sure the pool won't be blocked for too long.
+    DCHECK(pc_limit < constpool_.MaxPcOffset());
+  }
+
+  if (next_constant_pool_check_ < no_const_pool_before_) {
+    next_constant_pool_check_ = no_const_pool_before_;
+  }
+}
+
+
+void Assembler::CheckConstPool(bool force_emit, bool require_jump) {
+  // Some short sequence of instruction mustn't be broken up by constant pool
+  // emission, such sequences are protected by calls to BlockConstPoolFor and
+  // BlockConstPoolScope.
+  if (is_const_pool_blocked()) {
+    // Something is wrong if emission is forced and blocked at the same time.
+    DCHECK(!force_emit);
+    return;
+  }
+
+  // There is nothing to do if there are no pending constant pool entries.
+  if (constpool_.IsEmpty())  {
+    // Calculate the offset of the next check.
+    SetNextConstPoolCheckIn(kCheckConstPoolInterval);
+    return;
+  }
+
+  // We emit a constant pool when:
+  //  * requested to do so by parameter force_emit (e.g. after each function).
+  //  * the distance to the first instruction accessing the constant pool is
+  //    kApproxMaxDistToConstPool or more.
+  //  * the number of entries in the pool is kApproxMaxPoolEntryCount or more.
+  int dist = constpool_.DistanceToFirstUse();
+  int count = constpool_.EntryCount();
+  if (!force_emit &&
+      (dist < kApproxMaxDistToConstPool) &&
+      (count < kApproxMaxPoolEntryCount)) {
+    return;
+  }
+
+
+  // Emit veneers for branches that would go out of range during emission of the
+  // constant pool.
+  int worst_case_size = constpool_.WorstCaseSize();
+  CheckVeneerPool(false, require_jump,
+                  kVeneerDistanceMargin + worst_case_size);
+
+  // Check that the code buffer is large enough before emitting the constant
+  // pool (this includes the gap to the relocation information).
+  int needed_space = worst_case_size + kGap + 1 * kInstructionSize;
+  while (buffer_space() <= needed_space) {
+    GrowBuffer();
+  }
+
+  Label size_check;
+  bind(&size_check);
+  constpool_.Emit(require_jump);
+  DCHECK(SizeOfCodeGeneratedSince(&size_check) <=
+         static_cast<unsigned>(worst_case_size));
+
+  // Since a constant pool was just emitted, move the check offset forward by
+  // the standard interval.
+  SetNextConstPoolCheckIn(kCheckConstPoolInterval);
+}
+
+
+bool Assembler::ShouldEmitVeneer(int max_reachable_pc, int margin) {
+  // Account for the branch around the veneers and the guard.
+  int protection_offset = 2 * kInstructionSize;
+  return pc_offset() > max_reachable_pc - margin - protection_offset -
+    static_cast<int>(unresolved_branches_.size() * kMaxVeneerCodeSize);
+}
+
+
+void Assembler::RecordVeneerPool(int location_offset, int size) {
+  RelocInfo rinfo(buffer_ + location_offset,
+                  RelocInfo::VENEER_POOL, static_cast<intptr_t>(size),
+                  NULL);
+  reloc_info_writer.Write(&rinfo);
+}
+
+
+void Assembler::EmitVeneers(bool force_emit, bool need_protection, int margin) {
+  BlockPoolsScope scope(this);
+  RecordComment("[ Veneers");
+
+  // The exact size of the veneer pool must be recorded (see the comment at the
+  // declaration site of RecordConstPool()), but computing the number of
+  // veneers that will be generated is not obvious. So instead we remember the
+  // current position and will record the size after the pool has been
+  // generated.
+  Label size_check;
+  bind(&size_check);
+  int veneer_pool_relocinfo_loc = pc_offset();
+
+  Label end;
+  if (need_protection) {
+    b(&end);
+  }
+
+  EmitVeneersGuard();
+
+  Label veneer_size_check;
+
+  std::multimap<int, FarBranchInfo>::iterator it, it_to_delete;
+
+  it = unresolved_branches_.begin();
+  while (it != unresolved_branches_.end()) {
+    if (force_emit || ShouldEmitVeneer(it->first, margin)) {
+      Instruction* branch = InstructionAt(it->second.pc_offset_);
+      Label* label = it->second.label_;
+
+#ifdef DEBUG
+      bind(&veneer_size_check);
+#endif
+      // Patch the branch to point to the current position, and emit a branch
+      // to the label.
+      Instruction* veneer = reinterpret_cast<Instruction*>(pc_);
+      RemoveBranchFromLabelLinkChain(branch, label, veneer);
+      branch->SetImmPCOffsetTarget(veneer);
+      b(label);
+#ifdef DEBUG
+      DCHECK(SizeOfCodeGeneratedSince(&veneer_size_check) <=
+             static_cast<uint64_t>(kMaxVeneerCodeSize));
+      veneer_size_check.Unuse();
+#endif
+
+      it_to_delete = it++;
+      unresolved_branches_.erase(it_to_delete);
+    } else {
+      ++it;
+    }
+  }
+
+  // Record the veneer pool size.
+  int pool_size = SizeOfCodeGeneratedSince(&size_check);
+  RecordVeneerPool(veneer_pool_relocinfo_loc, pool_size);
+
+  if (unresolved_branches_.empty()) {
+    next_veneer_pool_check_ = kMaxInt;
+  } else {
+    next_veneer_pool_check_ =
+      unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
+  }
+
+  bind(&end);
+
+  RecordComment("]");
+}
+
+
+void Assembler::CheckVeneerPool(bool force_emit, bool require_jump,
+                                int margin) {
+  // There is nothing to do if there are no pending veneer pool entries.
+  if (unresolved_branches_.empty())  {
+    DCHECK(next_veneer_pool_check_ == kMaxInt);
+    return;
+  }
+
+  DCHECK(pc_offset() < unresolved_branches_first_limit());
+
+  // Some short sequence of instruction mustn't be broken up by veneer pool
+  // emission, such sequences are protected by calls to BlockVeneerPoolFor and
+  // BlockVeneerPoolScope.
+  if (is_veneer_pool_blocked()) {
+    DCHECK(!force_emit);
+    return;
+  }
+
+  if (!require_jump) {
+    // Prefer emitting veneers protected by an existing instruction.
+    margin *= kVeneerNoProtectionFactor;
+  }
+  if (force_emit || ShouldEmitVeneers(margin)) {
+    EmitVeneers(force_emit, require_jump, margin);
+  } else {
+    next_veneer_pool_check_ =
+      unresolved_branches_first_limit() - kVeneerDistanceCheckMargin;
+  }
+}
+
+
+void Assembler::RecordComment(const char* msg) {
+  if (FLAG_code_comments) {
+    CheckBuffer();
+    RecordRelocInfo(RelocInfo::COMMENT, reinterpret_cast<intptr_t>(msg));
+  }
+}
+
+
+int Assembler::buffer_space() const {
+  return reloc_info_writer.pos() - reinterpret_cast<byte*>(pc_);
+}
+
+
+void Assembler::RecordJSReturn() {
+  positions_recorder()->WriteRecordedPositions();
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::JS_RETURN);
+}
+
+
+void Assembler::RecordDebugBreakSlot() {
+  positions_recorder()->WriteRecordedPositions();
+  CheckBuffer();
+  RecordRelocInfo(RelocInfo::DEBUG_BREAK_SLOT);
+}
+
+
+void Assembler::RecordConstPool(int size) {
+  // We only need this for debugger support, to correctly compute offsets in the
+  // code.
+  RecordRelocInfo(RelocInfo::CONST_POOL, static_cast<intptr_t>(size));
+}
+
+
+Handle<ConstantPoolArray> Assembler::NewConstantPool(Isolate* isolate) {
+  // No out-of-line constant pool support.
+  DCHECK(!FLAG_enable_ool_constant_pool);
+  return isolate->factory()->empty_constant_pool_array();
+}
+
+
+void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) {
+  // No out-of-line constant pool support.
+  DCHECK(!FLAG_enable_ool_constant_pool);
+  return;
+}
+
+
+void PatchingAssembler::PatchAdrFar(int64_t target_offset) {
+  // The code at the current instruction should be:
+  //   adr  rd, 0
+  //   nop  (adr_far)
+  //   nop  (adr_far)
+  //   movz scratch, 0
+
+  // Verify the expected code.
+  Instruction* expected_adr = InstructionAt(0);
+  CHECK(expected_adr->IsAdr() && (expected_adr->ImmPCRel() == 0));
+  int rd_code = expected_adr->Rd();
+  for (int i = 0; i < kAdrFarPatchableNNops; ++i) {
+    CHECK(InstructionAt((i + 1) * kInstructionSize)->IsNop(ADR_FAR_NOP));
+  }
+  Instruction* expected_movz =
+      InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize);
+  CHECK(expected_movz->IsMovz() &&
+        (expected_movz->ImmMoveWide() == 0) &&
+        (expected_movz->ShiftMoveWide() == 0));
+  int scratch_code = expected_movz->Rd();
+
+  // Patch to load the correct address.
+  Register rd = Register::XRegFromCode(rd_code);
+  Register scratch = Register::XRegFromCode(scratch_code);
+  // Addresses are only 48 bits.
+  adr(rd, target_offset & 0xFFFF);
+  movz(scratch, (target_offset >> 16) & 0xFFFF, 16);
+  movk(scratch, (target_offset >> 32) & 0xFFFF, 32);
+  DCHECK((target_offset >> 48) == 0);
+  add(rd, rd, scratch);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/assembler-arm64.h b/src/arm64/assembler-arm64.h
new file mode 100644
index 0000000..82b4500
--- /dev/null
+++ b/src/arm64/assembler-arm64.h
@@ -0,0 +1,2300 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_ASSEMBLER_ARM64_H_
+#define V8_ARM64_ASSEMBLER_ARM64_H_
+
+#include <list>
+#include <map>
+#include <vector>
+
+#include "src/arm64/instructions-arm64.h"
+#include "src/assembler.h"
+#include "src/globals.h"
+#include "src/serialize.h"
+#include "src/utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+// -----------------------------------------------------------------------------
+// Registers.
+#define REGISTER_CODE_LIST(R)                                                  \
+R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                                 \
+R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                                \
+R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                                \
+R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
+
+
+static const int kRegListSizeInBits = sizeof(RegList) * kBitsPerByte;
+
+
+// Some CPURegister methods can return Register and FPRegister types, so we
+// need to declare them in advance.
+struct Register;
+struct FPRegister;
+
+
+struct CPURegister {
+  enum RegisterType {
+    // The kInvalid value is used to detect uninitialized static instances,
+    // which are always zero-initialized before any constructors are called.
+    kInvalid = 0,
+    kRegister,
+    kFPRegister,
+    kNoRegister
+  };
+
+  static CPURegister Create(unsigned code, unsigned size, RegisterType type) {
+    CPURegister r = {code, size, type};
+    return r;
+  }
+
+  unsigned code() const;
+  RegisterType type() const;
+  RegList Bit() const;
+  unsigned SizeInBits() const;
+  int SizeInBytes() const;
+  bool Is32Bits() const;
+  bool Is64Bits() const;
+  bool IsValid() const;
+  bool IsValidOrNone() const;
+  bool IsValidRegister() const;
+  bool IsValidFPRegister() const;
+  bool IsNone() const;
+  bool Is(const CPURegister& other) const;
+  bool Aliases(const CPURegister& other) const;
+
+  bool IsZero() const;
+  bool IsSP() const;
+
+  bool IsRegister() const;
+  bool IsFPRegister() const;
+
+  Register X() const;
+  Register W() const;
+  FPRegister D() const;
+  FPRegister S() const;
+
+  bool IsSameSizeAndType(const CPURegister& other) const;
+
+  // V8 compatibility.
+  bool is(const CPURegister& other) const { return Is(other); }
+  bool is_valid() const { return IsValid(); }
+
+  unsigned reg_code;
+  unsigned reg_size;
+  RegisterType reg_type;
+};
+
+
+struct Register : public CPURegister {
+  static Register Create(unsigned code, unsigned size) {
+    return Register(CPURegister::Create(code, size, CPURegister::kRegister));
+  }
+
+  Register() {
+    reg_code = 0;
+    reg_size = 0;
+    reg_type = CPURegister::kNoRegister;
+  }
+
+  explicit Register(const CPURegister& r) {
+    reg_code = r.reg_code;
+    reg_size = r.reg_size;
+    reg_type = r.reg_type;
+    DCHECK(IsValidOrNone());
+  }
+
+  Register(const Register& r) {  // NOLINT(runtime/explicit)
+    reg_code = r.reg_code;
+    reg_size = r.reg_size;
+    reg_type = r.reg_type;
+    DCHECK(IsValidOrNone());
+  }
+
+  bool IsValid() const {
+    DCHECK(IsRegister() || IsNone());
+    return IsValidRegister();
+  }
+
+  static Register XRegFromCode(unsigned code);
+  static Register WRegFromCode(unsigned code);
+
+  // Start of V8 compatibility section ---------------------
+  // These memebers are necessary for compilation.
+  // A few of them may be unused for now.
+
+  static const int kNumRegisters = kNumberOfRegisters;
+  static int NumRegisters() { return kNumRegisters; }
+
+  // We allow crankshaft to use the following registers:
+  //   - x0 to x15
+  //   - x18 to x24
+  //   - x27 (also context)
+  //
+  // TODO(all): Register x25 is currently free and could be available for
+  // crankshaft, but we don't use it as we might use it as a per function
+  // literal pool pointer in the future.
+  //
+  // TODO(all): Consider storing cp in x25 to have only two ranges.
+  // We split allocatable registers in three ranges called
+  //   - "low range"
+  //   - "high range"
+  //   - "context"
+  static const unsigned kAllocatableLowRangeBegin = 0;
+  static const unsigned kAllocatableLowRangeEnd = 15;
+  static const unsigned kAllocatableHighRangeBegin = 18;
+  static const unsigned kAllocatableHighRangeEnd = 24;
+  static const unsigned kAllocatableContext = 27;
+
+  // Gap between low and high ranges.
+  static const int kAllocatableRangeGapSize =
+      (kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1;
+
+  static const int kMaxNumAllocatableRegisters =
+      (kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) +
+      (kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1) + 1;  // cp
+  static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
+
+  // Return true if the register is one that crankshaft can allocate.
+  bool IsAllocatable() const {
+    return ((reg_code == kAllocatableContext) ||
+            (reg_code <= kAllocatableLowRangeEnd) ||
+            ((reg_code >= kAllocatableHighRangeBegin) &&
+             (reg_code <= kAllocatableHighRangeEnd)));
+  }
+
+  static Register FromAllocationIndex(unsigned index) {
+    DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters()));
+    // cp is the last allocatable register.
+    if (index == (static_cast<unsigned>(NumAllocatableRegisters() - 1))) {
+      return from_code(kAllocatableContext);
+    }
+
+    // Handle low and high ranges.
+    return (index <= kAllocatableLowRangeEnd)
+        ? from_code(index)
+        : from_code(index + kAllocatableRangeGapSize);
+  }
+
+  static const char* AllocationIndexToString(int index) {
+    DCHECK((index >= 0) && (index < NumAllocatableRegisters()));
+    DCHECK((kAllocatableLowRangeBegin == 0) &&
+           (kAllocatableLowRangeEnd == 15) &&
+           (kAllocatableHighRangeBegin == 18) &&
+           (kAllocatableHighRangeEnd == 24) &&
+           (kAllocatableContext == 27));
+    const char* const names[] = {
+      "x0", "x1", "x2", "x3", "x4",
+      "x5", "x6", "x7", "x8", "x9",
+      "x10", "x11", "x12", "x13", "x14",
+      "x15", "x18", "x19", "x20", "x21",
+      "x22", "x23", "x24", "x27",
+    };
+    return names[index];
+  }
+
+  static int ToAllocationIndex(Register reg) {
+    DCHECK(reg.IsAllocatable());
+    unsigned code = reg.code();
+    if (code == kAllocatableContext) {
+      return NumAllocatableRegisters() - 1;
+    }
+
+    return (code <= kAllocatableLowRangeEnd)
+        ? code
+        : code - kAllocatableRangeGapSize;
+  }
+
+  static Register from_code(int code) {
+    // Always return an X register.
+    return Register::Create(code, kXRegSizeInBits);
+  }
+
+  // End of V8 compatibility section -----------------------
+};
+
+
+struct FPRegister : public CPURegister {
+  static FPRegister Create(unsigned code, unsigned size) {
+    return FPRegister(
+        CPURegister::Create(code, size, CPURegister::kFPRegister));
+  }
+
+  FPRegister() {
+    reg_code = 0;
+    reg_size = 0;
+    reg_type = CPURegister::kNoRegister;
+  }
+
+  explicit FPRegister(const CPURegister& r) {
+    reg_code = r.reg_code;
+    reg_size = r.reg_size;
+    reg_type = r.reg_type;
+    DCHECK(IsValidOrNone());
+  }
+
+  FPRegister(const FPRegister& r) {  // NOLINT(runtime/explicit)
+    reg_code = r.reg_code;
+    reg_size = r.reg_size;
+    reg_type = r.reg_type;
+    DCHECK(IsValidOrNone());
+  }
+
+  bool IsValid() const {
+    DCHECK(IsFPRegister() || IsNone());
+    return IsValidFPRegister();
+  }
+
+  static FPRegister SRegFromCode(unsigned code);
+  static FPRegister DRegFromCode(unsigned code);
+
+  // Start of V8 compatibility section ---------------------
+  static const int kMaxNumRegisters = kNumberOfFPRegisters;
+
+  // Crankshaft can use all the FP registers except:
+  //   - d15 which is used to keep the 0 double value
+  //   - d30 which is used in crankshaft as a double scratch register
+  //   - d31 which is used in the MacroAssembler as a double scratch register
+  static const unsigned kAllocatableLowRangeBegin = 0;
+  static const unsigned kAllocatableLowRangeEnd = 14;
+  static const unsigned kAllocatableHighRangeBegin = 16;
+  static const unsigned kAllocatableHighRangeEnd = 28;
+
+  static const RegList kAllocatableFPRegisters = 0x1fff7fff;
+
+  // Gap between low and high ranges.
+  static const int kAllocatableRangeGapSize =
+      (kAllocatableHighRangeBegin - kAllocatableLowRangeEnd) - 1;
+
+  static const int kMaxNumAllocatableRegisters =
+      (kAllocatableLowRangeEnd - kAllocatableLowRangeBegin + 1) +
+      (kAllocatableHighRangeEnd - kAllocatableHighRangeBegin + 1);
+  static int NumAllocatableRegisters() { return kMaxNumAllocatableRegisters; }
+
+  // Return true if the register is one that crankshaft can allocate.
+  bool IsAllocatable() const {
+    return (Bit() & kAllocatableFPRegisters) != 0;
+  }
+
+  static FPRegister FromAllocationIndex(unsigned int index) {
+    DCHECK(index < static_cast<unsigned>(NumAllocatableRegisters()));
+
+    return (index <= kAllocatableLowRangeEnd)
+        ? from_code(index)
+        : from_code(index + kAllocatableRangeGapSize);
+  }
+
+  static const char* AllocationIndexToString(int index) {
+    DCHECK((index >= 0) && (index < NumAllocatableRegisters()));
+    DCHECK((kAllocatableLowRangeBegin == 0) &&
+           (kAllocatableLowRangeEnd == 14) &&
+           (kAllocatableHighRangeBegin == 16) &&
+           (kAllocatableHighRangeEnd == 28));
+    const char* const names[] = {
+      "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+      "d8", "d9", "d10", "d11", "d12", "d13", "d14",
+      "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+      "d24", "d25", "d26", "d27", "d28"
+    };
+    return names[index];
+  }
+
+  static int ToAllocationIndex(FPRegister reg) {
+    DCHECK(reg.IsAllocatable());
+    unsigned code = reg.code();
+
+    return (code <= kAllocatableLowRangeEnd)
+        ? code
+        : code - kAllocatableRangeGapSize;
+  }
+
+  static FPRegister from_code(int code) {
+    // Always return a D register.
+    return FPRegister::Create(code, kDRegSizeInBits);
+  }
+  // End of V8 compatibility section -----------------------
+};
+
+
+STATIC_ASSERT(sizeof(CPURegister) == sizeof(Register));
+STATIC_ASSERT(sizeof(CPURegister) == sizeof(FPRegister));
+
+
+#if defined(ARM64_DEFINE_REG_STATICS)
+#define INITIALIZE_REGISTER(register_class, name, code, size, type)      \
+  const CPURegister init_##register_class##_##name = {code, size, type}; \
+  const register_class& name = *reinterpret_cast<const register_class*>( \
+                                    &init_##register_class##_##name)
+#define ALIAS_REGISTER(register_class, alias, name)                       \
+  const register_class& alias = *reinterpret_cast<const register_class*>( \
+                                     &init_##register_class##_##name)
+#else
+#define INITIALIZE_REGISTER(register_class, name, code, size, type) \
+  extern const register_class& name
+#define ALIAS_REGISTER(register_class, alias, name) \
+  extern const register_class& alias
+#endif  // defined(ARM64_DEFINE_REG_STATICS)
+
+// No*Reg is used to indicate an unused argument, or an error case. Note that
+// these all compare equal (using the Is() method). The Register and FPRegister
+// variants are provided for convenience.
+INITIALIZE_REGISTER(Register, NoReg, 0, 0, CPURegister::kNoRegister);
+INITIALIZE_REGISTER(FPRegister, NoFPReg, 0, 0, CPURegister::kNoRegister);
+INITIALIZE_REGISTER(CPURegister, NoCPUReg, 0, 0, CPURegister::kNoRegister);
+
+// v8 compatibility.
+INITIALIZE_REGISTER(Register, no_reg, 0, 0, CPURegister::kNoRegister);
+
+#define DEFINE_REGISTERS(N)                                                  \
+  INITIALIZE_REGISTER(Register, w##N, N,                                     \
+                      kWRegSizeInBits, CPURegister::kRegister);              \
+  INITIALIZE_REGISTER(Register, x##N, N,                                     \
+                      kXRegSizeInBits, CPURegister::kRegister);
+REGISTER_CODE_LIST(DEFINE_REGISTERS)
+#undef DEFINE_REGISTERS
+
+INITIALIZE_REGISTER(Register, wcsp, kSPRegInternalCode, kWRegSizeInBits,
+                    CPURegister::kRegister);
+INITIALIZE_REGISTER(Register, csp, kSPRegInternalCode, kXRegSizeInBits,
+                    CPURegister::kRegister);
+
+#define DEFINE_FPREGISTERS(N)                                                  \
+  INITIALIZE_REGISTER(FPRegister, s##N, N,                                     \
+                      kSRegSizeInBits, CPURegister::kFPRegister);              \
+  INITIALIZE_REGISTER(FPRegister, d##N, N,                                     \
+                      kDRegSizeInBits, CPURegister::kFPRegister);
+REGISTER_CODE_LIST(DEFINE_FPREGISTERS)
+#undef DEFINE_FPREGISTERS
+
+#undef INITIALIZE_REGISTER
+
+// Registers aliases.
+ALIAS_REGISTER(Register, ip0, x16);
+ALIAS_REGISTER(Register, ip1, x17);
+ALIAS_REGISTER(Register, wip0, w16);
+ALIAS_REGISTER(Register, wip1, w17);
+// Root register.
+ALIAS_REGISTER(Register, root, x26);
+ALIAS_REGISTER(Register, rr, x26);
+// Context pointer register.
+ALIAS_REGISTER(Register, cp, x27);
+// We use a register as a JS stack pointer to overcome the restriction on the
+// architectural SP alignment.
+// We chose x28 because it is contiguous with the other specific purpose
+// registers.
+STATIC_ASSERT(kJSSPCode == 28);
+ALIAS_REGISTER(Register, jssp, x28);
+ALIAS_REGISTER(Register, wjssp, w28);
+ALIAS_REGISTER(Register, fp, x29);
+ALIAS_REGISTER(Register, lr, x30);
+ALIAS_REGISTER(Register, xzr, x31);
+ALIAS_REGISTER(Register, wzr, w31);
+
+// Keeps the 0 double value.
+ALIAS_REGISTER(FPRegister, fp_zero, d15);
+// Crankshaft double scratch register.
+ALIAS_REGISTER(FPRegister, crankshaft_fp_scratch, d29);
+// MacroAssembler double scratch registers.
+ALIAS_REGISTER(FPRegister, fp_scratch, d30);
+ALIAS_REGISTER(FPRegister, fp_scratch1, d30);
+ALIAS_REGISTER(FPRegister, fp_scratch2, d31);
+
+#undef ALIAS_REGISTER
+
+
+Register GetAllocatableRegisterThatIsNotOneOf(Register reg1,
+                                              Register reg2 = NoReg,
+                                              Register reg3 = NoReg,
+                                              Register reg4 = NoReg);
+
+
+// AreAliased returns true if any of the named registers overlap. Arguments set
+// to NoReg are ignored. The system stack pointer may be specified.
+bool AreAliased(const CPURegister& reg1,
+                const CPURegister& reg2,
+                const CPURegister& reg3 = NoReg,
+                const CPURegister& reg4 = NoReg,
+                const CPURegister& reg5 = NoReg,
+                const CPURegister& reg6 = NoReg,
+                const CPURegister& reg7 = NoReg,
+                const CPURegister& reg8 = NoReg);
+
+// AreSameSizeAndType returns true if all of the specified registers have the
+// same size, and are of the same type. The system stack pointer may be
+// specified. Arguments set to NoReg are ignored, as are any subsequent
+// arguments. At least one argument (reg1) must be valid (not NoCPUReg).
+bool AreSameSizeAndType(const CPURegister& reg1,
+                        const CPURegister& reg2,
+                        const CPURegister& reg3 = NoCPUReg,
+                        const CPURegister& reg4 = NoCPUReg,
+                        const CPURegister& reg5 = NoCPUReg,
+                        const CPURegister& reg6 = NoCPUReg,
+                        const CPURegister& reg7 = NoCPUReg,
+                        const CPURegister& reg8 = NoCPUReg);
+
+
+typedef FPRegister DoubleRegister;
+
+
+// -----------------------------------------------------------------------------
+// Lists of registers.
+class CPURegList {
+ public:
+  explicit CPURegList(CPURegister reg1,
+                      CPURegister reg2 = NoCPUReg,
+                      CPURegister reg3 = NoCPUReg,
+                      CPURegister reg4 = NoCPUReg)
+      : list_(reg1.Bit() | reg2.Bit() | reg3.Bit() | reg4.Bit()),
+        size_(reg1.SizeInBits()), type_(reg1.type()) {
+    DCHECK(AreSameSizeAndType(reg1, reg2, reg3, reg4));
+    DCHECK(IsValid());
+  }
+
+  CPURegList(CPURegister::RegisterType type, unsigned size, RegList list)
+      : list_(list), size_(size), type_(type) {
+    DCHECK(IsValid());
+  }
+
+  CPURegList(CPURegister::RegisterType type, unsigned size,
+             unsigned first_reg, unsigned last_reg)
+      : size_(size), type_(type) {
+    DCHECK(((type == CPURegister::kRegister) &&
+            (last_reg < kNumberOfRegisters)) ||
+           ((type == CPURegister::kFPRegister) &&
+            (last_reg < kNumberOfFPRegisters)));
+    DCHECK(last_reg >= first_reg);
+    list_ = (1UL << (last_reg + 1)) - 1;
+    list_ &= ~((1UL << first_reg) - 1);
+    DCHECK(IsValid());
+  }
+
+  CPURegister::RegisterType type() const {
+    DCHECK(IsValid());
+    return type_;
+  }
+
+  RegList list() const {
+    DCHECK(IsValid());
+    return list_;
+  }
+
+  inline void set_list(RegList new_list) {
+    DCHECK(IsValid());
+    list_ = new_list;
+  }
+
+  // Combine another CPURegList into this one. Registers that already exist in
+  // this list are left unchanged. The type and size of the registers in the
+  // 'other' list must match those in this list.
+  void Combine(const CPURegList& other);
+
+  // Remove every register in the other CPURegList from this one. Registers that
+  // do not exist in this list are ignored. The type of the registers in the
+  // 'other' list must match those in this list.
+  void Remove(const CPURegList& other);
+
+  // Variants of Combine and Remove which take CPURegisters.
+  void Combine(const CPURegister& other);
+  void Remove(const CPURegister& other1,
+              const CPURegister& other2 = NoCPUReg,
+              const CPURegister& other3 = NoCPUReg,
+              const CPURegister& other4 = NoCPUReg);
+
+  // Variants of Combine and Remove which take a single register by its code;
+  // the type and size of the register is inferred from this list.
+  void Combine(int code);
+  void Remove(int code);
+
+  // Remove all callee-saved registers from the list. This can be useful when
+  // preparing registers for an AAPCS64 function call, for example.
+  void RemoveCalleeSaved();
+
+  CPURegister PopLowestIndex();
+  CPURegister PopHighestIndex();
+
+  // AAPCS64 callee-saved registers.
+  static CPURegList GetCalleeSaved(unsigned size = kXRegSizeInBits);
+  static CPURegList GetCalleeSavedFP(unsigned size = kDRegSizeInBits);
+
+  // AAPCS64 caller-saved registers. Note that this includes lr.
+  static CPURegList GetCallerSaved(unsigned size = kXRegSizeInBits);
+  static CPURegList GetCallerSavedFP(unsigned size = kDRegSizeInBits);
+
+  // Registers saved as safepoints.
+  static CPURegList GetSafepointSavedRegisters();
+
+  bool IsEmpty() const {
+    DCHECK(IsValid());
+    return list_ == 0;
+  }
+
+  bool IncludesAliasOf(const CPURegister& other1,
+                       const CPURegister& other2 = NoCPUReg,
+                       const CPURegister& other3 = NoCPUReg,
+                       const CPURegister& other4 = NoCPUReg) const {
+    DCHECK(IsValid());
+    RegList list = 0;
+    if (!other1.IsNone() && (other1.type() == type_)) list |= other1.Bit();
+    if (!other2.IsNone() && (other2.type() == type_)) list |= other2.Bit();
+    if (!other3.IsNone() && (other3.type() == type_)) list |= other3.Bit();
+    if (!other4.IsNone() && (other4.type() == type_)) list |= other4.Bit();
+    return (list_ & list) != 0;
+  }
+
+  int Count() const {
+    DCHECK(IsValid());
+    return CountSetBits(list_, kRegListSizeInBits);
+  }
+
+  unsigned RegisterSizeInBits() const {
+    DCHECK(IsValid());
+    return size_;
+  }
+
+  unsigned RegisterSizeInBytes() const {
+    int size_in_bits = RegisterSizeInBits();
+    DCHECK((size_in_bits % kBitsPerByte) == 0);
+    return size_in_bits / kBitsPerByte;
+  }
+
+  unsigned TotalSizeInBytes() const {
+    DCHECK(IsValid());
+    return RegisterSizeInBytes() * Count();
+  }
+
+ private:
+  RegList list_;
+  unsigned size_;
+  CPURegister::RegisterType type_;
+
+  bool IsValid() const {
+    const RegList kValidRegisters = 0x8000000ffffffff;
+    const RegList kValidFPRegisters = 0x0000000ffffffff;
+    switch (type_) {
+      case CPURegister::kRegister:
+        return (list_ & kValidRegisters) == list_;
+      case CPURegister::kFPRegister:
+        return (list_ & kValidFPRegisters) == list_;
+      case CPURegister::kNoRegister:
+        return list_ == 0;
+      default:
+        UNREACHABLE();
+        return false;
+    }
+  }
+};
+
+
+// AAPCS64 callee-saved registers.
+#define kCalleeSaved CPURegList::GetCalleeSaved()
+#define kCalleeSavedFP CPURegList::GetCalleeSavedFP()
+
+
+// AAPCS64 caller-saved registers. Note that this includes lr.
+#define kCallerSaved CPURegList::GetCallerSaved()
+#define kCallerSavedFP CPURegList::GetCallerSavedFP()
+
+// -----------------------------------------------------------------------------
+// Immediates.
+class Immediate {
+ public:
+  template<typename T>
+  inline explicit Immediate(Handle<T> handle);
+
+  // This is allowed to be an implicit constructor because Immediate is
+  // a wrapper class that doesn't normally perform any type conversion.
+  template<typename T>
+  inline Immediate(T value);  // NOLINT(runtime/explicit)
+
+  template<typename T>
+  inline Immediate(T value, RelocInfo::Mode rmode);
+
+  int64_t value() const { return value_; }
+  RelocInfo::Mode rmode() const { return rmode_; }
+
+ private:
+  void InitializeHandle(Handle<Object> value);
+
+  int64_t value_;
+  RelocInfo::Mode rmode_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Operands.
+const int kSmiShift = kSmiTagSize + kSmiShiftSize;
+const uint64_t kSmiShiftMask = (1UL << kSmiShift) - 1;
+
+// Represents an operand in a machine instruction.
+class Operand {
+  // TODO(all): If necessary, study more in details which methods
+  // TODO(all): should be inlined or not.
+ public:
+  // rm, {<shift> {#<shift_amount>}}
+  // where <shift> is one of {LSL, LSR, ASR, ROR}.
+  //       <shift_amount> is uint6_t.
+  // This is allowed to be an implicit constructor because Operand is
+  // a wrapper class that doesn't normally perform any type conversion.
+  inline Operand(Register reg,
+                 Shift shift = LSL,
+                 unsigned shift_amount = 0);  // NOLINT(runtime/explicit)
+
+  // rm, <extend> {#<shift_amount>}
+  // where <extend> is one of {UXTB, UXTH, UXTW, UXTX, SXTB, SXTH, SXTW, SXTX}.
+  //       <shift_amount> is uint2_t.
+  inline Operand(Register reg,
+                 Extend extend,
+                 unsigned shift_amount = 0);
+
+  template<typename T>
+  inline explicit Operand(Handle<T> handle);
+
+  // Implicit constructor for all int types, ExternalReference, and Smi.
+  template<typename T>
+  inline Operand(T t);  // NOLINT(runtime/explicit)
+
+  // Implicit constructor for int types.
+  template<typename T>
+  inline Operand(T t, RelocInfo::Mode rmode);
+
+  inline bool IsImmediate() const;
+  inline bool IsShiftedRegister() const;
+  inline bool IsExtendedRegister() const;
+  inline bool IsZero() const;
+
+  // This returns an LSL shift (<= 4) operand as an equivalent extend operand,
+  // which helps in the encoding of instructions that use the stack pointer.
+  inline Operand ToExtendedRegister() const;
+
+  inline Immediate immediate() const;
+  inline int64_t ImmediateValue() const;
+  inline Register reg() const;
+  inline Shift shift() const;
+  inline Extend extend() const;
+  inline unsigned shift_amount() const;
+
+  // Relocation information.
+  bool NeedsRelocation(const Assembler* assembler) const;
+
+  // Helpers
+  inline static Operand UntagSmi(Register smi);
+  inline static Operand UntagSmiAndScale(Register smi, int scale);
+
+ private:
+  Immediate immediate_;
+  Register reg_;
+  Shift shift_;
+  Extend extend_;
+  unsigned shift_amount_;
+};
+
+
+// MemOperand represents a memory operand in a load or store instruction.
+class MemOperand {
+ public:
+  inline MemOperand();
+  inline explicit MemOperand(Register base,
+                             int64_t offset = 0,
+                             AddrMode addrmode = Offset);
+  inline explicit MemOperand(Register base,
+                             Register regoffset,
+                             Shift shift = LSL,
+                             unsigned shift_amount = 0);
+  inline explicit MemOperand(Register base,
+                             Register regoffset,
+                             Extend extend,
+                             unsigned shift_amount = 0);
+  inline explicit MemOperand(Register base,
+                             const Operand& offset,
+                             AddrMode addrmode = Offset);
+
+  const Register& base() const { return base_; }
+  const Register& regoffset() const { return regoffset_; }
+  int64_t offset() const { return offset_; }
+  AddrMode addrmode() const { return addrmode_; }
+  Shift shift() const { return shift_; }
+  Extend extend() const { return extend_; }
+  unsigned shift_amount() const { return shift_amount_; }
+  inline bool IsImmediateOffset() const;
+  inline bool IsRegisterOffset() const;
+  inline bool IsPreIndex() const;
+  inline bool IsPostIndex() const;
+
+  // For offset modes, return the offset as an Operand. This helper cannot
+  // handle indexed modes.
+  inline Operand OffsetAsOperand() const;
+
+  enum PairResult {
+    kNotPair,   // Can't use a pair instruction.
+    kPairAB,    // Can use a pair instruction (operandA has lower address).
+    kPairBA     // Can use a pair instruction (operandB has lower address).
+  };
+  // Check if two MemOperand are consistent for stp/ldp use.
+  static PairResult AreConsistentForPair(const MemOperand& operandA,
+                                         const MemOperand& operandB,
+                                         int access_size_log2 = kXRegSizeLog2);
+
+ private:
+  Register base_;
+  Register regoffset_;
+  int64_t offset_;
+  AddrMode addrmode_;
+  Shift shift_;
+  Extend extend_;
+  unsigned shift_amount_;
+};
+
+
+class ConstPool {
+ public:
+  explicit ConstPool(Assembler* assm)
+      : assm_(assm),
+        first_use_(-1),
+        shared_entries_count(0) {}
+  void RecordEntry(intptr_t data, RelocInfo::Mode mode);
+  int EntryCount() const {
+    return shared_entries_count + unique_entries_.size();
+  }
+  bool IsEmpty() const {
+    return shared_entries_.empty() && unique_entries_.empty();
+  }
+  // Distance in bytes between the current pc and the first instruction
+  // using the pool. If there are no pending entries return kMaxInt.
+  int DistanceToFirstUse();
+  // Offset after which instructions using the pool will be out of range.
+  int MaxPcOffset();
+  // Maximum size the constant pool can be with current entries. It always
+  // includes alignment padding and branch over.
+  int WorstCaseSize();
+  // Size in bytes of the literal pool *if* it is emitted at the current
+  // pc. The size will include the branch over the pool if it was requested.
+  int SizeIfEmittedAtCurrentPc(bool require_jump);
+  // Emit the literal pool at the current pc with a branch over the pool if
+  // requested.
+  void Emit(bool require_jump);
+  // Discard any pending pool entries.
+  void Clear();
+
+ private:
+  bool CanBeShared(RelocInfo::Mode mode);
+  void EmitMarker();
+  void EmitGuard();
+  void EmitEntries();
+
+  Assembler* assm_;
+  // Keep track of the first instruction requiring a constant pool entry
+  // since the previous constant pool was emitted.
+  int first_use_;
+  // values, pc offset(s) of entries which can be shared.
+  std::multimap<uint64_t, int> shared_entries_;
+  // Number of distinct literal in shared entries.
+  int shared_entries_count;
+  // values, pc offset of entries which cannot be shared.
+  std::vector<std::pair<uint64_t, int> > unique_entries_;
+};
+
+
+// -----------------------------------------------------------------------------
+// Assembler.
+
+class Assembler : public AssemblerBase {
+ public:
+  // Create an assembler. Instructions and relocation information are emitted
+  // into a buffer, with the instructions starting from the beginning and the
+  // relocation information starting from the end of the buffer. See CodeDesc
+  // for a detailed comment on the layout (globals.h).
+  //
+  // If the provided buffer is NULL, the assembler allocates and grows its own
+  // buffer, and buffer_size determines the initial buffer size. The buffer is
+  // owned by the assembler and deallocated upon destruction of the assembler.
+  //
+  // If the provided buffer is not NULL, the assembler uses the provided buffer
+  // for code generation and assumes its size to be buffer_size. If the buffer
+  // is too small, a fatal error occurs. No deallocation of the buffer is done
+  // upon destruction of the assembler.
+  Assembler(Isolate* arg_isolate, void* buffer, int buffer_size);
+
+  virtual ~Assembler();
+
+  virtual void AbortedCodeGeneration() {
+    constpool_.Clear();
+  }
+
+  // System functions ---------------------------------------------------------
+  // Start generating code from the beginning of the buffer, discarding any code
+  // and data that has already been emitted into the buffer.
+  //
+  // In order to avoid any accidental transfer of state, Reset DCHECKs that the
+  // constant pool is not blocked.
+  void Reset();
+
+  // GetCode emits any pending (non-emitted) code and fills the descriptor
+  // desc. GetCode() is idempotent; it returns the same result if no other
+  // Assembler functions are invoked in between GetCode() calls.
+  //
+  // The descriptor (desc) can be NULL. In that case, the code is finalized as
+  // usual, but the descriptor is not populated.
+  void GetCode(CodeDesc* desc);
+
+  // Insert the smallest number of nop instructions
+  // possible to align the pc offset to a multiple
+  // of m. m must be a power of 2 (>= 4).
+  void Align(int m);
+
+  inline void Unreachable();
+
+  // Label --------------------------------------------------------------------
+  // Bind a label to the current pc. Note that labels can only be bound once,
+  // and if labels are linked to other instructions, they _must_ be bound
+  // before they go out of scope.
+  void bind(Label* label);
+
+
+  // RelocInfo and pools ------------------------------------------------------
+
+  // Record relocation information for current pc_.
+  void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
+
+  // Return the address in the constant pool of the code target address used by
+  // the branch/call instruction at pc.
+  inline static Address target_pointer_address_at(Address pc);
+
+  // Read/Modify the code target address in the branch/call instruction at pc.
+  inline static Address target_address_at(Address pc,
+                                          ConstantPoolArray* constant_pool);
+  inline static void set_target_address_at(Address pc,
+                                           ConstantPoolArray* constant_pool,
+                                           Address target,
+                                           ICacheFlushMode icache_flush_mode =
+                                               FLUSH_ICACHE_IF_NEEDED);
+  static inline Address target_address_at(Address pc, Code* code);
+  static inline void set_target_address_at(Address pc,
+                                           Code* code,
+                                           Address target,
+                                           ICacheFlushMode icache_flush_mode =
+                                               FLUSH_ICACHE_IF_NEEDED);
+
+  // Return the code target address at a call site from the return address of
+  // that call in the instruction stream.
+  inline static Address target_address_from_return_address(Address pc);
+
+  // Given the address of the beginning of a call, return the address in the
+  // instruction stream that call will return from.
+  inline static Address return_address_from_call_start(Address pc);
+
+  // Return the code target address of the patch debug break slot
+  inline static Address break_address_from_return_address(Address pc);
+
+  // This sets the branch destination (which is in the constant pool on ARM).
+  // This is for calls and branches within generated code.
+  inline static void deserialization_set_special_target_at(
+      Address constant_pool_entry, Code* code, Address target);
+
+  // All addresses in the constant pool are the same size as pointers.
+  static const int kSpecialTargetSize = kPointerSize;
+
+  // The sizes of the call sequences emitted by MacroAssembler::Call.
+  // Wherever possible, use MacroAssembler::CallSize instead of these constants,
+  // as it will choose the correct value for a given relocation mode.
+  //
+  // Without relocation:
+  //  movz  temp, #(target & 0x000000000000ffff)
+  //  movk  temp, #(target & 0x00000000ffff0000)
+  //  movk  temp, #(target & 0x0000ffff00000000)
+  //  blr   temp
+  //
+  // With relocation:
+  //  ldr   temp, =target
+  //  blr   temp
+  static const int kCallSizeWithoutRelocation = 4 * kInstructionSize;
+  static const int kCallSizeWithRelocation = 2 * kInstructionSize;
+
+  // Size of the generated code in bytes
+  uint64_t SizeOfGeneratedCode() const {
+    DCHECK((pc_ >= buffer_) && (pc_ < (buffer_ + buffer_size_)));
+    return pc_ - buffer_;
+  }
+
+  // Return the code size generated from label to the current position.
+  uint64_t SizeOfCodeGeneratedSince(const Label* label) {
+    DCHECK(label->is_bound());
+    DCHECK(pc_offset() >= label->pos());
+    DCHECK(pc_offset() < buffer_size_);
+    return pc_offset() - label->pos();
+  }
+
+  // Check the size of the code generated since the given label. This function
+  // is used primarily to work around comparisons between signed and unsigned
+  // quantities, since V8 uses both.
+  // TODO(jbramley): Work out what sign to use for these things and if possible,
+  // change things to be consistent.
+  void AssertSizeOfCodeGeneratedSince(const Label* label, ptrdiff_t size) {
+    DCHECK(size >= 0);
+    DCHECK(static_cast<uint64_t>(size) == SizeOfCodeGeneratedSince(label));
+  }
+
+  // Return the number of instructions generated from label to the
+  // current position.
+  int InstructionsGeneratedSince(const Label* label) {
+    return SizeOfCodeGeneratedSince(label) / kInstructionSize;
+  }
+
+  // Number of instructions generated for the return sequence in
+  // FullCodeGenerator::EmitReturnSequence.
+  static const int kJSRetSequenceInstructions = 7;
+  // Distance between start of patched return sequence and the emitted address
+  // to jump to.
+  static const int kPatchReturnSequenceAddressOffset =  0;
+  static const int kPatchDebugBreakSlotAddressOffset =  0;
+
+  // Number of instructions necessary to be able to later patch it to a call.
+  // See DebugCodegen::GenerateSlot() and
+  // BreakLocationIterator::SetDebugBreakAtSlot().
+  static const int kDebugBreakSlotInstructions = 4;
+  static const int kDebugBreakSlotLength =
+    kDebugBreakSlotInstructions * kInstructionSize;
+
+  static const int kPatchDebugBreakSlotReturnOffset = 2 * kInstructionSize;
+
+  // Prevent contant pool emission until EndBlockConstPool is called.
+  // Call to this function can be nested but must be followed by an equal
+  // number of call to EndBlockConstpool.
+  void StartBlockConstPool();
+
+  // Resume constant pool emission. Need to be called as many time as
+  // StartBlockConstPool to have an effect.
+  void EndBlockConstPool();
+
+  bool is_const_pool_blocked() const;
+  static bool IsConstantPoolAt(Instruction* instr);
+  static int ConstantPoolSizeAt(Instruction* instr);
+  // See Assembler::CheckConstPool for more info.
+  void EmitPoolGuard();
+
+  // Prevent veneer pool emission until EndBlockVeneerPool is called.
+  // Call to this function can be nested but must be followed by an equal
+  // number of call to EndBlockConstpool.
+  void StartBlockVeneerPool();
+
+  // Resume constant pool emission. Need to be called as many time as
+  // StartBlockVeneerPool to have an effect.
+  void EndBlockVeneerPool();
+
+  bool is_veneer_pool_blocked() const {
+    return veneer_pool_blocked_nesting_ > 0;
+  }
+
+  // Block/resume emission of constant pools and veneer pools.
+  void StartBlockPools() {
+    StartBlockConstPool();
+    StartBlockVeneerPool();
+  }
+  void EndBlockPools() {
+    EndBlockConstPool();
+    EndBlockVeneerPool();
+  }
+
+  // Debugging ----------------------------------------------------------------
+  PositionsRecorder* positions_recorder() { return &positions_recorder_; }
+  void RecordComment(const char* msg);
+  int buffer_space() const;
+
+  // Mark address of the ExitJSFrame code.
+  void RecordJSReturn();
+
+  // Mark address of a debug break slot.
+  void RecordDebugBreakSlot();
+
+  // Record the emission of a constant pool.
+  //
+  // The emission of constant and veneer pools depends on the size of the code
+  // generated and the number of RelocInfo recorded.
+  // The Debug mechanism needs to map code offsets between two versions of a
+  // function, compiled with and without debugger support (see for example
+  // Debug::PrepareForBreakPoints()).
+  // Compiling functions with debugger support generates additional code
+  // (DebugCodegen::GenerateSlot()). This may affect the emission of the pools
+  // and cause the version of the code with debugger support to have pools
+  // generated in different places.
+  // Recording the position and size of emitted pools allows to correctly
+  // compute the offset mappings between the different versions of a function in
+  // all situations.
+  //
+  // The parameter indicates the size of the pool (in bytes), including
+  // the marker and branch over the data.
+  void RecordConstPool(int size);
+
+
+  // Instruction set functions ------------------------------------------------
+
+  // Branch / Jump instructions.
+  // For branches offsets are scaled, i.e. they in instrcutions not in bytes.
+  // Branch to register.
+  void br(const Register& xn);
+
+  // Branch-link to register.
+  void blr(const Register& xn);
+
+  // Branch to register with return hint.
+  void ret(const Register& xn = lr);
+
+  // Unconditional branch to label.
+  void b(Label* label);
+
+  // Conditional branch to label.
+  void b(Label* label, Condition cond);
+
+  // Unconditional branch to PC offset.
+  void b(int imm26);
+
+  // Conditional branch to PC offset.
+  void b(int imm19, Condition cond);
+
+  // Branch-link to label / pc offset.
+  void bl(Label* label);
+  void bl(int imm26);
+
+  // Compare and branch to label / pc offset if zero.
+  void cbz(const Register& rt, Label* label);
+  void cbz(const Register& rt, int imm19);
+
+  // Compare and branch to label / pc offset if not zero.
+  void cbnz(const Register& rt, Label* label);
+  void cbnz(const Register& rt, int imm19);
+
+  // Test bit and branch to label / pc offset if zero.
+  void tbz(const Register& rt, unsigned bit_pos, Label* label);
+  void tbz(const Register& rt, unsigned bit_pos, int imm14);
+
+  // Test bit and branch to label / pc offset if not zero.
+  void tbnz(const Register& rt, unsigned bit_pos, Label* label);
+  void tbnz(const Register& rt, unsigned bit_pos, int imm14);
+
+  // Address calculation instructions.
+  // Calculate a PC-relative address. Unlike for branches the offset in adr is
+  // unscaled (i.e. the result can be unaligned).
+  void adr(const Register& rd, Label* label);
+  void adr(const Register& rd, int imm21);
+
+  // Data Processing instructions.
+  // Add.
+  void add(const Register& rd,
+           const Register& rn,
+           const Operand& operand);
+
+  // Add and update status flags.
+  void adds(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Compare negative.
+  void cmn(const Register& rn, const Operand& operand);
+
+  // Subtract.
+  void sub(const Register& rd,
+           const Register& rn,
+           const Operand& operand);
+
+  // Subtract and update status flags.
+  void subs(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Compare.
+  void cmp(const Register& rn, const Operand& operand);
+
+  // Negate.
+  void neg(const Register& rd,
+           const Operand& operand);
+
+  // Negate and update status flags.
+  void negs(const Register& rd,
+            const Operand& operand);
+
+  // Add with carry bit.
+  void adc(const Register& rd,
+           const Register& rn,
+           const Operand& operand);
+
+  // Add with carry bit and update status flags.
+  void adcs(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Subtract with carry bit.
+  void sbc(const Register& rd,
+           const Register& rn,
+           const Operand& operand);
+
+  // Subtract with carry bit and update status flags.
+  void sbcs(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Negate with carry bit.
+  void ngc(const Register& rd,
+           const Operand& operand);
+
+  // Negate with carry bit and update status flags.
+  void ngcs(const Register& rd,
+            const Operand& operand);
+
+  // Logical instructions.
+  // Bitwise and (A & B).
+  void and_(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Bitwise and (A & B) and update status flags.
+  void ands(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Bit test, and set flags.
+  void tst(const Register& rn, const Operand& operand);
+
+  // Bit clear (A & ~B).
+  void bic(const Register& rd,
+           const Register& rn,
+           const Operand& operand);
+
+  // Bit clear (A & ~B) and update status flags.
+  void bics(const Register& rd,
+            const Register& rn,
+            const Operand& operand);
+
+  // Bitwise or (A | B).
+  void orr(const Register& rd, const Register& rn, const Operand& operand);
+
+  // Bitwise nor (A | ~B).
+  void orn(const Register& rd, const Register& rn, const Operand& operand);
+
+  // Bitwise eor/xor (A ^ B).
+  void eor(const Register& rd, const Register& rn, const Operand& operand);
+
+  // Bitwise enor/xnor (A ^ ~B).
+  void eon(const Register& rd, const Register& rn, const Operand& operand);
+
+  // Logical shift left variable.
+  void lslv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Logical shift right variable.
+  void lsrv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Arithmetic shift right variable.
+  void asrv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Rotate right variable.
+  void rorv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Bitfield instructions.
+  // Bitfield move.
+  void bfm(const Register& rd,
+           const Register& rn,
+           unsigned immr,
+           unsigned imms);
+
+  // Signed bitfield move.
+  void sbfm(const Register& rd,
+            const Register& rn,
+            unsigned immr,
+            unsigned imms);
+
+  // Unsigned bitfield move.
+  void ubfm(const Register& rd,
+            const Register& rn,
+            unsigned immr,
+            unsigned imms);
+
+  // Bfm aliases.
+  // Bitfield insert.
+  void bfi(const Register& rd,
+           const Register& rn,
+           unsigned lsb,
+           unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    bfm(rd, rn, (rd.SizeInBits() - lsb) & (rd.SizeInBits() - 1), width - 1);
+  }
+
+  // Bitfield extract and insert low.
+  void bfxil(const Register& rd,
+             const Register& rn,
+             unsigned lsb,
+             unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    bfm(rd, rn, lsb, lsb + width - 1);
+  }
+
+  // Sbfm aliases.
+  // Arithmetic shift right.
+  void asr(const Register& rd, const Register& rn, unsigned shift) {
+    DCHECK(shift < rd.SizeInBits());
+    sbfm(rd, rn, shift, rd.SizeInBits() - 1);
+  }
+
+  // Signed bitfield insert in zero.
+  void sbfiz(const Register& rd,
+             const Register& rn,
+             unsigned lsb,
+             unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    sbfm(rd, rn, (rd.SizeInBits() - lsb) & (rd.SizeInBits() - 1), width - 1);
+  }
+
+  // Signed bitfield extract.
+  void sbfx(const Register& rd,
+            const Register& rn,
+            unsigned lsb,
+            unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    sbfm(rd, rn, lsb, lsb + width - 1);
+  }
+
+  // Signed extend byte.
+  void sxtb(const Register& rd, const Register& rn) {
+    sbfm(rd, rn, 0, 7);
+  }
+
+  // Signed extend halfword.
+  void sxth(const Register& rd, const Register& rn) {
+    sbfm(rd, rn, 0, 15);
+  }
+
+  // Signed extend word.
+  void sxtw(const Register& rd, const Register& rn) {
+    sbfm(rd, rn, 0, 31);
+  }
+
+  // Ubfm aliases.
+  // Logical shift left.
+  void lsl(const Register& rd, const Register& rn, unsigned shift) {
+    unsigned reg_size = rd.SizeInBits();
+    DCHECK(shift < reg_size);
+    ubfm(rd, rn, (reg_size - shift) % reg_size, reg_size - shift - 1);
+  }
+
+  // Logical shift right.
+  void lsr(const Register& rd, const Register& rn, unsigned shift) {
+    DCHECK(shift < rd.SizeInBits());
+    ubfm(rd, rn, shift, rd.SizeInBits() - 1);
+  }
+
+  // Unsigned bitfield insert in zero.
+  void ubfiz(const Register& rd,
+             const Register& rn,
+             unsigned lsb,
+             unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    ubfm(rd, rn, (rd.SizeInBits() - lsb) & (rd.SizeInBits() - 1), width - 1);
+  }
+
+  // Unsigned bitfield extract.
+  void ubfx(const Register& rd,
+            const Register& rn,
+            unsigned lsb,
+            unsigned width) {
+    DCHECK(width >= 1);
+    DCHECK(lsb + width <= rn.SizeInBits());
+    ubfm(rd, rn, lsb, lsb + width - 1);
+  }
+
+  // Unsigned extend byte.
+  void uxtb(const Register& rd, const Register& rn) {
+    ubfm(rd, rn, 0, 7);
+  }
+
+  // Unsigned extend halfword.
+  void uxth(const Register& rd, const Register& rn) {
+    ubfm(rd, rn, 0, 15);
+  }
+
+  // Unsigned extend word.
+  void uxtw(const Register& rd, const Register& rn) {
+    ubfm(rd, rn, 0, 31);
+  }
+
+  // Extract.
+  void extr(const Register& rd,
+            const Register& rn,
+            const Register& rm,
+            unsigned lsb);
+
+  // Conditional select: rd = cond ? rn : rm.
+  void csel(const Register& rd,
+            const Register& rn,
+            const Register& rm,
+            Condition cond);
+
+  // Conditional select increment: rd = cond ? rn : rm + 1.
+  void csinc(const Register& rd,
+             const Register& rn,
+             const Register& rm,
+             Condition cond);
+
+  // Conditional select inversion: rd = cond ? rn : ~rm.
+  void csinv(const Register& rd,
+             const Register& rn,
+             const Register& rm,
+             Condition cond);
+
+  // Conditional select negation: rd = cond ? rn : -rm.
+  void csneg(const Register& rd,
+             const Register& rn,
+             const Register& rm,
+             Condition cond);
+
+  // Conditional set: rd = cond ? 1 : 0.
+  void cset(const Register& rd, Condition cond);
+
+  // Conditional set minus: rd = cond ? -1 : 0.
+  void csetm(const Register& rd, Condition cond);
+
+  // Conditional increment: rd = cond ? rn + 1 : rn.
+  void cinc(const Register& rd, const Register& rn, Condition cond);
+
+  // Conditional invert: rd = cond ? ~rn : rn.
+  void cinv(const Register& rd, const Register& rn, Condition cond);
+
+  // Conditional negate: rd = cond ? -rn : rn.
+  void cneg(const Register& rd, const Register& rn, Condition cond);
+
+  // Extr aliases.
+  void ror(const Register& rd, const Register& rs, unsigned shift) {
+    extr(rd, rs, rs, shift);
+  }
+
+  // Conditional comparison.
+  // Conditional compare negative.
+  void ccmn(const Register& rn,
+            const Operand& operand,
+            StatusFlags nzcv,
+            Condition cond);
+
+  // Conditional compare.
+  void ccmp(const Register& rn,
+            const Operand& operand,
+            StatusFlags nzcv,
+            Condition cond);
+
+  // Multiplication.
+  // 32 x 32 -> 32-bit and 64 x 64 -> 64-bit multiply.
+  void mul(const Register& rd, const Register& rn, const Register& rm);
+
+  // 32 + 32 x 32 -> 32-bit and 64 + 64 x 64 -> 64-bit multiply accumulate.
+  void madd(const Register& rd,
+            const Register& rn,
+            const Register& rm,
+            const Register& ra);
+
+  // -(32 x 32) -> 32-bit and -(64 x 64) -> 64-bit multiply.
+  void mneg(const Register& rd, const Register& rn, const Register& rm);
+
+  // 32 - 32 x 32 -> 32-bit and 64 - 64 x 64 -> 64-bit multiply subtract.
+  void msub(const Register& rd,
+            const Register& rn,
+            const Register& rm,
+            const Register& ra);
+
+  // 32 x 32 -> 64-bit multiply.
+  void smull(const Register& rd, const Register& rn, const Register& rm);
+
+  // Xd = bits<127:64> of Xn * Xm.
+  void smulh(const Register& rd, const Register& rn, const Register& rm);
+
+  // Signed 32 x 32 -> 64-bit multiply and accumulate.
+  void smaddl(const Register& rd,
+              const Register& rn,
+              const Register& rm,
+              const Register& ra);
+
+  // Unsigned 32 x 32 -> 64-bit multiply and accumulate.
+  void umaddl(const Register& rd,
+              const Register& rn,
+              const Register& rm,
+              const Register& ra);
+
+  // Signed 32 x 32 -> 64-bit multiply and subtract.
+  void smsubl(const Register& rd,
+              const Register& rn,
+              const Register& rm,
+              const Register& ra);
+
+  // Unsigned 32 x 32 -> 64-bit multiply and subtract.
+  void umsubl(const Register& rd,
+              const Register& rn,
+              const Register& rm,
+              const Register& ra);
+
+  // Signed integer divide.
+  void sdiv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Unsigned integer divide.
+  void udiv(const Register& rd, const Register& rn, const Register& rm);
+
+  // Bit count, bit reverse and endian reverse.
+  void rbit(const Register& rd, const Register& rn);
+  void rev16(const Register& rd, const Register& rn);
+  void rev32(const Register& rd, const Register& rn);
+  void rev(const Register& rd, const Register& rn);
+  void clz(const Register& rd, const Register& rn);
+  void cls(const Register& rd, const Register& rn);
+
+  // Memory instructions.
+
+  // Load integer or FP register.
+  void ldr(const CPURegister& rt, const MemOperand& src);
+
+  // Store integer or FP register.
+  void str(const CPURegister& rt, const MemOperand& dst);
+
+  // Load word with sign extension.
+  void ldrsw(const Register& rt, const MemOperand& src);
+
+  // Load byte.
+  void ldrb(const Register& rt, const MemOperand& src);
+
+  // Store byte.
+  void strb(const Register& rt, const MemOperand& dst);
+
+  // Load byte with sign extension.
+  void ldrsb(const Register& rt, const MemOperand& src);
+
+  // Load half-word.
+  void ldrh(const Register& rt, const MemOperand& src);
+
+  // Store half-word.
+  void strh(const Register& rt, const MemOperand& dst);
+
+  // Load half-word with sign extension.
+  void ldrsh(const Register& rt, const MemOperand& src);
+
+  // Load integer or FP register pair.
+  void ldp(const CPURegister& rt, const CPURegister& rt2,
+           const MemOperand& src);
+
+  // Store integer or FP register pair.
+  void stp(const CPURegister& rt, const CPURegister& rt2,
+           const MemOperand& dst);
+
+  // Load word pair with sign extension.
+  void ldpsw(const Register& rt, const Register& rt2, const MemOperand& src);
+
+  // Load integer or FP register pair, non-temporal.
+  void ldnp(const CPURegister& rt, const CPURegister& rt2,
+            const MemOperand& src);
+
+  // Store integer or FP register pair, non-temporal.
+  void stnp(const CPURegister& rt, const CPURegister& rt2,
+            const MemOperand& dst);
+
+  // Load literal to register from a pc relative address.
+  void ldr_pcrel(const CPURegister& rt, int imm19);
+
+  // Load literal to register.
+  void ldr(const CPURegister& rt, const Immediate& imm);
+
+  // Move instructions. The default shift of -1 indicates that the move
+  // instruction will calculate an appropriate 16-bit immediate and left shift
+  // that is equal to the 64-bit immediate argument. If an explicit left shift
+  // is specified (0, 16, 32 or 48), the immediate must be a 16-bit value.
+  //
+  // For movk, an explicit shift can be used to indicate which half word should
+  // be overwritten, eg. movk(x0, 0, 0) will overwrite the least-significant
+  // half word with zero, whereas movk(x0, 0, 48) will overwrite the
+  // most-significant.
+
+  // Move and keep.
+  void movk(const Register& rd, uint64_t imm, int shift = -1) {
+    MoveWide(rd, imm, shift, MOVK);
+  }
+
+  // Move with non-zero.
+  void movn(const Register& rd, uint64_t imm, int shift = -1) {
+    MoveWide(rd, imm, shift, MOVN);
+  }
+
+  // Move with zero.
+  void movz(const Register& rd, uint64_t imm, int shift = -1) {
+    MoveWide(rd, imm, shift, MOVZ);
+  }
+
+  // Misc instructions.
+  // Monitor debug-mode breakpoint.
+  void brk(int code);
+
+  // Halting debug-mode breakpoint.
+  void hlt(int code);
+
+  // Move register to register.
+  void mov(const Register& rd, const Register& rn);
+
+  // Move NOT(operand) to register.
+  void mvn(const Register& rd, const Operand& operand);
+
+  // System instructions.
+  // Move to register from system register.
+  void mrs(const Register& rt, SystemRegister sysreg);
+
+  // Move from register to system register.
+  void msr(SystemRegister sysreg, const Register& rt);
+
+  // System hint.
+  void hint(SystemHint code);
+
+  // Data memory barrier
+  void dmb(BarrierDomain domain, BarrierType type);
+
+  // Data synchronization barrier
+  void dsb(BarrierDomain domain, BarrierType type);
+
+  // Instruction synchronization barrier
+  void isb();
+
+  // Alias for system instructions.
+  void nop() { hint(NOP); }
+
+  // Different nop operations are used by the code generator to detect certain
+  // states of the generated code.
+  enum NopMarkerTypes {
+    DEBUG_BREAK_NOP,
+    INTERRUPT_CODE_NOP,
+    ADR_FAR_NOP,
+    FIRST_NOP_MARKER = DEBUG_BREAK_NOP,
+    LAST_NOP_MARKER = ADR_FAR_NOP
+  };
+
+  void nop(NopMarkerTypes n) {
+    DCHECK((FIRST_NOP_MARKER <= n) && (n <= LAST_NOP_MARKER));
+    mov(Register::XRegFromCode(n), Register::XRegFromCode(n));
+  }
+
+  // FP instructions.
+  // Move immediate to FP register.
+  void fmov(FPRegister fd, double imm);
+  void fmov(FPRegister fd, float imm);
+
+  // Move FP register to register.
+  void fmov(Register rd, FPRegister fn);
+
+  // Move register to FP register.
+  void fmov(FPRegister fd, Register rn);
+
+  // Move FP register to FP register.
+  void fmov(FPRegister fd, FPRegister fn);
+
+  // FP add.
+  void fadd(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP subtract.
+  void fsub(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP multiply.
+  void fmul(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP fused multiply and add.
+  void fmadd(const FPRegister& fd,
+             const FPRegister& fn,
+             const FPRegister& fm,
+             const FPRegister& fa);
+
+  // FP fused multiply and subtract.
+  void fmsub(const FPRegister& fd,
+             const FPRegister& fn,
+             const FPRegister& fm,
+             const FPRegister& fa);
+
+  // FP fused multiply, add and negate.
+  void fnmadd(const FPRegister& fd,
+              const FPRegister& fn,
+              const FPRegister& fm,
+              const FPRegister& fa);
+
+  // FP fused multiply, subtract and negate.
+  void fnmsub(const FPRegister& fd,
+              const FPRegister& fn,
+              const FPRegister& fm,
+              const FPRegister& fa);
+
+  // FP divide.
+  void fdiv(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP maximum.
+  void fmax(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP minimum.
+  void fmin(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP maximum.
+  void fmaxnm(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP minimum.
+  void fminnm(const FPRegister& fd, const FPRegister& fn, const FPRegister& fm);
+
+  // FP absolute.
+  void fabs(const FPRegister& fd, const FPRegister& fn);
+
+  // FP negate.
+  void fneg(const FPRegister& fd, const FPRegister& fn);
+
+  // FP square root.
+  void fsqrt(const FPRegister& fd, const FPRegister& fn);
+
+  // FP round to integer (nearest with ties to away).
+  void frinta(const FPRegister& fd, const FPRegister& fn);
+
+  // FP round to integer (toward minus infinity).
+  void frintm(const FPRegister& fd, const FPRegister& fn);
+
+  // FP round to integer (nearest with ties to even).
+  void frintn(const FPRegister& fd, const FPRegister& fn);
+
+  // FP round to integer (towards zero.)
+  void frintz(const FPRegister& fd, const FPRegister& fn);
+
+  // FP compare registers.
+  void fcmp(const FPRegister& fn, const FPRegister& fm);
+
+  // FP compare immediate.
+  void fcmp(const FPRegister& fn, double value);
+
+  // FP conditional compare.
+  void fccmp(const FPRegister& fn,
+             const FPRegister& fm,
+             StatusFlags nzcv,
+             Condition cond);
+
+  // FP conditional select.
+  void fcsel(const FPRegister& fd,
+             const FPRegister& fn,
+             const FPRegister& fm,
+             Condition cond);
+
+  // Common FP Convert function
+  void FPConvertToInt(const Register& rd,
+                      const FPRegister& fn,
+                      FPIntegerConvertOp op);
+
+  // FP convert between single and double precision.
+  void fcvt(const FPRegister& fd, const FPRegister& fn);
+
+  // Convert FP to unsigned integer (nearest with ties to away).
+  void fcvtau(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to signed integer (nearest with ties to away).
+  void fcvtas(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to unsigned integer (round towards -infinity).
+  void fcvtmu(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to signed integer (round towards -infinity).
+  void fcvtms(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to unsigned integer (nearest with ties to even).
+  void fcvtnu(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to signed integer (nearest with ties to even).
+  void fcvtns(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to unsigned integer (round towards zero).
+  void fcvtzu(const Register& rd, const FPRegister& fn);
+
+  // Convert FP to signed integer (rounf towards zero).
+  void fcvtzs(const Register& rd, const FPRegister& fn);
+
+  // Convert signed integer or fixed point to FP.
+  void scvtf(const FPRegister& fd, const Register& rn, unsigned fbits = 0);
+
+  // Convert unsigned integer or fixed point to FP.
+  void ucvtf(const FPRegister& fd, const Register& rn, unsigned fbits = 0);
+
+  // Instruction functions used only for test, debug, and patching.
+  // Emit raw instructions in the instruction stream.
+  void dci(Instr raw_inst) { Emit(raw_inst); }
+
+  // Emit 8 bits of data in the instruction stream.
+  void dc8(uint8_t data) { EmitData(&data, sizeof(data)); }
+
+  // Emit 32 bits of data in the instruction stream.
+  void dc32(uint32_t data) { EmitData(&data, sizeof(data)); }
+
+  // Emit 64 bits of data in the instruction stream.
+  void dc64(uint64_t data) { EmitData(&data, sizeof(data)); }
+
+  // Copy a string into the instruction stream, including the terminating NULL
+  // character. The instruction pointer (pc_) is then aligned correctly for
+  // subsequent instructions.
+  void EmitStringData(const char* string);
+
+  // Pseudo-instructions ------------------------------------------------------
+
+  // Parameters are described in arm64/instructions-arm64.h.
+  void debug(const char* message, uint32_t code, Instr params = BREAK);
+
+  // Required by V8.
+  void dd(uint32_t data) { dc32(data); }
+  void db(uint8_t data) { dc8(data); }
+
+  // Code generation helpers --------------------------------------------------
+
+  bool IsConstPoolEmpty() const { return constpool_.IsEmpty(); }
+
+  Instruction* pc() const { return Instruction::Cast(pc_); }
+
+  Instruction* InstructionAt(int offset) const {
+    return reinterpret_cast<Instruction*>(buffer_ + offset);
+  }
+
+  ptrdiff_t InstructionOffset(Instruction* instr) const {
+    return reinterpret_cast<byte*>(instr) - buffer_;
+  }
+
+  // Register encoding.
+  static Instr Rd(CPURegister rd) {
+    DCHECK(rd.code() != kSPRegInternalCode);
+    return rd.code() << Rd_offset;
+  }
+
+  static Instr Rn(CPURegister rn) {
+    DCHECK(rn.code() != kSPRegInternalCode);
+    return rn.code() << Rn_offset;
+  }
+
+  static Instr Rm(CPURegister rm) {
+    DCHECK(rm.code() != kSPRegInternalCode);
+    return rm.code() << Rm_offset;
+  }
+
+  static Instr Ra(CPURegister ra) {
+    DCHECK(ra.code() != kSPRegInternalCode);
+    return ra.code() << Ra_offset;
+  }
+
+  static Instr Rt(CPURegister rt) {
+    DCHECK(rt.code() != kSPRegInternalCode);
+    return rt.code() << Rt_offset;
+  }
+
+  static Instr Rt2(CPURegister rt2) {
+    DCHECK(rt2.code() != kSPRegInternalCode);
+    return rt2.code() << Rt2_offset;
+  }
+
+  // These encoding functions allow the stack pointer to be encoded, and
+  // disallow the zero register.
+  static Instr RdSP(Register rd) {
+    DCHECK(!rd.IsZero());
+    return (rd.code() & kRegCodeMask) << Rd_offset;
+  }
+
+  static Instr RnSP(Register rn) {
+    DCHECK(!rn.IsZero());
+    return (rn.code() & kRegCodeMask) << Rn_offset;
+  }
+
+  // Flags encoding.
+  inline static Instr Flags(FlagsUpdate S);
+  inline static Instr Cond(Condition cond);
+
+  // PC-relative address encoding.
+  inline static Instr ImmPCRelAddress(int imm21);
+
+  // Branch encoding.
+  inline static Instr ImmUncondBranch(int imm26);
+  inline static Instr ImmCondBranch(int imm19);
+  inline static Instr ImmCmpBranch(int imm19);
+  inline static Instr ImmTestBranch(int imm14);
+  inline static Instr ImmTestBranchBit(unsigned bit_pos);
+
+  // Data Processing encoding.
+  inline static Instr SF(Register rd);
+  inline static Instr ImmAddSub(int64_t imm);
+  inline static Instr ImmS(unsigned imms, unsigned reg_size);
+  inline static Instr ImmR(unsigned immr, unsigned reg_size);
+  inline static Instr ImmSetBits(unsigned imms, unsigned reg_size);
+  inline static Instr ImmRotate(unsigned immr, unsigned reg_size);
+  inline static Instr ImmLLiteral(int imm19);
+  inline static Instr BitN(unsigned bitn, unsigned reg_size);
+  inline static Instr ShiftDP(Shift shift);
+  inline static Instr ImmDPShift(unsigned amount);
+  inline static Instr ExtendMode(Extend extend);
+  inline static Instr ImmExtendShift(unsigned left_shift);
+  inline static Instr ImmCondCmp(unsigned imm);
+  inline static Instr Nzcv(StatusFlags nzcv);
+
+  static bool IsImmAddSub(int64_t immediate);
+  static bool IsImmLogical(uint64_t value,
+                           unsigned width,
+                           unsigned* n,
+                           unsigned* imm_s,
+                           unsigned* imm_r);
+
+  // MemOperand offset encoding.
+  inline static Instr ImmLSUnsigned(int imm12);
+  inline static Instr ImmLS(int imm9);
+  inline static Instr ImmLSPair(int imm7, LSDataSize size);
+  inline static Instr ImmShiftLS(unsigned shift_amount);
+  inline static Instr ImmException(int imm16);
+  inline static Instr ImmSystemRegister(int imm15);
+  inline static Instr ImmHint(int imm7);
+  inline static Instr ImmBarrierDomain(int imm2);
+  inline static Instr ImmBarrierType(int imm2);
+  inline static LSDataSize CalcLSDataSize(LoadStoreOp op);
+
+  static bool IsImmLSUnscaled(int64_t offset);
+  static bool IsImmLSScaled(int64_t offset, LSDataSize size);
+
+  // Move immediates encoding.
+  inline static Instr ImmMoveWide(uint64_t imm);
+  inline static Instr ShiftMoveWide(int64_t shift);
+
+  // FP Immediates.
+  static Instr ImmFP32(float imm);
+  static Instr ImmFP64(double imm);
+  inline static Instr FPScale(unsigned scale);
+
+  // FP register type.
+  inline static Instr FPType(FPRegister fd);
+
+  // Class for scoping postponing the constant pool generation.
+  class BlockConstPoolScope {
+   public:
+    explicit BlockConstPoolScope(Assembler* assem) : assem_(assem) {
+      assem_->StartBlockConstPool();
+    }
+    ~BlockConstPoolScope() {
+      assem_->EndBlockConstPool();
+    }
+
+   private:
+    Assembler* assem_;
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstPoolScope);
+  };
+
+  // Check if is time to emit a constant pool.
+  void CheckConstPool(bool force_emit, bool require_jump);
+
+  // Allocate a constant pool of the correct size for the generated code.
+  Handle<ConstantPoolArray> NewConstantPool(Isolate* isolate);
+
+  // Generate the constant pool for the generated code.
+  void PopulateConstantPool(ConstantPoolArray* constant_pool);
+
+  // Returns true if we should emit a veneer as soon as possible for a branch
+  // which can at most reach to specified pc.
+  bool ShouldEmitVeneer(int max_reachable_pc,
+                        int margin = kVeneerDistanceMargin);
+  bool ShouldEmitVeneers(int margin = kVeneerDistanceMargin) {
+    return ShouldEmitVeneer(unresolved_branches_first_limit(), margin);
+  }
+
+  // The maximum code size generated for a veneer. Currently one branch
+  // instruction. This is for code size checking purposes, and can be extended
+  // in the future for example if we decide to add nops between the veneers.
+  static const int kMaxVeneerCodeSize = 1 * kInstructionSize;
+
+  void RecordVeneerPool(int location_offset, int size);
+  // Emits veneers for branches that are approaching their maximum range.
+  // If need_protection is true, the veneers are protected by a branch jumping
+  // over the code.
+  void EmitVeneers(bool force_emit, bool need_protection,
+                   int margin = kVeneerDistanceMargin);
+  void EmitVeneersGuard() { EmitPoolGuard(); }
+  // Checks whether veneers need to be emitted at this point.
+  // If force_emit is set, a veneer is generated for *all* unresolved branches.
+  void CheckVeneerPool(bool force_emit, bool require_jump,
+                       int margin = kVeneerDistanceMargin);
+
+  class BlockPoolsScope {
+   public:
+    explicit BlockPoolsScope(Assembler* assem) : assem_(assem) {
+      assem_->StartBlockPools();
+    }
+    ~BlockPoolsScope() {
+      assem_->EndBlockPools();
+    }
+
+   private:
+    Assembler* assem_;
+
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BlockPoolsScope);
+  };
+
+ protected:
+  inline const Register& AppropriateZeroRegFor(const CPURegister& reg) const;
+
+  void LoadStore(const CPURegister& rt,
+                 const MemOperand& addr,
+                 LoadStoreOp op);
+
+  void LoadStorePair(const CPURegister& rt, const CPURegister& rt2,
+                     const MemOperand& addr, LoadStorePairOp op);
+  static bool IsImmLSPair(int64_t offset, LSDataSize size);
+
+  void Logical(const Register& rd,
+               const Register& rn,
+               const Operand& operand,
+               LogicalOp op);
+  void LogicalImmediate(const Register& rd,
+                        const Register& rn,
+                        unsigned n,
+                        unsigned imm_s,
+                        unsigned imm_r,
+                        LogicalOp op);
+
+  void ConditionalCompare(const Register& rn,
+                          const Operand& operand,
+                          StatusFlags nzcv,
+                          Condition cond,
+                          ConditionalCompareOp op);
+  static bool IsImmConditionalCompare(int64_t immediate);
+
+  void AddSubWithCarry(const Register& rd,
+                       const Register& rn,
+                       const Operand& operand,
+                       FlagsUpdate S,
+                       AddSubWithCarryOp op);
+
+  // Functions for emulating operands not directly supported by the instruction
+  // set.
+  void EmitShift(const Register& rd,
+                 const Register& rn,
+                 Shift shift,
+                 unsigned amount);
+  void EmitExtendShift(const Register& rd,
+                       const Register& rn,
+                       Extend extend,
+                       unsigned left_shift);
+
+  void AddSub(const Register& rd,
+              const Register& rn,
+              const Operand& operand,
+              FlagsUpdate S,
+              AddSubOp op);
+
+  static bool IsImmFP32(float imm);
+  static bool IsImmFP64(double imm);
+
+  // Find an appropriate LoadStoreOp or LoadStorePairOp for the specified
+  // registers. Only simple loads are supported; sign- and zero-extension (such
+  // as in LDPSW_x or LDRB_w) are not supported.
+  static inline LoadStoreOp LoadOpFor(const CPURegister& rt);
+  static inline LoadStorePairOp LoadPairOpFor(const CPURegister& rt,
+                                              const CPURegister& rt2);
+  static inline LoadStoreOp StoreOpFor(const CPURegister& rt);
+  static inline LoadStorePairOp StorePairOpFor(const CPURegister& rt,
+                                               const CPURegister& rt2);
+  static inline LoadStorePairNonTemporalOp LoadPairNonTemporalOpFor(
+    const CPURegister& rt, const CPURegister& rt2);
+  static inline LoadStorePairNonTemporalOp StorePairNonTemporalOpFor(
+    const CPURegister& rt, const CPURegister& rt2);
+  static inline LoadLiteralOp LoadLiteralOpFor(const CPURegister& rt);
+
+  // Remove the specified branch from the unbound label link chain.
+  // If available, a veneer for this label can be used for other branches in the
+  // chain if the link chain cannot be fixed up without this branch.
+  void RemoveBranchFromLabelLinkChain(Instruction* branch,
+                                      Label* label,
+                                      Instruction* label_veneer = NULL);
+
+ private:
+  // Instruction helpers.
+  void MoveWide(const Register& rd,
+                uint64_t imm,
+                int shift,
+                MoveWideImmediateOp mov_op);
+  void DataProcShiftedRegister(const Register& rd,
+                               const Register& rn,
+                               const Operand& operand,
+                               FlagsUpdate S,
+                               Instr op);
+  void DataProcExtendedRegister(const Register& rd,
+                                const Register& rn,
+                                const Operand& operand,
+                                FlagsUpdate S,
+                                Instr op);
+  void LoadStorePairNonTemporal(const CPURegister& rt,
+                                const CPURegister& rt2,
+                                const MemOperand& addr,
+                                LoadStorePairNonTemporalOp op);
+  void ConditionalSelect(const Register& rd,
+                         const Register& rn,
+                         const Register& rm,
+                         Condition cond,
+                         ConditionalSelectOp op);
+  void DataProcessing1Source(const Register& rd,
+                             const Register& rn,
+                             DataProcessing1SourceOp op);
+  void DataProcessing3Source(const Register& rd,
+                             const Register& rn,
+                             const Register& rm,
+                             const Register& ra,
+                             DataProcessing3SourceOp op);
+  void FPDataProcessing1Source(const FPRegister& fd,
+                               const FPRegister& fn,
+                               FPDataProcessing1SourceOp op);
+  void FPDataProcessing2Source(const FPRegister& fd,
+                               const FPRegister& fn,
+                               const FPRegister& fm,
+                               FPDataProcessing2SourceOp op);
+  void FPDataProcessing3Source(const FPRegister& fd,
+                               const FPRegister& fn,
+                               const FPRegister& fm,
+                               const FPRegister& fa,
+                               FPDataProcessing3SourceOp op);
+
+  // Label helpers.
+
+  // Return an offset for a label-referencing instruction, typically a branch.
+  int LinkAndGetByteOffsetTo(Label* label);
+
+  // This is the same as LinkAndGetByteOffsetTo, but return an offset
+  // suitable for fields that take instruction offsets.
+  inline int LinkAndGetInstructionOffsetTo(Label* label);
+
+  static const int kStartOfLabelLinkChain = 0;
+
+  // Verify that a label's link chain is intact.
+  void CheckLabelLinkChain(Label const * label);
+
+  void RecordLiteral(int64_t imm, unsigned size);
+
+  // Postpone the generation of the constant pool for the specified number of
+  // instructions.
+  void BlockConstPoolFor(int instructions);
+
+  // Set how far from current pc the next constant pool check will be.
+  void SetNextConstPoolCheckIn(int instructions) {
+    next_constant_pool_check_ = pc_offset() + instructions * kInstructionSize;
+  }
+
+  // Emit the instruction at pc_.
+  void Emit(Instr instruction) {
+    STATIC_ASSERT(sizeof(*pc_) == 1);
+    STATIC_ASSERT(sizeof(instruction) == kInstructionSize);
+    DCHECK((pc_ + sizeof(instruction)) <= (buffer_ + buffer_size_));
+
+    memcpy(pc_, &instruction, sizeof(instruction));
+    pc_ += sizeof(instruction);
+    CheckBuffer();
+  }
+
+  // Emit data inline in the instruction stream.
+  void EmitData(void const * data, unsigned size) {
+    DCHECK(sizeof(*pc_) == 1);
+    DCHECK((pc_ + size) <= (buffer_ + buffer_size_));
+
+    // TODO(all): Somehow register we have some data here. Then we can
+    // disassemble it correctly.
+    memcpy(pc_, data, size);
+    pc_ += size;
+    CheckBuffer();
+  }
+
+  void GrowBuffer();
+  void CheckBufferSpace();
+  void CheckBuffer();
+
+  // Pc offset of the next constant pool check.
+  int next_constant_pool_check_;
+
+  // Constant pool generation
+  // Pools are emitted in the instruction stream. They are emitted when:
+  //  * the distance to the first use is above a pre-defined distance or
+  //  * the numbers of entries in the pool is above a pre-defined size or
+  //  * code generation is finished
+  // If a pool needs to be emitted before code generation is finished a branch
+  // over the emitted pool will be inserted.
+
+  // Constants in the pool may be addresses of functions that gets relocated;
+  // if so, a relocation info entry is associated to the constant pool entry.
+
+  // Repeated checking whether the constant pool should be emitted is rather
+  // expensive. By default we only check again once a number of instructions
+  // has been generated. That also means that the sizing of the buffers is not
+  // an exact science, and that we rely on some slop to not overrun buffers.
+  static const int kCheckConstPoolInterval = 128;
+
+  // Distance to first use after a which a pool will be emitted. Pool entries
+  // are accessed with pc relative load therefore this cannot be more than
+  // 1 * MB. Since constant pool emission checks are interval based this value
+  // is an approximation.
+  static const int kApproxMaxDistToConstPool = 64 * KB;
+
+  // Number of pool entries after which a pool will be emitted. Since constant
+  // pool emission checks are interval based this value is an approximation.
+  static const int kApproxMaxPoolEntryCount = 512;
+
+  // Emission of the constant pool may be blocked in some code sequences.
+  int const_pool_blocked_nesting_;  // Block emission if this is not zero.
+  int no_const_pool_before_;  // Block emission before this pc offset.
+
+  // Emission of the veneer pools may be blocked in some code sequences.
+  int veneer_pool_blocked_nesting_;  // Block emission if this is not zero.
+
+  // Relocation info generation
+  // Each relocation is encoded as a variable size value
+  static const int kMaxRelocSize = RelocInfoWriter::kMaxSize;
+  RelocInfoWriter reloc_info_writer;
+
+  // Relocation info records are also used during code generation as temporary
+  // containers for constants and code target addresses until they are emitted
+  // to the constant pool. These pending relocation info records are temporarily
+  // stored in a separate buffer until a constant pool is emitted.
+  // If every instruction in a long sequence is accessing the pool, we need one
+  // pending relocation entry per instruction.
+
+  // The pending constant pool.
+  ConstPool constpool_;
+
+  // Relocation for a type-recording IC has the AST id added to it.  This
+  // member variable is a way to pass the information from the call site to
+  // the relocation info.
+  TypeFeedbackId recorded_ast_id_;
+
+  inline TypeFeedbackId RecordedAstId();
+  inline void ClearRecordedAstId();
+
+ protected:
+  // Record the AST id of the CallIC being compiled, so that it can be placed
+  // in the relocation information.
+  void SetRecordedAstId(TypeFeedbackId ast_id) {
+    DCHECK(recorded_ast_id_.IsNone());
+    recorded_ast_id_ = ast_id;
+  }
+
+  // Code generation
+  // The relocation writer's position is at least kGap bytes below the end of
+  // the generated instructions. This is so that multi-instruction sequences do
+  // not have to check for overflow. The same is true for writes of large
+  // relocation info entries, and debug strings encoded in the instruction
+  // stream.
+  static const int kGap = 128;
+
+ public:
+  class FarBranchInfo {
+   public:
+    FarBranchInfo(int offset, Label* label)
+        : pc_offset_(offset), label_(label) {}
+    // Offset of the branch in the code generation buffer.
+    int pc_offset_;
+    // The label branched to.
+    Label* label_;
+  };
+
+ protected:
+  // Information about unresolved (forward) branches.
+  // The Assembler is only allowed to delete out-of-date information from here
+  // after a label is bound. The MacroAssembler uses this information to
+  // generate veneers.
+  //
+  // The second member gives information about the unresolved branch. The first
+  // member of the pair is the maximum offset that the branch can reach in the
+  // buffer. The map is sorted according to this reachable offset, allowing to
+  // easily check when veneers need to be emitted.
+  // Note that the maximum reachable offset (first member of the pairs) should
+  // always be positive but has the same type as the return value for
+  // pc_offset() for convenience.
+  std::multimap<int, FarBranchInfo> unresolved_branches_;
+
+  // We generate a veneer for a branch if we reach within this distance of the
+  // limit of the range.
+  static const int kVeneerDistanceMargin = 1 * KB;
+  // The factor of 2 is a finger in the air guess. With a default margin of
+  // 1KB, that leaves us an addional 256 instructions to avoid generating a
+  // protective branch.
+  static const int kVeneerNoProtectionFactor = 2;
+  static const int kVeneerDistanceCheckMargin =
+    kVeneerNoProtectionFactor * kVeneerDistanceMargin;
+  int unresolved_branches_first_limit() const {
+    DCHECK(!unresolved_branches_.empty());
+    return unresolved_branches_.begin()->first;
+  }
+  // This is similar to next_constant_pool_check_ and helps reduce the overhead
+  // of checking for veneer pools.
+  // It is maintained to the closest unresolved branch limit minus the maximum
+  // veneer margin (or kMaxInt if there are no unresolved branches).
+  int next_veneer_pool_check_;
+
+ private:
+  // If a veneer is emitted for a branch instruction, that instruction must be
+  // removed from the associated label's link chain so that the assembler does
+  // not later attempt (likely unsuccessfully) to patch it to branch directly to
+  // the label.
+  void DeleteUnresolvedBranchInfoForLabel(Label* label);
+  // This function deletes the information related to the label by traversing
+  // the label chain, and for each PC-relative instruction in the chain checking
+  // if pending unresolved information exists. Its complexity is proportional to
+  // the length of the label chain.
+  void DeleteUnresolvedBranchInfoForLabelTraverse(Label* label);
+
+ private:
+  PositionsRecorder positions_recorder_;
+  friend class PositionsRecorder;
+  friend class EnsureSpace;
+  friend class ConstPool;
+};
+
+class PatchingAssembler : public Assembler {
+ public:
+  // Create an Assembler with a buffer starting at 'start'.
+  // The buffer size is
+  //   size of instructions to patch + kGap
+  // Where kGap is the distance from which the Assembler tries to grow the
+  // buffer.
+  // If more or fewer instructions than expected are generated or if some
+  // relocation information takes space in the buffer, the PatchingAssembler
+  // will crash trying to grow the buffer.
+  PatchingAssembler(Instruction* start, unsigned count)
+    : Assembler(NULL,
+                reinterpret_cast<byte*>(start),
+                count * kInstructionSize + kGap) {
+    StartBlockPools();
+  }
+
+  PatchingAssembler(byte* start, unsigned count)
+    : Assembler(NULL, start, count * kInstructionSize + kGap) {
+    // Block constant pool emission.
+    StartBlockPools();
+  }
+
+  ~PatchingAssembler() {
+    // Const pool should still be blocked.
+    DCHECK(is_const_pool_blocked());
+    EndBlockPools();
+    // Verify we have generated the number of instruction we expected.
+    DCHECK((pc_offset() + kGap) == buffer_size_);
+    // Verify no relocation information has been emitted.
+    DCHECK(IsConstPoolEmpty());
+    // Flush the Instruction cache.
+    size_t length = buffer_size_ - kGap;
+    CpuFeatures::FlushICache(buffer_, length);
+  }
+
+  // See definition of PatchAdrFar() for details.
+  static const int kAdrFarPatchableNNops = 2;
+  static const int kAdrFarPatchableNInstrs = kAdrFarPatchableNNops + 2;
+  void PatchAdrFar(int64_t target_offset);
+};
+
+
+class EnsureSpace BASE_EMBEDDED {
+ public:
+  explicit EnsureSpace(Assembler* assembler) {
+    assembler->CheckBufferSpace();
+  }
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_ASSEMBLER_ARM64_H_
diff --git a/src/arm64/builtins-arm64.cc b/src/arm64/builtins-arm64.cc
new file mode 100644
index 0000000..0013e24
--- /dev/null
+++ b/src/arm64/builtins-arm64.cc
@@ -0,0 +1,1564 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/codegen.h"
+#include "src/debug.h"
+#include "src/deoptimizer.h"
+#include "src/full-codegen.h"
+#include "src/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define __ ACCESS_MASM(masm)
+
+
+// Load the built-in Array function from the current context.
+static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
+  // Load the native context.
+  __ Ldr(result, GlobalObjectMemOperand());
+  __ Ldr(result,
+         FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  // Load the InternalArray function from the native context.
+  __ Ldr(result,
+         MemOperand(result,
+                    Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
+}
+
+
+// Load the built-in InternalArray function from the current context.
+static void GenerateLoadInternalArrayFunction(MacroAssembler* masm,
+                                              Register result) {
+  // Load the native context.
+  __ Ldr(result, GlobalObjectMemOperand());
+  __ Ldr(result,
+         FieldMemOperand(result, GlobalObject::kNativeContextOffset));
+  // Load the InternalArray function from the native context.
+  __ Ldr(result, ContextMemOperand(result,
+                                   Context::INTERNAL_ARRAY_FUNCTION_INDEX));
+}
+
+
+void Builtins::Generate_Adaptor(MacroAssembler* masm,
+                                CFunctionId id,
+                                BuiltinExtraArguments extra_args) {
+  // ----------- S t a t e -------------
+  //  -- x0                 : number of arguments excluding receiver
+  //  -- x1                 : called function (only guaranteed when
+  //                          extra_args requires it)
+  //  -- cp                 : context
+  //  -- sp[0]              : last argument
+  //  -- ...
+  //  -- sp[4 * (argc - 1)] : first argument (argc == x0)
+  //  -- sp[4 * argc]       : receiver
+  // -----------------------------------
+
+  // Insert extra arguments.
+  int num_extra_args = 0;
+  if (extra_args == NEEDS_CALLED_FUNCTION) {
+    num_extra_args = 1;
+    __ Push(x1);
+  } else {
+    DCHECK(extra_args == NO_EXTRA_ARGUMENTS);
+  }
+
+  // JumpToExternalReference expects x0 to contain the number of arguments
+  // including the receiver and the extra arguments.
+  __ Add(x0, x0, num_extra_args + 1);
+  __ JumpToExternalReference(ExternalReference(id, masm->isolate()));
+}
+
+
+void Builtins::Generate_InternalArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0     : number of arguments
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+  ASM_LOCATION("Builtins::Generate_InternalArrayCode");
+  Label generic_array_code;
+
+  // Get the InternalArray function.
+  GenerateLoadInternalArrayFunction(masm, x1);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin InternalArray functions should be maps.
+    __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
+    __ Tst(x10, kSmiTagMask);
+    __ Assert(ne, kUnexpectedInitialMapForInternalArrayFunction);
+    __ CompareObjectType(x10, x11, x12, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForInternalArrayFunction);
+  }
+
+  // Run the native code for the InternalArray function called as a normal
+  // function.
+  InternalArrayConstructorStub stub(masm->isolate());
+  __ TailCallStub(&stub);
+}
+
+
+void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0     : number of arguments
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+  ASM_LOCATION("Builtins::Generate_ArrayCode");
+  Label generic_array_code, one_or_more_arguments, two_or_more_arguments;
+
+  // Get the Array function.
+  GenerateLoadArrayFunction(masm, x1);
+
+  if (FLAG_debug_code) {
+    // Initial map for the builtin Array functions should be maps.
+    __ Ldr(x10, FieldMemOperand(x1, JSFunction::kPrototypeOrInitialMapOffset));
+    __ Tst(x10, kSmiTagMask);
+    __ Assert(ne, kUnexpectedInitialMapForArrayFunction);
+    __ CompareObjectType(x10, x11, x12, MAP_TYPE);
+    __ Assert(eq, kUnexpectedInitialMapForArrayFunction);
+  }
+
+  // Run the native code for the Array function called as a normal function.
+  __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+  ArrayConstructorStub stub(masm->isolate());
+  __ TailCallStub(&stub);
+}
+
+
+void Builtins::Generate_StringConstructCode(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0                     : number of arguments
+  //  -- x1                     : constructor function
+  //  -- lr                     : return address
+  //  -- sp[(argc - n - 1) * 8] : arg[n] (zero based)
+  //  -- sp[argc * 8]           : receiver
+  // -----------------------------------
+  ASM_LOCATION("Builtins::Generate_StringConstructCode");
+  Counters* counters = masm->isolate()->counters();
+  __ IncrementCounter(counters->string_ctor_calls(), 1, x10, x11);
+
+  Register argc = x0;
+  Register function = x1;
+  if (FLAG_debug_code) {
+    __ LoadGlobalFunction(Context::STRING_FUNCTION_INDEX, x10);
+    __ Cmp(function, x10);
+    __ Assert(eq, kUnexpectedStringFunction);
+  }
+
+  // Load the first arguments in x0 and get rid of the rest.
+  Label no_arguments;
+  __ Cbz(argc, &no_arguments);
+  // First args = sp[(argc - 1) * 8].
+  __ Sub(argc, argc, 1);
+  __ Claim(argc, kXRegSize);
+  // jssp now point to args[0], load and drop args[0] + receiver.
+  Register arg = argc;
+  __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
+  argc = NoReg;
+
+  Register argument = x2;
+  Label not_cached, argument_is_string;
+  __ LookupNumberStringCache(arg,        // Input.
+                             argument,   // Result.
+                             x10,        // Scratch.
+                             x11,        // Scratch.
+                             x12,        // Scratch.
+                             &not_cached);
+  __ IncrementCounter(counters->string_ctor_cached_number(), 1, x10, x11);
+  __ Bind(&argument_is_string);
+
+  // ----------- S t a t e -------------
+  //  -- x2     : argument converted to string
+  //  -- x1     : constructor function
+  //  -- lr     : return address
+  // -----------------------------------
+
+  Label gc_required;
+  Register new_obj = x0;
+  __ Allocate(JSValue::kSize, new_obj, x10, x11, &gc_required, TAG_OBJECT);
+
+  // Initialize the String object.
+  Register map = x3;
+  __ LoadGlobalFunctionInitialMap(function, map, x10);
+  if (FLAG_debug_code) {
+    __ Ldrb(x4, FieldMemOperand(map, Map::kInstanceSizeOffset));
+    __ Cmp(x4, JSValue::kSize >> kPointerSizeLog2);
+    __ Assert(eq, kUnexpectedStringWrapperInstanceSize);
+    __ Ldrb(x4, FieldMemOperand(map, Map::kUnusedPropertyFieldsOffset));
+    __ Cmp(x4, 0);
+    __ Assert(eq, kUnexpectedUnusedPropertiesOfStringWrapper);
+  }
+  __ Str(map, FieldMemOperand(new_obj, HeapObject::kMapOffset));
+
+  Register empty = x3;
+  __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
+  __ Str(empty, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
+  __ Str(empty, FieldMemOperand(new_obj, JSObject::kElementsOffset));
+
+  __ Str(argument, FieldMemOperand(new_obj, JSValue::kValueOffset));
+
+  // Ensure the object is fully initialized.
+  STATIC_ASSERT(JSValue::kSize == (4 * kPointerSize));
+
+  __ Ret();
+
+  // The argument was not found in the number to string cache. Check
+  // if it's a string already before calling the conversion builtin.
+  Label convert_argument;
+  __ Bind(&not_cached);
+  __ JumpIfSmi(arg, &convert_argument);
+
+  // Is it a String?
+  __ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ Ldrb(x11, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+  __ Tbnz(x11, MaskToBit(kIsNotStringMask), &convert_argument);
+  __ Mov(argument, arg);
+  __ IncrementCounter(counters->string_ctor_string_value(), 1, x10, x11);
+  __ B(&argument_is_string);
+
+  // Invoke the conversion builtin and put the result into x2.
+  __ Bind(&convert_argument);
+  __ Push(function);  // Preserve the function.
+  __ IncrementCounter(counters->string_ctor_conversions(), 1, x10, x11);
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ Push(arg);
+    __ InvokeBuiltin(Builtins::TO_STRING, CALL_FUNCTION);
+  }
+  __ Pop(function);
+  __ Mov(argument, x0);
+  __ B(&argument_is_string);
+
+  // Load the empty string into x2, remove the receiver from the
+  // stack, and jump back to the case where the argument is a string.
+  __ Bind(&no_arguments);
+  __ LoadRoot(argument, Heap::kempty_stringRootIndex);
+  __ Drop(1);
+  __ B(&argument_is_string);
+
+  // At this point the argument is already a string. Call runtime to create a
+  // string wrapper.
+  __ Bind(&gc_required);
+  __ IncrementCounter(counters->string_ctor_gc_required(), 1, x10, x11);
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ Push(argument);
+    __ CallRuntime(Runtime::kNewStringWrapper, 1);
+  }
+  __ Ret();
+}
+
+
+static void CallRuntimePassFunction(MacroAssembler* masm,
+                                    Runtime::FunctionId function_id) {
+  FrameScope scope(masm, StackFrame::INTERNAL);
+  //   - Push a copy of the function onto the stack.
+  //   - Push another copy as a parameter to the runtime call.
+  __ Push(x1, x1);
+
+  __ CallRuntime(function_id, 1);
+
+  //   - Restore receiver.
+  __ Pop(x1);
+}
+
+
+static void GenerateTailCallToSharedCode(MacroAssembler* masm) {
+  __ Ldr(x2, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(x2, FieldMemOperand(x2, SharedFunctionInfo::kCodeOffset));
+  __ Add(x2, x2, Code::kHeaderSize - kHeapObjectTag);
+  __ Br(x2);
+}
+
+
+static void GenerateTailCallToReturnedCode(MacroAssembler* masm) {
+  __ Add(x0, x0, Code::kHeaderSize - kHeapObjectTag);
+  __ Br(x0);
+}
+
+
+void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) {
+  // Checking whether the queued function is ready for install is optional,
+  // since we come across interrupts and stack checks elsewhere. However, not
+  // checking may delay installing ready functions, and always checking would be
+  // quite expensive. A good compromise is to first check against stack limit as
+  // a cue for an interrupt signal.
+  Label ok;
+  __ CompareRoot(masm->StackPointer(), Heap::kStackLimitRootIndex);
+  __ B(hs, &ok);
+
+  CallRuntimePassFunction(masm, Runtime::kTryInstallOptimizedCode);
+  GenerateTailCallToReturnedCode(masm);
+
+  __ Bind(&ok);
+  GenerateTailCallToSharedCode(masm);
+}
+
+
+static void Generate_JSConstructStubHelper(MacroAssembler* masm,
+                                           bool is_api_function,
+                                           bool create_memento) {
+  // ----------- S t a t e -------------
+  //  -- x0     : number of arguments
+  //  -- x1     : constructor function
+  //  -- x2     : allocation site or undefined
+  //  -- lr     : return address
+  //  -- sp[...]: constructor arguments
+  // -----------------------------------
+
+  ASM_LOCATION("Builtins::Generate_JSConstructStubHelper");
+  // Should never create mementos for api functions.
+  DCHECK(!is_api_function || !create_memento);
+
+  Isolate* isolate = masm->isolate();
+
+  // Enter a construct frame.
+  {
+    FrameScope scope(masm, StackFrame::CONSTRUCT);
+
+    // Preserve the three incoming parameters on the stack.
+    if (create_memento) {
+      __ AssertUndefinedOrAllocationSite(x2, x10);
+      __ Push(x2);
+    }
+
+    Register argc = x0;
+    Register constructor = x1;
+    // x1: constructor function
+    __ SmiTag(argc);
+    __ Push(argc, constructor);
+    // sp[0] : Constructor function.
+    // sp[1]: number of arguments (smi-tagged)
+
+    // Try to allocate the object without transitioning into C code. If any of
+    // the preconditions is not met, the code bails out to the runtime call.
+    Label rt_call, allocated;
+    if (FLAG_inline_new) {
+      Label undo_allocation;
+      ExternalReference debug_step_in_fp =
+          ExternalReference::debug_step_in_fp_address(isolate);
+      __ Mov(x2, Operand(debug_step_in_fp));
+      __ Ldr(x2, MemOperand(x2));
+      __ Cbnz(x2, &rt_call);
+      // Load the initial map and verify that it is in fact a map.
+      Register init_map = x2;
+      __ Ldr(init_map,
+             FieldMemOperand(constructor,
+                             JSFunction::kPrototypeOrInitialMapOffset));
+      __ JumpIfSmi(init_map, &rt_call);
+      __ JumpIfNotObjectType(init_map, x10, x11, MAP_TYPE, &rt_call);
+
+      // Check that the constructor is not constructing a JSFunction (see
+      // comments in Runtime_NewObject in runtime.cc). In which case the initial
+      // map's instance type would be JS_FUNCTION_TYPE.
+      __ CompareInstanceType(init_map, x10, JS_FUNCTION_TYPE);
+      __ B(eq, &rt_call);
+
+      Register constructon_count = x14;
+      if (!is_api_function) {
+        Label allocate;
+        MemOperand bit_field3 =
+            FieldMemOperand(init_map, Map::kBitField3Offset);
+        // Check if slack tracking is enabled.
+        __ Ldr(x4, bit_field3);
+        __ DecodeField<Map::ConstructionCount>(constructon_count, x4);
+        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
+        __ B(eq, &allocate);
+        // Decrease generous allocation count.
+        __ Subs(x4, x4, Operand(1 << Map::ConstructionCount::kShift));
+        __ Str(x4, bit_field3);
+        __ Cmp(constructon_count, Operand(JSFunction::kFinishSlackTracking));
+        __ B(ne, &allocate);
+
+        // Push the constructor and map to the stack, and the constructor again
+        // as argument to the runtime call.
+        __ Push(constructor, init_map, constructor);
+        __ CallRuntime(Runtime::kFinalizeInstanceSize, 1);
+        __ Pop(init_map, constructor);
+        __ Mov(constructon_count, Operand(JSFunction::kNoSlackTracking));
+        __ Bind(&allocate);
+      }
+
+      // Now allocate the JSObject on the heap.
+      Register obj_size = x3;
+      Register new_obj = x4;
+      __ Ldrb(obj_size, FieldMemOperand(init_map, Map::kInstanceSizeOffset));
+      if (create_memento) {
+        __ Add(x7, obj_size,
+               Operand(AllocationMemento::kSize / kPointerSize));
+        __ Allocate(x7, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
+      } else {
+        __ Allocate(obj_size, new_obj, x10, x11, &rt_call, SIZE_IN_WORDS);
+      }
+
+      // Allocated the JSObject, now initialize the fields. Map is set to
+      // initial map and properties and elements are set to empty fixed array.
+      // NB. the object pointer is not tagged, so MemOperand is used.
+      Register empty = x5;
+      __ LoadRoot(empty, Heap::kEmptyFixedArrayRootIndex);
+      __ Str(init_map, MemOperand(new_obj, JSObject::kMapOffset));
+      STATIC_ASSERT(JSObject::kElementsOffset ==
+          (JSObject::kPropertiesOffset + kPointerSize));
+      __ Stp(empty, empty, MemOperand(new_obj, JSObject::kPropertiesOffset));
+
+      Register first_prop = x5;
+      __ Add(first_prop, new_obj, JSObject::kHeaderSize);
+
+      // Fill all of the in-object properties with the appropriate filler.
+      Register filler = x7;
+      __ LoadRoot(filler, Heap::kUndefinedValueRootIndex);
+
+      // Obtain number of pre-allocated property fields and in-object
+      // properties.
+      Register prealloc_fields = x10;
+      Register inobject_props = x11;
+      Register inst_sizes = x11;
+      __ Ldr(inst_sizes, FieldMemOperand(init_map, Map::kInstanceSizesOffset));
+      __ Ubfx(prealloc_fields, inst_sizes,
+              Map::kPreAllocatedPropertyFieldsByte * kBitsPerByte,
+              kBitsPerByte);
+      __ Ubfx(inobject_props, inst_sizes,
+              Map::kInObjectPropertiesByte * kBitsPerByte, kBitsPerByte);
+
+      // Calculate number of property fields in the object.
+      Register prop_fields = x6;
+      __ Sub(prop_fields, obj_size, JSObject::kHeaderSize / kPointerSize);
+
+      if (!is_api_function) {
+        Label no_inobject_slack_tracking;
+
+        // Check if slack tracking is enabled.
+        __ Cmp(constructon_count, Operand(JSFunction::kNoSlackTracking));
+        __ B(eq, &no_inobject_slack_tracking);
+        constructon_count = NoReg;
+
+        // Fill the pre-allocated fields with undef.
+        __ FillFields(first_prop, prealloc_fields, filler);
+
+        // Update first_prop register to be the offset of the first field after
+        // pre-allocated fields.
+        __ Add(first_prop, first_prop,
+               Operand(prealloc_fields, LSL, kPointerSizeLog2));
+
+        if (FLAG_debug_code) {
+          Register obj_end = x14;
+          __ Add(obj_end, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
+          __ Cmp(first_prop, obj_end);
+          __ Assert(le, kUnexpectedNumberOfPreAllocatedPropertyFields);
+        }
+
+        // Fill the remaining fields with one pointer filler map.
+        __ LoadRoot(filler, Heap::kOnePointerFillerMapRootIndex);
+        __ Sub(prop_fields, prop_fields, prealloc_fields);
+
+        __ bind(&no_inobject_slack_tracking);
+      }
+      if (create_memento) {
+        // Fill the pre-allocated fields with undef.
+        __ FillFields(first_prop, prop_fields, filler);
+        __ Add(first_prop, new_obj, Operand(obj_size, LSL, kPointerSizeLog2));
+        __ LoadRoot(x14, Heap::kAllocationMementoMapRootIndex);
+        DCHECK_EQ(0 * kPointerSize, AllocationMemento::kMapOffset);
+        __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
+        // Load the AllocationSite
+        __ Peek(x14, 2 * kXRegSize);
+        DCHECK_EQ(1 * kPointerSize, AllocationMemento::kAllocationSiteOffset);
+        __ Str(x14, MemOperand(first_prop, kPointerSize, PostIndex));
+        first_prop = NoReg;
+      } else {
+        // Fill all of the property fields with undef.
+        __ FillFields(first_prop, prop_fields, filler);
+        first_prop = NoReg;
+        prop_fields = NoReg;
+      }
+
+      // Add the object tag to make the JSObject real, so that we can continue
+      // and jump into the continuation code at any time from now on. Any
+      // failures need to undo the allocation, so that the heap is in a
+      // consistent state and verifiable.
+      __ Add(new_obj, new_obj, kHeapObjectTag);
+
+      // Check if a non-empty properties array is needed. Continue with
+      // allocated object if not, or fall through to runtime call if it is.
+      Register element_count = x3;
+      __ Ldrb(element_count,
+              FieldMemOperand(init_map, Map::kUnusedPropertyFieldsOffset));
+      // The field instance sizes contains both pre-allocated property fields
+      // and in-object properties.
+      __ Add(element_count, element_count, prealloc_fields);
+      __ Subs(element_count, element_count, inobject_props);
+
+      // Done if no extra properties are to be allocated.
+      __ B(eq, &allocated);
+      __ Assert(pl, kPropertyAllocationCountFailed);
+
+      // Scale the number of elements by pointer size and add the header for
+      // FixedArrays to the start of the next object calculation from above.
+      Register new_array = x5;
+      Register array_size = x6;
+      __ Add(array_size, element_count, FixedArray::kHeaderSize / kPointerSize);
+      __ Allocate(array_size, new_array, x11, x12, &undo_allocation,
+                  static_cast<AllocationFlags>(RESULT_CONTAINS_TOP |
+                                               SIZE_IN_WORDS));
+
+      Register array_map = x10;
+      __ LoadRoot(array_map, Heap::kFixedArrayMapRootIndex);
+      __ Str(array_map, MemOperand(new_array, FixedArray::kMapOffset));
+      __ SmiTag(x0, element_count);
+      __ Str(x0, MemOperand(new_array, FixedArray::kLengthOffset));
+
+      // Initialize the fields to undefined.
+      Register elements = x10;
+      __ Add(elements, new_array, FixedArray::kHeaderSize);
+      __ FillFields(elements, element_count, filler);
+
+      // Store the initialized FixedArray into the properties field of the
+      // JSObject.
+      __ Add(new_array, new_array, kHeapObjectTag);
+      __ Str(new_array, FieldMemOperand(new_obj, JSObject::kPropertiesOffset));
+
+      // Continue with JSObject being successfully allocated.
+      __ B(&allocated);
+
+      // Undo the setting of the new top so that the heap is verifiable. For
+      // example, the map's unused properties potentially do not match the
+      // allocated objects unused properties.
+      __ Bind(&undo_allocation);
+      __ UndoAllocationInNewSpace(new_obj, x14);
+    }
+
+    // Allocate the new receiver object using the runtime call.
+    __ Bind(&rt_call);
+    Label count_incremented;
+    if (create_memento) {
+      // Get the cell or allocation site.
+      __ Peek(x4, 2 * kXRegSize);
+      __ Push(x4);
+      __ Push(constructor);  // Argument for Runtime_NewObject.
+      __ CallRuntime(Runtime::kNewObjectWithAllocationSite, 2);
+      __ Mov(x4, x0);
+      // If we ended up using the runtime, and we want a memento, then the
+      // runtime call made it for us, and we shouldn't do create count
+      // increment.
+      __ jmp(&count_incremented);
+    } else {
+      __ Push(constructor);  // Argument for Runtime_NewObject.
+      __ CallRuntime(Runtime::kNewObject, 1);
+      __ Mov(x4, x0);
+    }
+
+    // Receiver for constructor call allocated.
+    // x4: JSObject
+    __ Bind(&allocated);
+
+    if (create_memento) {
+      __ Peek(x10, 2 * kXRegSize);
+      __ JumpIfRoot(x10, Heap::kUndefinedValueRootIndex, &count_incremented);
+      // r2 is an AllocationSite. We are creating a memento from it, so we
+      // need to increment the memento create count.
+      __ Ldr(x5, FieldMemOperand(x10,
+                                 AllocationSite::kPretenureCreateCountOffset));
+      __ Add(x5, x5, Operand(Smi::FromInt(1)));
+      __ Str(x5, FieldMemOperand(x10,
+                                 AllocationSite::kPretenureCreateCountOffset));
+      __ bind(&count_incremented);
+    }
+
+    __ Push(x4, x4);
+
+    // Reload the number of arguments from the stack.
+    // Set it up in x0 for the function call below.
+    // jssp[0]: receiver
+    // jssp[1]: receiver
+    // jssp[2]: constructor function
+    // jssp[3]: number of arguments (smi-tagged)
+    __ Peek(constructor, 2 * kXRegSize);  // Load constructor.
+    __ Peek(argc, 3 * kXRegSize);  // Load number of arguments.
+    __ SmiUntag(argc);
+
+    // Set up pointer to last argument.
+    __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset);
+
+    // Copy arguments and receiver to the expression stack.
+    // Copy 2 values every loop to use ldp/stp.
+    // x0: number of arguments
+    // x1: constructor function
+    // x2: address of last argument (caller sp)
+    // jssp[0]: receiver
+    // jssp[1]: receiver
+    // jssp[2]: constructor function
+    // jssp[3]: number of arguments (smi-tagged)
+    // Compute the start address of the copy in x3.
+    __ Add(x3, x2, Operand(argc, LSL, kPointerSizeLog2));
+    Label loop, entry, done_copying_arguments;
+    __ B(&entry);
+    __ Bind(&loop);
+    __ Ldp(x10, x11, MemOperand(x3, -2 * kPointerSize, PreIndex));
+    __ Push(x11, x10);
+    __ Bind(&entry);
+    __ Cmp(x3, x2);
+    __ B(gt, &loop);
+    // Because we copied values 2 by 2 we may have copied one extra value.
+    // Drop it if that is the case.
+    __ B(eq, &done_copying_arguments);
+    __ Drop(1);
+    __ Bind(&done_copying_arguments);
+
+    // Call the function.
+    // x0: number of arguments
+    // x1: constructor function
+    if (is_api_function) {
+      __ Ldr(cp, FieldMemOperand(constructor, JSFunction::kContextOffset));
+      Handle<Code> code =
+          masm->isolate()->builtins()->HandleApiCallConstruct();
+      __ Call(code, RelocInfo::CODE_TARGET);
+    } else {
+      ParameterCount actual(argc);
+      __ InvokeFunction(constructor, actual, CALL_FUNCTION, NullCallWrapper());
+    }
+
+    // Store offset of return address for deoptimizer.
+    if (!is_api_function) {
+      masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset());
+    }
+
+    // Restore the context from the frame.
+    // x0: result
+    // jssp[0]: receiver
+    // jssp[1]: constructor function
+    // jssp[2]: number of arguments (smi-tagged)
+    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+    // If the result is an object (in the ECMA sense), we should get rid
+    // of the receiver and use the result; see ECMA-262 section 13.2.2-7
+    // on page 74.
+    Label use_receiver, exit;
+
+    // If the result is a smi, it is *not* an object in the ECMA sense.
+    // x0: result
+    // jssp[0]: receiver (newly allocated object)
+    // jssp[1]: constructor function
+    // jssp[2]: number of arguments (smi-tagged)
+    __ JumpIfSmi(x0, &use_receiver);
+
+    // If the type of the result (stored in its map) is less than
+    // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense.
+    __ JumpIfObjectType(x0, x1, x3, FIRST_SPEC_OBJECT_TYPE, &exit, ge);
+
+    // Throw away the result of the constructor invocation and use the
+    // on-stack receiver as the result.
+    __ Bind(&use_receiver);
+    __ Peek(x0, 0);
+
+    // Remove the receiver from the stack, remove caller arguments, and
+    // return.
+    __ Bind(&exit);
+    // x0: result
+    // jssp[0]: receiver (newly allocated object)
+    // jssp[1]: constructor function
+    // jssp[2]: number of arguments (smi-tagged)
+    __ Peek(x1, 2 * kXRegSize);
+
+    // Leave construct frame.
+  }
+
+  __ DropBySMI(x1);
+  __ Drop(1);
+  __ IncrementCounter(isolate->counters()->constructed_objects(), 1, x1, x2);
+  __ Ret();
+}
+
+
+void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new);
+}
+
+
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) {
+  Generate_JSConstructStubHelper(masm, true, false);
+}
+
+
+// Input:
+//   x0: code entry.
+//   x1: function.
+//   x2: receiver.
+//   x3: argc.
+//   x4: argv.
+// Output:
+//   x0: result.
+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
+                                             bool is_construct) {
+  // Called from JSEntryStub::GenerateBody().
+  Register function = x1;
+  Register receiver = x2;
+  Register argc = x3;
+  Register argv = x4;
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  // Clear the context before we push it when entering the internal frame.
+  __ Mov(cp, 0);
+
+  {
+    // Enter an internal frame.
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Set up the context from the function argument.
+    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
+
+    __ InitializeRootRegister();
+
+    // Push the function and the receiver onto the stack.
+    __ Push(function, receiver);
+
+    // Copy arguments to the stack in a loop, in reverse order.
+    // x3: argc.
+    // x4: argv.
+    Label loop, entry;
+    // Compute the copy end address.
+    __ Add(x10, argv, Operand(argc, LSL, kPointerSizeLog2));
+
+    __ B(&entry);
+    __ Bind(&loop);
+    __ Ldr(x11, MemOperand(argv, kPointerSize, PostIndex));
+    __ Ldr(x12, MemOperand(x11));  // Dereference the handle.
+    __ Push(x12);  // Push the argument.
+    __ Bind(&entry);
+    __ Cmp(x10, argv);
+    __ B(ne, &loop);
+
+    // Initialize all JavaScript callee-saved registers, since they will be seen
+    // by the garbage collector as part of handlers.
+    // The original values have been saved in JSEntryStub::GenerateBody().
+    __ LoadRoot(x19, Heap::kUndefinedValueRootIndex);
+    __ Mov(x20, x19);
+    __ Mov(x21, x19);
+    __ Mov(x22, x19);
+    __ Mov(x23, x19);
+    __ Mov(x24, x19);
+    __ Mov(x25, x19);
+    // Don't initialize the reserved registers.
+    // x26 : root register (root).
+    // x27 : context pointer (cp).
+    // x28 : JS stack pointer (jssp).
+    // x29 : frame pointer (fp).
+
+    __ Mov(x0, argc);
+    if (is_construct) {
+      // No type feedback cell is available.
+      __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+
+      CallConstructStub stub(masm->isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
+      __ CallStub(&stub);
+    } else {
+      ParameterCount actual(x0);
+      __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
+    }
+    // Exit the JS internal frame and remove the parameters (except function),
+    // and return.
+  }
+
+  // Result is in x0. Return.
+  __ Ret();
+}
+
+
+void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, true);
+}
+
+
+void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
+  CallRuntimePassFunction(masm, Runtime::kCompileLazy);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+static void CallCompileOptimized(MacroAssembler* masm, bool concurrent) {
+  FrameScope scope(masm, StackFrame::INTERNAL);
+  Register function = x1;
+
+  // Preserve function. At the same time, push arguments for
+  // kCompileOptimized.
+  __ LoadObject(x10, masm->isolate()->factory()->ToBoolean(concurrent));
+  __ Push(function, function, x10);
+
+  __ CallRuntime(Runtime::kCompileOptimized, 2);
+
+  // Restore receiver.
+  __ Pop(function);
+}
+
+
+void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
+  CallCompileOptimized(masm, false);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+void Builtins::Generate_CompileOptimizedConcurrent(MacroAssembler* masm) {
+  CallCompileOptimized(masm, true);
+  GenerateTailCallToReturnedCode(masm);
+}
+
+
+static void GenerateMakeCodeYoungAgainCommon(MacroAssembler* masm) {
+  // For now, we are relying on the fact that make_code_young doesn't do any
+  // garbage collection which allows us to save/restore the registers without
+  // worrying about which of them contain pointers. We also don't build an
+  // internal frame to make the code fast, since we shouldn't have to do stack
+  // crawls in MakeCodeYoung. This seems a bit fragile.
+
+  // The following caller-saved registers must be saved and restored when
+  // calling through to the runtime:
+  //   x0 - The address from which to resume execution.
+  //   x1 - isolate
+  //   lr - The return address for the JSFunction itself. It has not yet been
+  //        preserved on the stack because the frame setup code was replaced
+  //        with a call to this stub, to handle code ageing.
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ Push(x0, x1, fp, lr);
+    __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
+    __ CallCFunction(
+        ExternalReference::get_make_code_young_function(masm->isolate()), 2);
+    __ Pop(lr, fp, x1, x0);
+  }
+
+  // The calling function has been made young again, so return to execute the
+  // real frame set-up code.
+  __ Br(x0);
+}
+
+#define DEFINE_CODE_AGE_BUILTIN_GENERATOR(C)                 \
+void Builtins::Generate_Make##C##CodeYoungAgainEvenMarking(  \
+    MacroAssembler* masm) {                                  \
+  GenerateMakeCodeYoungAgainCommon(masm);                    \
+}                                                            \
+void Builtins::Generate_Make##C##CodeYoungAgainOddMarking(   \
+    MacroAssembler* masm) {                                  \
+  GenerateMakeCodeYoungAgainCommon(masm);                    \
+}
+CODE_AGE_LIST(DEFINE_CODE_AGE_BUILTIN_GENERATOR)
+#undef DEFINE_CODE_AGE_BUILTIN_GENERATOR
+
+
+void Builtins::Generate_MarkCodeAsExecutedOnce(MacroAssembler* masm) {
+  // For now, as in GenerateMakeCodeYoungAgainCommon, we are relying on the fact
+  // that make_code_young doesn't do any garbage collection which allows us to
+  // save/restore the registers without worrying about which of them contain
+  // pointers.
+
+  // The following caller-saved registers must be saved and restored when
+  // calling through to the runtime:
+  //   x0 - The address from which to resume execution.
+  //   x1 - isolate
+  //   lr - The return address for the JSFunction itself. It has not yet been
+  //        preserved on the stack because the frame setup code was replaced
+  //        with a call to this stub, to handle code ageing.
+  {
+    FrameScope scope(masm, StackFrame::MANUAL);
+    __ Push(x0, x1, fp, lr);
+    __ Mov(x1, ExternalReference::isolate_address(masm->isolate()));
+    __ CallCFunction(
+        ExternalReference::get_mark_code_as_executed_function(
+            masm->isolate()), 2);
+    __ Pop(lr, fp, x1, x0);
+
+    // Perform prologue operations usually performed by the young code stub.
+    __ EmitFrameSetupForCodeAgePatching(masm);
+  }
+
+  // Jump to point after the code-age stub.
+  __ Add(x0, x0, kNoCodeAgeSequenceLength);
+  __ Br(x0);
+}
+
+
+void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
+  GenerateMakeCodeYoungAgainCommon(masm);
+}
+
+
+static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
+                                             SaveFPRegsMode save_doubles) {
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Preserve registers across notification, this is important for compiled
+    // stubs that tail call the runtime on deopts passing their parameters in
+    // registers.
+    // TODO(jbramley): Is it correct (and appropriate) to use safepoint
+    // registers here? According to the comment above, we should only need to
+    // preserve the registers with parameters.
+    __ PushXRegList(kSafepointSavedRegisters);
+    // Pass the function and deoptimization type to the runtime system.
+    __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
+    __ PopXRegList(kSafepointSavedRegisters);
+  }
+
+  // Ignore state (pushed by Deoptimizer::EntryGenerator::Generate).
+  __ Drop(1);
+
+  // Jump to the miss handler. Deoptimizer::EntryGenerator::Generate loads this
+  // into lr before it jumps here.
+  __ Br(lr);
+}
+
+
+void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
+  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
+}
+
+
+void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
+  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
+}
+
+
+static void Generate_NotifyDeoptimizedHelper(MacroAssembler* masm,
+                                             Deoptimizer::BailoutType type) {
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    // Pass the deoptimization type to the runtime system.
+    __ Mov(x0, Smi::FromInt(static_cast<int>(type)));
+    __ Push(x0);
+    __ CallRuntime(Runtime::kNotifyDeoptimized, 1);
+  }
+
+  // Get the full codegen state from the stack and untag it.
+  Register state = x6;
+  __ Peek(state, 0);
+  __ SmiUntag(state);
+
+  // Switch on the state.
+  Label with_tos_register, unknown_state;
+  __ CompareAndBranch(
+      state, FullCodeGenerator::NO_REGISTERS, ne, &with_tos_register);
+  __ Drop(1);  // Remove state.
+  __ Ret();
+
+  __ Bind(&with_tos_register);
+  // Reload TOS register.
+  __ Peek(x0, kPointerSize);
+  __ CompareAndBranch(state, FullCodeGenerator::TOS_REG, ne, &unknown_state);
+  __ Drop(2);  // Remove state and TOS.
+  __ Ret();
+
+  __ Bind(&unknown_state);
+  __ Abort(kInvalidFullCodegenState);
+}
+
+
+void Builtins::Generate_NotifyDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::EAGER);
+}
+
+
+void Builtins::Generate_NotifyLazyDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::LAZY);
+}
+
+
+void Builtins::Generate_NotifySoftDeoptimized(MacroAssembler* masm) {
+  Generate_NotifyDeoptimizedHelper(masm, Deoptimizer::SOFT);
+}
+
+
+void Builtins::Generate_OnStackReplacement(MacroAssembler* masm) {
+  // Lookup the function in the JavaScript frame.
+  __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    // Pass function as argument.
+    __ Push(x0);
+    __ CallRuntime(Runtime::kCompileForOnStackReplacement, 1);
+  }
+
+  // If the code object is null, just return to the unoptimized code.
+  Label skip;
+  __ CompareAndBranch(x0, Smi::FromInt(0), ne, &skip);
+  __ Ret();
+
+  __ Bind(&skip);
+
+  // Load deoptimization data from the code object.
+  // <deopt_data> = <code>[#deoptimization_data_offset]
+  __ Ldr(x1, MemOperand(x0, Code::kDeoptimizationDataOffset - kHeapObjectTag));
+
+  // Load the OSR entrypoint offset from the deoptimization data.
+  // <osr_offset> = <deopt_data>[#header_size + #osr_pc_offset]
+  __ Ldrsw(w1, UntagSmiFieldMemOperand(x1, FixedArray::OffsetOfElementAt(
+      DeoptimizationInputData::kOsrPcOffsetIndex)));
+
+  // Compute the target address = code_obj + header_size + osr_offset
+  // <entry_addr> = <code_obj> + #header_size + <osr_offset>
+  __ Add(x0, x0, x1);
+  __ Add(lr, x0, Code::kHeaderSize - kHeapObjectTag);
+
+  // And "return" to the OSR entry point of the function.
+  __ Ret();
+}
+
+
+void Builtins::Generate_OsrAfterStackCheck(MacroAssembler* masm) {
+  // We check the stack limit as indicator that recompilation might be done.
+  Label ok;
+  __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
+  __ B(hs, &ok);
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    __ CallRuntime(Runtime::kStackGuard, 0);
+  }
+  __ Jump(masm->isolate()->builtins()->OnStackReplacement(),
+          RelocInfo::CODE_TARGET);
+
+  __ Bind(&ok);
+  __ Ret();
+}
+
+
+void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
+  enum {
+    call_type_JS_func = 0,
+    call_type_func_proxy = 1,
+    call_type_non_func = 2
+  };
+  Register argc = x0;
+  Register function = x1;
+  Register call_type = x4;
+  Register scratch1 = x10;
+  Register scratch2 = x11;
+  Register receiver_type = x13;
+
+  ASM_LOCATION("Builtins::Generate_FunctionCall");
+  // 1. Make sure we have at least one argument.
+  { Label done;
+    __ Cbnz(argc, &done);
+    __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
+    __ Push(scratch1);
+    __ Mov(argc, 1);
+    __ Bind(&done);
+  }
+
+  // 2. Get the function to call (passed as receiver) from the stack, check
+  //    if it is a function.
+  Label slow, non_function;
+  __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
+  __ JumpIfSmi(function, &non_function);
+  __ JumpIfNotObjectType(function, scratch1, receiver_type,
+                         JS_FUNCTION_TYPE, &slow);
+
+  // 3a. Patch the first argument if necessary when calling a function.
+  Label shift_arguments;
+  __ Mov(call_type, static_cast<int>(call_type_JS_func));
+  { Label convert_to_object, use_global_proxy, patch_receiver;
+    // Change context eagerly in case we need the global receiver.
+    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
+
+    // Do not transform the receiver for strict mode functions.
+    // Also do not transform the receiver for native (Compilerhints already in
+    // x3).
+    __ Ldr(scratch1,
+           FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+    __ Ldr(scratch2.W(),
+           FieldMemOperand(scratch1, SharedFunctionInfo::kCompilerHintsOffset));
+    __ TestAndBranchIfAnySet(
+        scratch2.W(),
+        (1 << SharedFunctionInfo::kStrictModeFunction) |
+        (1 << SharedFunctionInfo::kNative),
+        &shift_arguments);
+
+    // Compute the receiver in sloppy mode.
+    Register receiver = x2;
+    __ Sub(scratch1, argc, 1);
+    __ Peek(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
+    __ JumpIfSmi(receiver, &convert_to_object);
+
+    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
+                  &use_global_proxy);
+    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
+
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ JumpIfObjectType(receiver, scratch1, scratch2,
+                        FIRST_SPEC_OBJECT_TYPE, &shift_arguments, ge);
+
+    __ Bind(&convert_to_object);
+
+    {
+      // Enter an internal frame in order to preserve argument count.
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      __ SmiTag(argc);
+
+      __ Push(argc, receiver);
+      __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+      __ Mov(receiver, x0);
+
+      __ Pop(argc);
+      __ SmiUntag(argc);
+
+      // Exit the internal frame.
+    }
+
+    // Restore the function and flag in the registers.
+    __ Peek(function, Operand(argc, LSL, kXRegSizeLog2));
+    __ Mov(call_type, static_cast<int>(call_type_JS_func));
+    __ B(&patch_receiver);
+
+    __ Bind(&use_global_proxy);
+    __ Ldr(receiver, GlobalObjectMemOperand());
+    __ Ldr(receiver,
+           FieldMemOperand(receiver, GlobalObject::kGlobalProxyOffset));
+
+
+    __ Bind(&patch_receiver);
+    __ Sub(scratch1, argc, 1);
+    __ Poke(receiver, Operand(scratch1, LSL, kXRegSizeLog2));
+
+    __ B(&shift_arguments);
+  }
+
+  // 3b. Check for function proxy.
+  __ Bind(&slow);
+  __ Mov(call_type, static_cast<int>(call_type_func_proxy));
+  __ Cmp(receiver_type, JS_FUNCTION_PROXY_TYPE);
+  __ B(eq, &shift_arguments);
+  __ Bind(&non_function);
+  __ Mov(call_type, static_cast<int>(call_type_non_func));
+
+  // 3c. Patch the first argument when calling a non-function.  The
+  //     CALL_NON_FUNCTION builtin expects the non-function callee as
+  //     receiver, so overwrite the first argument which will ultimately
+  //     become the receiver.
+  // call type (0: JS function, 1: function proxy, 2: non-function)
+  __ Sub(scratch1, argc, 1);
+  __ Poke(function, Operand(scratch1, LSL, kXRegSizeLog2));
+
+  // 4. Shift arguments and return address one slot down on the stack
+  //    (overwriting the original receiver).  Adjust argument count to make
+  //    the original first argument the new receiver.
+  // call type (0: JS function, 1: function proxy, 2: non-function)
+  __ Bind(&shift_arguments);
+  { Label loop;
+    // Calculate the copy start address (destination). Copy end address is jssp.
+    __ Add(scratch2, jssp, Operand(argc, LSL, kPointerSizeLog2));
+    __ Sub(scratch1, scratch2, kPointerSize);
+
+    __ Bind(&loop);
+    __ Ldr(x12, MemOperand(scratch1, -kPointerSize, PostIndex));
+    __ Str(x12, MemOperand(scratch2, -kPointerSize, PostIndex));
+    __ Cmp(scratch1, jssp);
+    __ B(ge, &loop);
+    // Adjust the actual number of arguments and remove the top element
+    // (which is a copy of the last argument).
+    __ Sub(argc, argc, 1);
+    __ Drop(1);
+  }
+
+  // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin,
+  //     or a function proxy via CALL_FUNCTION_PROXY.
+  // call type (0: JS function, 1: function proxy, 2: non-function)
+  { Label js_function, non_proxy;
+    __ Cbz(call_type, &js_function);
+    // Expected number of arguments is 0 for CALL_NON_FUNCTION.
+    __ Mov(x2, 0);
+    __ Cmp(call_type, static_cast<int>(call_type_func_proxy));
+    __ B(ne, &non_proxy);
+
+    __ Push(function);  // Re-add proxy object as additional argument.
+    __ Add(argc, argc, 1);
+    __ GetBuiltinFunction(function, Builtins::CALL_FUNCTION_PROXY);
+    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+
+    __ Bind(&non_proxy);
+    __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
+    __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+    __ Bind(&js_function);
+  }
+
+  // 5b. Get the code to call from the function and check that the number of
+  //     expected arguments matches what we're providing.  If so, jump
+  //     (tail-call) to the code in register edx without checking arguments.
+  __ Ldr(x3, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldrsw(x2,
+           FieldMemOperand(x3,
+             SharedFunctionInfo::kFormalParameterCountOffset));
+  Label dont_adapt_args;
+  __ Cmp(x2, argc);  // Check formal and actual parameter counts.
+  __ B(eq, &dont_adapt_args);
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+  __ Bind(&dont_adapt_args);
+
+  __ Ldr(x3, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+  ParameterCount expected(0);
+  __ InvokeCode(x3, expected, expected, JUMP_FUNCTION, NullCallWrapper());
+}
+
+
+void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
+  ASM_LOCATION("Builtins::Generate_FunctionApply");
+  const int kIndexOffset    =
+      StandardFrameConstants::kExpressionsOffset - (2 * kPointerSize);
+  const int kLimitOffset    =
+      StandardFrameConstants::kExpressionsOffset - (1 * kPointerSize);
+  const int kArgsOffset     =  2 * kPointerSize;
+  const int kReceiverOffset =  3 * kPointerSize;
+  const int kFunctionOffset =  4 * kPointerSize;
+
+  {
+    FrameScope frame_scope(masm, StackFrame::INTERNAL);
+
+    Register args = x12;
+    Register receiver = x14;
+    Register function = x15;
+
+    // Get the length of the arguments via a builtin call.
+    __ Ldr(function, MemOperand(fp, kFunctionOffset));
+    __ Ldr(args, MemOperand(fp, kArgsOffset));
+    __ Push(function, args);
+    __ InvokeBuiltin(Builtins::APPLY_PREPARE, CALL_FUNCTION);
+    Register argc = x0;
+
+    // Check the stack for overflow.
+    // We are not trying to catch interruptions (e.g. debug break and
+    // preemption) here, so the "real stack limit" is checked.
+    Label enough_stack_space;
+    __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
+    __ Ldr(function, MemOperand(fp, kFunctionOffset));
+    // Make x10 the space we have left. The stack might already be overflowed
+    // here which will cause x10 to become negative.
+    // TODO(jbramley): Check that the stack usage here is safe.
+    __ Sub(x10, jssp, x10);
+    // Check if the arguments will overflow the stack.
+    __ Cmp(x10, Operand::UntagSmiAndScale(argc, kPointerSizeLog2));
+    __ B(gt, &enough_stack_space);
+    // There is not enough stack space, so use a builtin to throw an appropriate
+    // error.
+    __ Push(function, argc);
+    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+    // We should never return from the APPLY_OVERFLOW builtin.
+    if (__ emit_debug_code()) {
+      __ Unreachable();
+    }
+
+    __ Bind(&enough_stack_space);
+    // Push current limit and index.
+    __ Mov(x1, 0);  // Initial index.
+    __ Push(argc, x1);
+
+    Label push_receiver;
+    __ Ldr(receiver, MemOperand(fp, kReceiverOffset));
+
+    // Check that the function is a JS function. Otherwise it must be a proxy.
+    // When it is not the function proxy will be invoked later.
+    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE,
+                           &push_receiver);
+
+    // Change context eagerly to get the right global object if necessary.
+    __ Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
+    // Load the shared function info.
+    __ Ldr(x2, FieldMemOperand(function,
+                               JSFunction::kSharedFunctionInfoOffset));
+
+    // Compute and push the receiver.
+    // Do not transform the receiver for strict mode functions.
+    Label convert_receiver_to_object, use_global_proxy;
+    __ Ldr(w10, FieldMemOperand(x2, SharedFunctionInfo::kCompilerHintsOffset));
+    __ Tbnz(x10, SharedFunctionInfo::kStrictModeFunction, &push_receiver);
+    // Do not transform the receiver for native functions.
+    __ Tbnz(x10, SharedFunctionInfo::kNative, &push_receiver);
+
+    // Compute the receiver in sloppy mode.
+    __ JumpIfSmi(receiver, &convert_receiver_to_object);
+    __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &use_global_proxy);
+    __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex,
+                  &use_global_proxy);
+
+    // Check if the receiver is already a JavaScript object.
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+    __ JumpIfObjectType(receiver, x10, x11, FIRST_SPEC_OBJECT_TYPE,
+                        &push_receiver, ge);
+
+    // Call a builtin to convert the receiver to a regular object.
+    __ Bind(&convert_receiver_to_object);
+    __ Push(receiver);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+    __ Mov(receiver, x0);
+    __ B(&push_receiver);
+
+    __ Bind(&use_global_proxy);
+    __ Ldr(x10, GlobalObjectMemOperand());
+    __ Ldr(receiver, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
+
+    // Push the receiver
+    __ Bind(&push_receiver);
+    __ Push(receiver);
+
+    // Copy all arguments from the array to the stack.
+    Label entry, loop;
+    Register current = x0;
+    __ Ldr(current, MemOperand(fp, kIndexOffset));
+    __ B(&entry);
+
+    __ Bind(&loop);
+    // Load the current argument from the arguments array and push it.
+    // TODO(all): Couldn't we optimize this for JS arrays?
+
+    __ Ldr(x1, MemOperand(fp, kArgsOffset));
+    __ Push(x1, current);
+
+    // Call the runtime to access the property in the arguments array.
+    __ CallRuntime(Runtime::kGetProperty, 2);
+    __ Push(x0);
+
+    // Use inline caching to access the arguments.
+    __ Ldr(current, MemOperand(fp, kIndexOffset));
+    __ Add(current, current, Smi::FromInt(1));
+    __ Str(current, MemOperand(fp, kIndexOffset));
+
+    // Test if the copy loop has finished copying all the elements from the
+    // arguments object.
+    __ Bind(&entry);
+    __ Ldr(x1, MemOperand(fp, kLimitOffset));
+    __ Cmp(current, x1);
+    __ B(ne, &loop);
+
+    // At the end of the loop, the number of arguments is stored in 'current',
+    // represented as a smi.
+
+    function = x1;  // From now on we want the function to be kept in x1;
+    __ Ldr(function, MemOperand(fp, kFunctionOffset));
+
+    // Call the function.
+    Label call_proxy;
+    ParameterCount actual(current);
+    __ SmiUntag(current);
+    __ JumpIfNotObjectType(function, x10, x11, JS_FUNCTION_TYPE, &call_proxy);
+    __ InvokeFunction(function, actual, CALL_FUNCTION, NullCallWrapper());
+    frame_scope.GenerateLeaveFrame();
+    __ Drop(3);
+    __ Ret();
+
+    // Call the function proxy.
+    __ Bind(&call_proxy);
+    // x0 : argc
+    // x1 : function
+    __ Push(function);  // Add function proxy as last argument.
+    __ Add(x0, x0, 1);
+    __ Mov(x2, 0);
+    __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
+    __ Call(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+            RelocInfo::CODE_TARGET);
+  }
+  __ Drop(3);
+  __ Ret();
+}
+
+
+static void ArgumentAdaptorStackCheck(MacroAssembler* masm,
+                                      Label* stack_overflow) {
+  // ----------- S t a t e -------------
+  //  -- x0 : actual number of arguments
+  //  -- x1 : function (passed through to callee)
+  //  -- x2 : expected number of arguments
+  // -----------------------------------
+  // Check the stack for overflow.
+  // We are not trying to catch interruptions (e.g. debug break and
+  // preemption) here, so the "real stack limit" is checked.
+  Label enough_stack_space;
+  __ LoadRoot(x10, Heap::kRealStackLimitRootIndex);
+  // Make x10 the space we have left. The stack might already be overflowed
+  // here which will cause x10 to become negative.
+  __ Sub(x10, jssp, x10);
+  // Check if the arguments will overflow the stack.
+  __ Cmp(x10, Operand(x2, LSL, kPointerSizeLog2));
+  __ B(le, stack_overflow);
+}
+
+
+static void EnterArgumentsAdaptorFrame(MacroAssembler* masm) {
+  __ SmiTag(x10, x0);
+  __ Mov(x11, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ Push(lr, fp);
+  __ Push(x11, x1, x10);
+  __ Add(fp, jssp,
+         StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
+}
+
+
+static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0 : result being passed through
+  // -----------------------------------
+  // Get the number of arguments passed (as a smi), tear down the frame and
+  // then drop the parameters and the receiver.
+  __ Ldr(x10, MemOperand(fp, -(StandardFrameConstants::kFixedFrameSizeFromFp +
+                               kPointerSize)));
+  __ Mov(jssp, fp);
+  __ Pop(fp, lr);
+  __ DropBySMI(x10, kXRegSize);
+  __ Drop(1);
+}
+
+
+void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) {
+  ASM_LOCATION("Builtins::Generate_ArgumentsAdaptorTrampoline");
+  // ----------- S t a t e -------------
+  //  -- x0 : actual number of arguments
+  //  -- x1 : function (passed through to callee)
+  //  -- x2 : expected number of arguments
+  // -----------------------------------
+
+  Label stack_overflow;
+  ArgumentAdaptorStackCheck(masm, &stack_overflow);
+
+  Register argc_actual = x0;  // Excluding the receiver.
+  Register argc_expected = x2;  // Excluding the receiver.
+  Register function = x1;
+  Register code_entry = x3;
+
+  Label invoke, dont_adapt_arguments;
+
+  Label enough, too_few;
+  __ Ldr(code_entry, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+  __ Cmp(argc_actual, argc_expected);
+  __ B(lt, &too_few);
+  __ Cmp(argc_expected, SharedFunctionInfo::kDontAdaptArgumentsSentinel);
+  __ B(eq, &dont_adapt_arguments);
+
+  {  // Enough parameters: actual >= expected
+    EnterArgumentsAdaptorFrame(masm);
+
+    Register copy_start = x10;
+    Register copy_end = x11;
+    Register copy_to = x12;
+    Register scratch1 = x13, scratch2 = x14;
+
+    __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
+
+    // Adjust for fp, lr, and the receiver.
+    __ Add(copy_start, fp, 3 * kPointerSize);
+    __ Add(copy_start, copy_start, Operand(argc_actual, LSL, kPointerSizeLog2));
+    __ Sub(copy_end, copy_start, argc_expected);
+    __ Sub(copy_end, copy_end, kPointerSize);
+    __ Mov(copy_to, jssp);
+
+    // Claim space for the arguments, the receiver, and one extra slot.
+    // The extra slot ensures we do not write under jssp. It will be popped
+    // later.
+    __ Add(scratch1, argc_expected, 2 * kPointerSize);
+    __ Claim(scratch1, 1);
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    Label copy_2_by_2;
+    __ Bind(&copy_2_by_2);
+    __ Ldp(scratch1, scratch2,
+           MemOperand(copy_start, - 2 * kPointerSize, PreIndex));
+    __ Stp(scratch1, scratch2,
+           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
+    __ Cmp(copy_start, copy_end);
+    __ B(hi, &copy_2_by_2);
+
+    // Correct the space allocated for the extra slot.
+    __ Drop(1);
+
+    __ B(&invoke);
+  }
+
+  {  // Too few parameters: Actual < expected
+    __ Bind(&too_few);
+    EnterArgumentsAdaptorFrame(masm);
+
+    Register copy_from = x10;
+    Register copy_end = x11;
+    Register copy_to = x12;
+    Register scratch1 = x13, scratch2 = x14;
+
+    __ Lsl(argc_expected, argc_expected, kPointerSizeLog2);
+    __ Lsl(argc_actual, argc_actual, kPointerSizeLog2);
+
+    // Adjust for fp, lr, and the receiver.
+    __ Add(copy_from, fp, 3 * kPointerSize);
+    __ Add(copy_from, copy_from, argc_actual);
+    __ Mov(copy_to, jssp);
+    __ Sub(copy_end, copy_to, 1 * kPointerSize);   // Adjust for the receiver.
+    __ Sub(copy_end, copy_end, argc_actual);
+
+    // Claim space for the arguments, the receiver, and one extra slot.
+    // The extra slot ensures we do not write under jssp. It will be popped
+    // later.
+    __ Add(scratch1, argc_expected, 2 * kPointerSize);
+    __ Claim(scratch1, 1);
+
+    // Copy the arguments (including the receiver) to the new stack frame.
+    Label copy_2_by_2;
+    __ Bind(&copy_2_by_2);
+    __ Ldp(scratch1, scratch2,
+           MemOperand(copy_from, - 2 * kPointerSize, PreIndex));
+    __ Stp(scratch1, scratch2,
+           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
+    __ Cmp(copy_to, copy_end);
+    __ B(hi, &copy_2_by_2);
+
+    __ Mov(copy_to, copy_end);
+
+    // Fill the remaining expected arguments with undefined.
+    __ LoadRoot(scratch1, Heap::kUndefinedValueRootIndex);
+    __ Add(copy_end, jssp, kPointerSize);
+
+    Label fill;
+    __ Bind(&fill);
+    __ Stp(scratch1, scratch1,
+           MemOperand(copy_to, - 2 * kPointerSize, PreIndex));
+    __ Cmp(copy_to, copy_end);
+    __ B(hi, &fill);
+
+    // Correct the space allocated for the extra slot.
+    __ Drop(1);
+  }
+
+  // Arguments have been adapted. Now call the entry point.
+  __ Bind(&invoke);
+  __ Call(code_entry);
+
+  // Store offset of return address for deoptimizer.
+  masm->isolate()->heap()->SetArgumentsAdaptorDeoptPCOffset(masm->pc_offset());
+
+  // Exit frame and return.
+  LeaveArgumentsAdaptorFrame(masm);
+  __ Ret();
+
+  // Call the entry point without adapting the arguments.
+  __ Bind(&dont_adapt_arguments);
+  __ Jump(code_entry);
+
+  __ Bind(&stack_overflow);
+  {
+    FrameScope frame(masm, StackFrame::MANUAL);
+    EnterArgumentsAdaptorFrame(masm);
+    __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+    __ Unreachable();
+  }
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM
diff --git a/src/arm64/code-stubs-arm64.cc b/src/arm64/code-stubs-arm64.cc
new file mode 100644
index 0000000..4978e5e
--- /dev/null
+++ b/src/arm64/code-stubs-arm64.cc
@@ -0,0 +1,5069 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/bootstrapper.h"
+#include "src/code-stubs.h"
+#include "src/codegen.h"
+#include "src/ic/handler-compiler.h"
+#include "src/ic/ic.h"
+#include "src/isolate.h"
+#include "src/jsregexp.h"
+#include "src/regexp-macro-assembler.h"
+#include "src/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+
+static void InitializeArrayConstructorDescriptor(
+    Isolate* isolate, CodeStubDescriptor* descriptor,
+    int constant_stack_parameter_count) {
+  // cp: context
+  // x1: function
+  // x2: allocation site with elements kind
+  // x0: number of arguments to the constructor function
+  Address deopt_handler = Runtime::FunctionForId(
+      Runtime::kArrayConstructor)->entry;
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE);
+  } else {
+    descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
+  }
+}
+
+
+void ArrayNoArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, 0);
+}
+
+
+void ArraySingleArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, 1);
+}
+
+
+void ArrayNArgumentsConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeArrayConstructorDescriptor(isolate(), descriptor, -1);
+}
+
+
+static void InitializeInternalArrayConstructorDescriptor(
+    Isolate* isolate, CodeStubDescriptor* descriptor,
+    int constant_stack_parameter_count) {
+  Address deopt_handler = Runtime::FunctionForId(
+      Runtime::kInternalArrayConstructor)->entry;
+
+  if (constant_stack_parameter_count == 0) {
+    descriptor->Initialize(deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE);
+  } else {
+    descriptor->Initialize(x0, deopt_handler, constant_stack_parameter_count,
+                           JS_FUNCTION_STUB_MODE, PASS_ARGUMENTS);
+  }
+}
+
+
+void InternalArrayNoArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 0);
+}
+
+
+void InternalArraySingleArgumentConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, 1);
+}
+
+
+void InternalArrayNArgumentsConstructorStub::InitializeDescriptor(
+    CodeStubDescriptor* descriptor) {
+  InitializeInternalArrayConstructorDescriptor(isolate(), descriptor, -1);
+}
+
+
+#define __ ACCESS_MASM(masm)
+
+
+void HydrogenCodeStub::GenerateLightweightMiss(MacroAssembler* masm,
+                                               ExternalReference miss) {
+  // Update the static counter each time a new code stub is generated.
+  isolate()->counters()->code_stubs()->Increment();
+
+  CallInterfaceDescriptor descriptor = GetCallInterfaceDescriptor();
+  int param_count = descriptor.GetEnvironmentParameterCount();
+  {
+    // Call the runtime system in a fresh internal frame.
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    DCHECK((param_count == 0) ||
+           x0.Is(descriptor.GetEnvironmentParameterRegister(param_count - 1)));
+
+    // Push arguments
+    MacroAssembler::PushPopQueue queue(masm);
+    for (int i = 0; i < param_count; ++i) {
+      queue.Queue(descriptor.GetEnvironmentParameterRegister(i));
+    }
+    queue.PushQueued();
+
+    __ CallExternalReference(miss, param_count);
+  }
+
+  __ Ret();
+}
+
+
+void DoubleToIStub::Generate(MacroAssembler* masm) {
+  Label done;
+  Register input = source();
+  Register result = destination();
+  DCHECK(is_truncating());
+
+  DCHECK(result.Is64Bits());
+  DCHECK(jssp.Is(masm->StackPointer()));
+
+  int double_offset = offset();
+
+  DoubleRegister double_scratch = d0;  // only used if !skip_fastpath()
+  Register scratch1 = GetAllocatableRegisterThatIsNotOneOf(input, result);
+  Register scratch2 =
+      GetAllocatableRegisterThatIsNotOneOf(input, result, scratch1);
+
+  __ Push(scratch1, scratch2);
+  // Account for saved regs if input is jssp.
+  if (input.is(jssp)) double_offset += 2 * kPointerSize;
+
+  if (!skip_fastpath()) {
+    __ Push(double_scratch);
+    if (input.is(jssp)) double_offset += 1 * kDoubleSize;
+    __ Ldr(double_scratch, MemOperand(input, double_offset));
+    // Try to convert with a FPU convert instruction.  This handles all
+    // non-saturating cases.
+    __ TryConvertDoubleToInt64(result, double_scratch, &done);
+    __ Fmov(result, double_scratch);
+  } else {
+    __ Ldr(result, MemOperand(input, double_offset));
+  }
+
+  // If we reach here we need to manually convert the input to an int32.
+
+  // Extract the exponent.
+  Register exponent = scratch1;
+  __ Ubfx(exponent, result, HeapNumber::kMantissaBits,
+          HeapNumber::kExponentBits);
+
+  // It the exponent is >= 84 (kMantissaBits + 32), the result is always 0 since
+  // the mantissa gets shifted completely out of the int32_t result.
+  __ Cmp(exponent, HeapNumber::kExponentBias + HeapNumber::kMantissaBits + 32);
+  __ CzeroX(result, ge);
+  __ B(ge, &done);
+
+  // The Fcvtzs sequence handles all cases except where the conversion causes
+  // signed overflow in the int64_t target. Since we've already handled
+  // exponents >= 84, we can guarantee that 63 <= exponent < 84.
+
+  if (masm->emit_debug_code()) {
+    __ Cmp(exponent, HeapNumber::kExponentBias + 63);
+    // Exponents less than this should have been handled by the Fcvt case.
+    __ Check(ge, kUnexpectedValue);
+  }
+
+  // Isolate the mantissa bits, and set the implicit '1'.
+  Register mantissa = scratch2;
+  __ Ubfx(mantissa, result, 0, HeapNumber::kMantissaBits);
+  __ Orr(mantissa, mantissa, 1UL << HeapNumber::kMantissaBits);
+
+  // Negate the mantissa if necessary.
+  __ Tst(result, kXSignMask);
+  __ Cneg(mantissa, mantissa, ne);
+
+  // Shift the mantissa bits in the correct place. We know that we have to shift
+  // it left here, because exponent >= 63 >= kMantissaBits.
+  __ Sub(exponent, exponent,
+         HeapNumber::kExponentBias + HeapNumber::kMantissaBits);
+  __ Lsl(result, mantissa, exponent);
+
+  __ Bind(&done);
+  if (!skip_fastpath()) {
+    __ Pop(double_scratch);
+  }
+  __ Pop(scratch2, scratch1);
+  __ Ret();
+}
+
+
+// See call site for description.
+static void EmitIdenticalObjectComparison(MacroAssembler* masm,
+                                          Register left,
+                                          Register right,
+                                          Register scratch,
+                                          FPRegister double_scratch,
+                                          Label* slow,
+                                          Condition cond) {
+  DCHECK(!AreAliased(left, right, scratch));
+  Label not_identical, return_equal, heap_number;
+  Register result = x0;
+
+  __ Cmp(right, left);
+  __ B(ne, &not_identical);
+
+  // Test for NaN. Sadly, we can't just compare to factory::nan_value(),
+  // so we do the second best thing - test it ourselves.
+  // They are both equal and they are not both Smis so both of them are not
+  // Smis.  If it's not a heap number, then return equal.
+  if ((cond == lt) || (cond == gt)) {
+    __ JumpIfObjectType(right, scratch, scratch, FIRST_SPEC_OBJECT_TYPE, slow,
+                        ge);
+  } else if (cond == eq) {
+    __ JumpIfHeapNumber(right, &heap_number);
+  } else {
+    Register right_type = scratch;
+    __ JumpIfObjectType(right, right_type, right_type, HEAP_NUMBER_TYPE,
+                        &heap_number);
+    // Comparing JS objects with <=, >= is complicated.
+    __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
+    __ B(ge, slow);
+    // Normally here we fall through to return_equal, but undefined is
+    // special: (undefined == undefined) == true, but
+    // (undefined <= undefined) == false!  See ECMAScript 11.8.5.
+    if ((cond == le) || (cond == ge)) {
+      __ Cmp(right_type, ODDBALL_TYPE);
+      __ B(ne, &return_equal);
+      __ JumpIfNotRoot(right, Heap::kUndefinedValueRootIndex, &return_equal);
+      if (cond == le) {
+        // undefined <= undefined should fail.
+        __ Mov(result, GREATER);
+      } else {
+        // undefined >= undefined should fail.
+        __ Mov(result, LESS);
+      }
+      __ Ret();
+    }
+  }
+
+  __ Bind(&return_equal);
+  if (cond == lt) {
+    __ Mov(result, GREATER);  // Things aren't less than themselves.
+  } else if (cond == gt) {
+    __ Mov(result, LESS);     // Things aren't greater than themselves.
+  } else {
+    __ Mov(result, EQUAL);    // Things are <=, >=, ==, === themselves.
+  }
+  __ Ret();
+
+  // Cases lt and gt have been handled earlier, and case ne is never seen, as
+  // it is handled in the parser (see Parser::ParseBinaryExpression). We are
+  // only concerned with cases ge, le and eq here.
+  if ((cond != lt) && (cond != gt)) {
+    DCHECK((cond == ge) || (cond == le) || (cond == eq));
+    __ Bind(&heap_number);
+    // Left and right are identical pointers to a heap number object. Return
+    // non-equal if the heap number is a NaN, and equal otherwise. Comparing
+    // the number to itself will set the overflow flag iff the number is NaN.
+    __ Ldr(double_scratch, FieldMemOperand(right, HeapNumber::kValueOffset));
+    __ Fcmp(double_scratch, double_scratch);
+    __ B(vc, &return_equal);  // Not NaN, so treat as normal heap number.
+
+    if (cond == le) {
+      __ Mov(result, GREATER);
+    } else {
+      __ Mov(result, LESS);
+    }
+    __ Ret();
+  }
+
+  // No fall through here.
+  if (FLAG_debug_code) {
+    __ Unreachable();
+  }
+
+  __ Bind(&not_identical);
+}
+
+
+// See call site for description.
+static void EmitStrictTwoHeapObjectCompare(MacroAssembler* masm,
+                                           Register left,
+                                           Register right,
+                                           Register left_type,
+                                           Register right_type,
+                                           Register scratch) {
+  DCHECK(!AreAliased(left, right, left_type, right_type, scratch));
+
+  if (masm->emit_debug_code()) {
+    // We assume that the arguments are not identical.
+    __ Cmp(left, right);
+    __ Assert(ne, kExpectedNonIdenticalObjects);
+  }
+
+  // If either operand is a JS object or an oddball value, then they are not
+  // equal since their pointers are different.
+  // There is no test for undetectability in strict equality.
+  STATIC_ASSERT(LAST_TYPE == LAST_SPEC_OBJECT_TYPE);
+  Label right_non_object;
+
+  __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
+  __ B(lt, &right_non_object);
+
+  // Return non-zero - x0 already contains a non-zero pointer.
+  DCHECK(left.is(x0) || right.is(x0));
+  Label return_not_equal;
+  __ Bind(&return_not_equal);
+  __ Ret();
+
+  __ Bind(&right_non_object);
+
+  // Check for oddballs: true, false, null, undefined.
+  __ Cmp(right_type, ODDBALL_TYPE);
+
+  // If right is not ODDBALL, test left. Otherwise, set eq condition.
+  __ Ccmp(left_type, ODDBALL_TYPE, ZFlag, ne);
+
+  // If right or left is not ODDBALL, test left >= FIRST_SPEC_OBJECT_TYPE.
+  // Otherwise, right or left is ODDBALL, so set a ge condition.
+  __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NVFlag, ne);
+
+  __ B(ge, &return_not_equal);
+
+  // Internalized strings are unique, so they can only be equal if they are the
+  // same object. We have already tested that case, so if left and right are
+  // both internalized strings, they cannot be equal.
+  STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
+  __ Orr(scratch, left_type, right_type);
+  __ TestAndBranchIfAllClear(
+      scratch, kIsNotStringMask | kIsNotInternalizedMask, &return_not_equal);
+}
+
+
+// See call site for description.
+static void EmitSmiNonsmiComparison(MacroAssembler* masm,
+                                    Register left,
+                                    Register right,
+                                    FPRegister left_d,
+                                    FPRegister right_d,
+                                    Label* slow,
+                                    bool strict) {
+  DCHECK(!AreAliased(left_d, right_d));
+  DCHECK((left.is(x0) && right.is(x1)) ||
+         (right.is(x0) && left.is(x1)));
+  Register result = x0;
+
+  Label right_is_smi, done;
+  __ JumpIfSmi(right, &right_is_smi);
+
+  // Left is the smi. Check whether right is a heap number.
+  if (strict) {
+    // If right is not a number and left is a smi, then strict equality cannot
+    // succeed. Return non-equal.
+    Label is_heap_number;
+    __ JumpIfHeapNumber(right, &is_heap_number);
+    // Register right is a non-zero pointer, which is a valid NOT_EQUAL result.
+    if (!right.is(result)) {
+      __ Mov(result, NOT_EQUAL);
+    }
+    __ Ret();
+    __ Bind(&is_heap_number);
+  } else {
+    // Smi compared non-strictly with a non-smi, non-heap-number. Call the
+    // runtime.
+    __ JumpIfNotHeapNumber(right, slow);
+  }
+
+  // Left is the smi. Right is a heap number. Load right value into right_d, and
+  // convert left smi into double in left_d.
+  __ Ldr(right_d, FieldMemOperand(right, HeapNumber::kValueOffset));
+  __ SmiUntagToDouble(left_d, left);
+  __ B(&done);
+
+  __ Bind(&right_is_smi);
+  // Right is a smi. Check whether the non-smi left is a heap number.
+  if (strict) {
+    // If left is not a number and right is a smi then strict equality cannot
+    // succeed. Return non-equal.
+    Label is_heap_number;
+    __ JumpIfHeapNumber(left, &is_heap_number);
+    // Register left is a non-zero pointer, which is a valid NOT_EQUAL result.
+    if (!left.is(result)) {
+      __ Mov(result, NOT_EQUAL);
+    }
+    __ Ret();
+    __ Bind(&is_heap_number);
+  } else {
+    // Smi compared non-strictly with a non-smi, non-heap-number. Call the
+    // runtime.
+    __ JumpIfNotHeapNumber(left, slow);
+  }
+
+  // Right is the smi. Left is a heap number. Load left value into left_d, and
+  // convert right smi into double in right_d.
+  __ Ldr(left_d, FieldMemOperand(left, HeapNumber::kValueOffset));
+  __ SmiUntagToDouble(right_d, right);
+
+  // Fall through to both_loaded_as_doubles.
+  __ Bind(&done);
+}
+
+
+// Fast negative check for internalized-to-internalized equality.
+// See call site for description.
+static void EmitCheckForInternalizedStringsOrObjects(MacroAssembler* masm,
+                                                     Register left,
+                                                     Register right,
+                                                     Register left_map,
+                                                     Register right_map,
+                                                     Register left_type,
+                                                     Register right_type,
+                                                     Label* possible_strings,
+                                                     Label* not_both_strings) {
+  DCHECK(!AreAliased(left, right, left_map, right_map, left_type, right_type));
+  Register result = x0;
+
+  Label object_test;
+  STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
+  // TODO(all): reexamine this branch sequence for optimisation wrt branch
+  // prediction.
+  __ Tbnz(right_type, MaskToBit(kIsNotStringMask), &object_test);
+  __ Tbnz(right_type, MaskToBit(kIsNotInternalizedMask), possible_strings);
+  __ Tbnz(left_type, MaskToBit(kIsNotStringMask), not_both_strings);
+  __ Tbnz(left_type, MaskToBit(kIsNotInternalizedMask), possible_strings);
+
+  // Both are internalized. We already checked that they weren't the same
+  // pointer, so they are not equal.
+  __ Mov(result, NOT_EQUAL);
+  __ Ret();
+
+  __ Bind(&object_test);
+
+  __ Cmp(right_type, FIRST_SPEC_OBJECT_TYPE);
+
+  // If right >= FIRST_SPEC_OBJECT_TYPE, test left.
+  // Otherwise, right < FIRST_SPEC_OBJECT_TYPE, so set lt condition.
+  __ Ccmp(left_type, FIRST_SPEC_OBJECT_TYPE, NFlag, ge);
+
+  __ B(lt, not_both_strings);
+
+  // If both objects are undetectable, they are equal. Otherwise, they are not
+  // equal, since they are different objects and an object is not equal to
+  // undefined.
+
+  // Returning here, so we can corrupt right_type and left_type.
+  Register right_bitfield = right_type;
+  Register left_bitfield = left_type;
+  __ Ldrb(right_bitfield, FieldMemOperand(right_map, Map::kBitFieldOffset));
+  __ Ldrb(left_bitfield, FieldMemOperand(left_map, Map::kBitFieldOffset));
+  __ And(result, right_bitfield, left_bitfield);
+  __ And(result, result, 1 << Map::kIsUndetectable);
+  __ Eor(result, result, 1 << Map::kIsUndetectable);
+  __ Ret();
+}
+
+
+static void CompareICStub_CheckInputType(MacroAssembler* masm, Register input,
+                                         CompareICState::State expected,
+                                         Label* fail) {
+  Label ok;
+  if (expected == CompareICState::SMI) {
+    __ JumpIfNotSmi(input, fail);
+  } else if (expected == CompareICState::NUMBER) {
+    __ JumpIfSmi(input, &ok);
+    __ JumpIfNotHeapNumber(input, fail);
+  }
+  // We could be strict about internalized/non-internalized here, but as long as
+  // hydrogen doesn't care, the stub doesn't have to care either.
+  __ Bind(&ok);
+}
+
+
+void CompareICStub::GenerateGeneric(MacroAssembler* masm) {
+  Register lhs = x1;
+  Register rhs = x0;
+  Register result = x0;
+  Condition cond = GetCondition();
+
+  Label miss;
+  CompareICStub_CheckInputType(masm, lhs, left(), &miss);
+  CompareICStub_CheckInputType(masm, rhs, right(), &miss);
+
+  Label slow;  // Call builtin.
+  Label not_smis, both_loaded_as_doubles;
+  Label not_two_smis, smi_done;
+  __ JumpIfEitherNotSmi(lhs, rhs, &not_two_smis);
+  __ SmiUntag(lhs);
+  __ Sub(result, lhs, Operand::UntagSmi(rhs));
+  __ Ret();
+
+  __ Bind(&not_two_smis);
+
+  // NOTICE! This code is only reached after a smi-fast-case check, so it is
+  // certain that at least one operand isn't a smi.
+
+  // Handle the case where the objects are identical. Either returns the answer
+  // or goes to slow. Only falls through if the objects were not identical.
+  EmitIdenticalObjectComparison(masm, lhs, rhs, x10, d0, &slow, cond);
+
+  // If either is a smi (we know that at least one is not a smi), then they can
+  // only be strictly equal if the other is a HeapNumber.
+  __ JumpIfBothNotSmi(lhs, rhs, &not_smis);
+
+  // Exactly one operand is a smi. EmitSmiNonsmiComparison generates code that
+  // can:
+  //  1) Return the answer.
+  //  2) Branch to the slow case.
+  //  3) Fall through to both_loaded_as_doubles.
+  // In case 3, we have found out that we were dealing with a number-number
+  // comparison. The double values of the numbers have been loaded, right into
+  // rhs_d, left into lhs_d.
+  FPRegister rhs_d = d0;
+  FPRegister lhs_d = d1;
+  EmitSmiNonsmiComparison(masm, lhs, rhs, lhs_d, rhs_d, &slow, strict());
+
+  __ Bind(&both_loaded_as_doubles);
+  // The arguments have been converted to doubles and stored in rhs_d and
+  // lhs_d.
+  Label nan;
+  __ Fcmp(lhs_d, rhs_d);
+  __ B(vs, &nan);  // Overflow flag set if either is NaN.
+  STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1));
+  __ Cset(result, gt);  // gt => 1, otherwise (lt, eq) => 0 (EQUAL).
+  __ Csinv(result, result, xzr, ge);  // lt => -1, gt => 1, eq => 0.
+  __ Ret();
+
+  __ Bind(&nan);
+  // Left and/or right is a NaN. Load the result register with whatever makes
+  // the comparison fail, since comparisons with NaN always fail (except ne,
+  // which is filtered out at a higher level.)
+  DCHECK(cond != ne);
+  if ((cond == lt) || (cond == le)) {
+    __ Mov(result, GREATER);
+  } else {
+    __ Mov(result, LESS);
+  }
+  __ Ret();
+
+  __ Bind(&not_smis);
+  // At this point we know we are dealing with two different objects, and
+  // neither of them is a smi. The objects are in rhs_ and lhs_.
+
+  // Load the maps and types of the objects.
+  Register rhs_map = x10;
+  Register rhs_type = x11;
+  Register lhs_map = x12;
+  Register lhs_type = x13;
+  __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
+  __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
+
+  if (strict()) {
+    // This emits a non-equal return sequence for some object types, or falls
+    // through if it was not lucky.
+    EmitStrictTwoHeapObjectCompare(masm, lhs, rhs, lhs_type, rhs_type, x14);
+  }
+
+  Label check_for_internalized_strings;
+  Label flat_string_check;
+  // Check for heap number comparison. Branch to earlier double comparison code
+  // if they are heap numbers, otherwise, branch to internalized string check.
+  __ Cmp(rhs_type, HEAP_NUMBER_TYPE);
+  __ B(ne, &check_for_internalized_strings);
+  __ Cmp(lhs_map, rhs_map);
+
+  // If maps aren't equal, lhs_ and rhs_ are not heap numbers. Branch to flat
+  // string check.
+  __ B(ne, &flat_string_check);
+
+  // Both lhs_ and rhs_ are heap numbers. Load them and branch to the double
+  // comparison code.
+  __ Ldr(lhs_d, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+  __ Ldr(rhs_d, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+  __ B(&both_loaded_as_doubles);
+
+  __ Bind(&check_for_internalized_strings);
+  // In the strict case, the EmitStrictTwoHeapObjectCompare already took care
+  // of internalized strings.
+  if ((cond == eq) && !strict()) {
+    // Returns an answer for two internalized strings or two detectable objects.
+    // Otherwise branches to the string case or not both strings case.
+    EmitCheckForInternalizedStringsOrObjects(masm, lhs, rhs, lhs_map, rhs_map,
+                                             lhs_type, rhs_type,
+                                             &flat_string_check, &slow);
+  }
+
+  // Check for both being sequential one-byte strings,
+  // and inline if that is the case.
+  __ Bind(&flat_string_check);
+  __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x14,
+                                                    x15, &slow);
+
+  __ IncrementCounter(isolate()->counters()->string_compare_native(), 1, x10,
+                      x11);
+  if (cond == eq) {
+    StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11,
+                                                  x12);
+  } else {
+    StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11,
+                                                    x12, x13);
+  }
+
+  // Never fall through to here.
+  if (FLAG_debug_code) {
+    __ Unreachable();
+  }
+
+  __ Bind(&slow);
+
+  __ Push(lhs, rhs);
+  // Figure out which native to call and setup the arguments.
+  Builtins::JavaScript native;
+  if (cond == eq) {
+    native = strict() ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
+  } else {
+    native = Builtins::COMPARE;
+    int ncr;  // NaN compare result
+    if ((cond == lt) || (cond == le)) {
+      ncr = GREATER;
+    } else {
+      DCHECK((cond == gt) || (cond == ge));  // remaining cases
+      ncr = LESS;
+    }
+    __ Mov(x10, Smi::FromInt(ncr));
+    __ Push(x10);
+  }
+
+  // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
+  // tagged as a small integer.
+  __ InvokeBuiltin(native, JUMP_FUNCTION);
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
+  CPURegList saved_regs = kCallerSaved;
+  CPURegList saved_fp_regs = kCallerSavedFP;
+
+  // We don't allow a GC during a store buffer overflow so there is no need to
+  // store the registers in any particular way, but we do have to store and
+  // restore them.
+
+  // We don't care if MacroAssembler scratch registers are corrupted.
+  saved_regs.Remove(*(masm->TmpList()));
+  saved_fp_regs.Remove(*(masm->FPTmpList()));
+
+  __ PushCPURegList(saved_regs);
+  if (save_doubles()) {
+    __ PushCPURegList(saved_fp_regs);
+  }
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  __ Mov(x0, ExternalReference::isolate_address(isolate()));
+  __ CallCFunction(
+      ExternalReference::store_buffer_overflow_function(isolate()), 1, 0);
+
+  if (save_doubles()) {
+    __ PopCPURegList(saved_fp_regs);
+  }
+  __ PopCPURegList(saved_regs);
+  __ Ret();
+}
+
+
+void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
+    Isolate* isolate) {
+  StoreBufferOverflowStub stub1(isolate, kDontSaveFPRegs);
+  stub1.GetCode();
+  StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
+  stub2.GetCode();
+}
+
+
+void StoreRegistersStateStub::Generate(MacroAssembler* masm) {
+  MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
+  UseScratchRegisterScope temps(masm);
+  Register saved_lr = temps.UnsafeAcquire(to_be_pushed_lr());
+  Register return_address = temps.AcquireX();
+  __ Mov(return_address, lr);
+  // Restore lr with the value it had before the call to this stub (the value
+  // which must be pushed).
+  __ Mov(lr, saved_lr);
+  __ PushSafepointRegisters();
+  __ Ret(return_address);
+}
+
+
+void RestoreRegistersStateStub::Generate(MacroAssembler* masm) {
+  MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
+  UseScratchRegisterScope temps(masm);
+  Register return_address = temps.AcquireX();
+  // Preserve the return address (lr will be clobbered by the pop).
+  __ Mov(return_address, lr);
+  __ PopSafepointRegisters();
+  __ Ret(return_address);
+}
+
+
+void MathPowStub::Generate(MacroAssembler* masm) {
+  // Stack on entry:
+  // jssp[0]: Exponent (as a tagged value).
+  // jssp[1]: Base (as a tagged value).
+  //
+  // The (tagged) result will be returned in x0, as a heap number.
+
+  Register result_tagged = x0;
+  Register base_tagged = x10;
+  Register exponent_tagged = MathPowTaggedDescriptor::exponent();
+  DCHECK(exponent_tagged.is(x11));
+  Register exponent_integer = MathPowIntegerDescriptor::exponent();
+  DCHECK(exponent_integer.is(x12));
+  Register scratch1 = x14;
+  Register scratch0 = x15;
+  Register saved_lr = x19;
+  FPRegister result_double = d0;
+  FPRegister base_double = d0;
+  FPRegister exponent_double = d1;
+  FPRegister base_double_copy = d2;
+  FPRegister scratch1_double = d6;
+  FPRegister scratch0_double = d7;
+
+  // A fast-path for integer exponents.
+  Label exponent_is_smi, exponent_is_integer;
+  // Bail out to runtime.
+  Label call_runtime;
+  // Allocate a heap number for the result, and return it.
+  Label done;
+
+  // Unpack the inputs.
+  if (exponent_type() == ON_STACK) {
+    Label base_is_smi;
+    Label unpack_exponent;
+
+    __ Pop(exponent_tagged, base_tagged);
+
+    __ JumpIfSmi(base_tagged, &base_is_smi);
+    __ JumpIfNotHeapNumber(base_tagged, &call_runtime);
+    // base_tagged is a heap number, so load its double value.
+    __ Ldr(base_double, FieldMemOperand(base_tagged, HeapNumber::kValueOffset));
+    __ B(&unpack_exponent);
+    __ Bind(&base_is_smi);
+    // base_tagged is a SMI, so untag it and convert it to a double.
+    __ SmiUntagToDouble(base_double, base_tagged);
+
+    __ Bind(&unpack_exponent);
+    //  x10   base_tagged       The tagged base (input).
+    //  x11   exponent_tagged   The tagged exponent (input).
+    //  d1    base_double       The base as a double.
+    __ JumpIfSmi(exponent_tagged, &exponent_is_smi);
+    __ JumpIfNotHeapNumber(exponent_tagged, &call_runtime);
+    // exponent_tagged is a heap number, so load its double value.
+    __ Ldr(exponent_double,
+           FieldMemOperand(exponent_tagged, HeapNumber::kValueOffset));
+  } else if (exponent_type() == TAGGED) {
+    __ JumpIfSmi(exponent_tagged, &exponent_is_smi);
+    __ Ldr(exponent_double,
+           FieldMemOperand(exponent_tagged, HeapNumber::kValueOffset));
+  }
+
+  // Handle double (heap number) exponents.
+  if (exponent_type() != INTEGER) {
+    // Detect integer exponents stored as doubles and handle those in the
+    // integer fast-path.
+    __ TryRepresentDoubleAsInt64(exponent_integer, exponent_double,
+                                 scratch0_double, &exponent_is_integer);
+
+    if (exponent_type() == ON_STACK) {
+      FPRegister  half_double = d3;
+      FPRegister  minus_half_double = d4;
+      // Detect square root case. Crankshaft detects constant +/-0.5 at compile
+      // time and uses DoMathPowHalf instead. We then skip this check for
+      // non-constant cases of +/-0.5 as these hardly occur.
+
+      __ Fmov(minus_half_double, -0.5);
+      __ Fmov(half_double, 0.5);
+      __ Fcmp(minus_half_double, exponent_double);
+      __ Fccmp(half_double, exponent_double, NZFlag, ne);
+      // Condition flags at this point:
+      //    0.5;  nZCv    // Identified by eq && pl
+      //   -0.5:  NZcv    // Identified by eq && mi
+      //  other:  ?z??    // Identified by ne
+      __ B(ne, &call_runtime);
+
+      // The exponent is 0.5 or -0.5.
+
+      // Given that exponent is known to be either 0.5 or -0.5, the following
+      // special cases could apply (according to ECMA-262 15.8.2.13):
+      //
+      //  base.isNaN():                   The result is NaN.
+      //  (base == +INFINITY) || (base == -INFINITY)
+      //    exponent == 0.5:              The result is +INFINITY.
+      //    exponent == -0.5:             The result is +0.
+      //  (base == +0) || (base == -0)
+      //    exponent == 0.5:              The result is +0.
+      //    exponent == -0.5:             The result is +INFINITY.
+      //  (base < 0) && base.isFinite():  The result is NaN.
+      //
+      // Fsqrt (and Fdiv for the -0.5 case) can handle all of those except
+      // where base is -INFINITY or -0.
+
+      // Add +0 to base. This has no effect other than turning -0 into +0.
+      __ Fadd(base_double, base_double, fp_zero);
+      // The operation -0+0 results in +0 in all cases except where the
+      // FPCR rounding mode is 'round towards minus infinity' (RM). The
+      // ARM64 simulator does not currently simulate FPCR (where the rounding
+      // mode is set), so test the operation with some debug code.
+      if (masm->emit_debug_code()) {
+        UseScratchRegisterScope temps(masm);
+        Register temp = temps.AcquireX();
+        __ Fneg(scratch0_double, fp_zero);
+        // Verify that we correctly generated +0.0 and -0.0.
+        //  bits(+0.0) = 0x0000000000000000
+        //  bits(-0.0) = 0x8000000000000000
+        __ Fmov(temp, fp_zero);
+        __ CheckRegisterIsClear(temp, kCouldNotGenerateZero);
+        __ Fmov(temp, scratch0_double);
+        __ Eor(temp, temp, kDSignMask);
+        __ CheckRegisterIsClear(temp, kCouldNotGenerateNegativeZero);
+        // Check that -0.0 + 0.0 == +0.0.
+        __ Fadd(scratch0_double, scratch0_double, fp_zero);
+        __ Fmov(temp, scratch0_double);
+        __ CheckRegisterIsClear(temp, kExpectedPositiveZero);
+      }
+
+      // If base is -INFINITY, make it +INFINITY.
+      //  * Calculate base - base: All infinities will become NaNs since both
+      //    -INFINITY+INFINITY and +INFINITY-INFINITY are NaN in ARM64.
+      //  * If the result is NaN, calculate abs(base).
+      __ Fsub(scratch0_double, base_double, base_double);
+      __ Fcmp(scratch0_double, 0.0);
+      __ Fabs(scratch1_double, base_double);
+      __ Fcsel(base_double, scratch1_double, base_double, vs);
+
+      // Calculate the square root of base.
+      __ Fsqrt(result_double, base_double);
+      __ Fcmp(exponent_double, 0.0);
+      __ B(ge, &done);  // Finish now for exponents of 0.5.
+      // Find the inverse for exponents of -0.5.
+      __ Fmov(scratch0_double, 1.0);
+      __ Fdiv(result_double, scratch0_double, result_double);
+      __ B(&done);
+    }
+
+    {
+      AllowExternalCallThatCantCauseGC scope(masm);
+      __ Mov(saved_lr, lr);
+      __ CallCFunction(
+          ExternalReference::power_double_double_function(isolate()),
+          0, 2);
+      __ Mov(lr, saved_lr);
+      __ B(&done);
+    }
+
+    // Handle SMI exponents.
+    __ Bind(&exponent_is_smi);
+    //  x10   base_tagged       The tagged base (input).
+    //  x11   exponent_tagged   The tagged exponent (input).
+    //  d1    base_double       The base as a double.
+    __ SmiUntag(exponent_integer, exponent_tagged);
+  }
+
+  __ Bind(&exponent_is_integer);
+  //  x10   base_tagged       The tagged base (input).
+  //  x11   exponent_tagged   The tagged exponent (input).
+  //  x12   exponent_integer  The exponent as an integer.
+  //  d1    base_double       The base as a double.
+
+  // Find abs(exponent). For negative exponents, we can find the inverse later.
+  Register exponent_abs = x13;
+  __ Cmp(exponent_integer, 0);
+  __ Cneg(exponent_abs, exponent_integer, mi);
+  //  x13   exponent_abs      The value of abs(exponent_integer).
+
+  // Repeatedly multiply to calculate the power.
+  //  result = 1.0;
+  //  For each bit n (exponent_integer{n}) {
+  //    if (exponent_integer{n}) {
+  //      result *= base;
+  //    }
+  //    base *= base;
+  //    if (remaining bits in exponent_integer are all zero) {
+  //      break;
+  //    }
+  //  }
+  Label power_loop, power_loop_entry, power_loop_exit;
+  __ Fmov(scratch1_double, base_double);
+  __ Fmov(base_double_copy, base_double);
+  __ Fmov(result_double, 1.0);
+  __ B(&power_loop_entry);
+
+  __ Bind(&power_loop);
+  __ Fmul(scratch1_double, scratch1_double, scratch1_double);
+  __ Lsr(exponent_abs, exponent_abs, 1);
+  __ Cbz(exponent_abs, &power_loop_exit);
+
+  __ Bind(&power_loop_entry);
+  __ Tbz(exponent_abs, 0, &power_loop);
+  __ Fmul(result_double, result_double, scratch1_double);
+  __ B(&power_loop);
+
+  __ Bind(&power_loop_exit);
+
+  // If the exponent was positive, result_double holds the result.
+  __ Tbz(exponent_integer, kXSignBit, &done);
+
+  // The exponent was negative, so find the inverse.
+  __ Fmov(scratch0_double, 1.0);
+  __ Fdiv(result_double, scratch0_double, result_double);
+  // ECMA-262 only requires Math.pow to return an 'implementation-dependent
+  // approximation' of base^exponent. However, mjsunit/math-pow uses Math.pow
+  // to calculate the subnormal value 2^-1074. This method of calculating
+  // negative powers doesn't work because 2^1074 overflows to infinity. To
+  // catch this corner-case, we bail out if the result was 0. (This can only
+  // occur if the divisor is infinity or the base is zero.)
+  __ Fcmp(result_double, 0.0);
+  __ B(&done, ne);
+
+  if (exponent_type() == ON_STACK) {
+    // Bail out to runtime code.
+    __ Bind(&call_runtime);
+    // Put the arguments back on the stack.
+    __ Push(base_tagged, exponent_tagged);
+    __ TailCallRuntime(Runtime::kMathPowRT, 2, 1);
+
+    // Return.
+    __ Bind(&done);
+    __ AllocateHeapNumber(result_tagged, &call_runtime, scratch0, scratch1,
+                          result_double);
+    DCHECK(result_tagged.is(x0));
+    __ IncrementCounter(
+        isolate()->counters()->math_pow(), 1, scratch0, scratch1);
+    __ Ret();
+  } else {
+    AllowExternalCallThatCantCauseGC scope(masm);
+    __ Mov(saved_lr, lr);
+    __ Fmov(base_double, base_double_copy);
+    __ Scvtf(exponent_double, exponent_integer);
+    __ CallCFunction(
+        ExternalReference::power_double_double_function(isolate()),
+        0, 2);
+    __ Mov(lr, saved_lr);
+    __ Bind(&done);
+    __ IncrementCounter(
+        isolate()->counters()->math_pow(), 1, scratch0, scratch1);
+    __ Ret();
+  }
+}
+
+
+void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
+  // It is important that the following stubs are generated in this order
+  // because pregenerated stubs can only call other pregenerated stubs.
+  // RecordWriteStub uses StoreBufferOverflowStub, which in turn uses
+  // CEntryStub.
+  CEntryStub::GenerateAheadOfTime(isolate);
+  StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(isolate);
+  StubFailureTrampolineStub::GenerateAheadOfTime(isolate);
+  ArrayConstructorStubBase::GenerateStubsAheadOfTime(isolate);
+  CreateAllocationSiteStub::GenerateAheadOfTime(isolate);
+  BinaryOpICStub::GenerateAheadOfTime(isolate);
+  StoreRegistersStateStub::GenerateAheadOfTime(isolate);
+  RestoreRegistersStateStub::GenerateAheadOfTime(isolate);
+  BinaryOpICWithAllocationSiteStub::GenerateAheadOfTime(isolate);
+}
+
+
+void StoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
+  StoreRegistersStateStub stub(isolate);
+  stub.GetCode();
+}
+
+
+void RestoreRegistersStateStub::GenerateAheadOfTime(Isolate* isolate) {
+  RestoreRegistersStateStub stub(isolate);
+  stub.GetCode();
+}
+
+
+void CodeStub::GenerateFPStubs(Isolate* isolate) {
+  // Floating-point code doesn't get special handling in ARM64, so there's
+  // nothing to do here.
+  USE(isolate);
+}
+
+
+bool CEntryStub::NeedsImmovableCode() {
+  // CEntryStub stores the return address on the stack before calling into
+  // C++ code. In some cases, the VM accesses this address, but it is not used
+  // when the C++ code returns to the stub because LR holds the return address
+  // in AAPCS64. If the stub is moved (perhaps during a GC), we could end up
+  // returning to dead code.
+  // TODO(jbramley): Whilst this is the only analysis that makes sense, I can't
+  // find any comment to confirm this, and I don't hit any crashes whatever
+  // this function returns. The anaylsis should be properly confirmed.
+  return true;
+}
+
+
+void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
+  CEntryStub stub(isolate, 1, kDontSaveFPRegs);
+  stub.GetCode();
+  CEntryStub stub_fp(isolate, 1, kSaveFPRegs);
+  stub_fp.GetCode();
+}
+
+
+void CEntryStub::Generate(MacroAssembler* masm) {
+  // The Abort mechanism relies on CallRuntime, which in turn relies on
+  // CEntryStub, so until this stub has been generated, we have to use a
+  // fall-back Abort mechanism.
+  //
+  // Note that this stub must be generated before any use of Abort.
+  MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
+
+  ASM_LOCATION("CEntryStub::Generate entry");
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  // Register parameters:
+  //    x0: argc (including receiver, untagged)
+  //    x1: target
+  //
+  // The stack on entry holds the arguments and the receiver, with the receiver
+  // at the highest address:
+  //
+  //    jssp]argc-1]: receiver
+  //    jssp[argc-2]: arg[argc-2]
+  //    ...           ...
+  //    jssp[1]:      arg[1]
+  //    jssp[0]:      arg[0]
+  //
+  // The arguments are in reverse order, so that arg[argc-2] is actually the
+  // first argument to the target function and arg[0] is the last.
+  DCHECK(jssp.Is(__ StackPointer()));
+  const Register& argc_input = x0;
+  const Register& target_input = x1;
+
+  // Calculate argv, argc and the target address, and store them in
+  // callee-saved registers so we can retry the call without having to reload
+  // these arguments.
+  // TODO(jbramley): If the first call attempt succeeds in the common case (as
+  // it should), then we might be better off putting these parameters directly
+  // into their argument registers, rather than using callee-saved registers and
+  // preserving them on the stack.
+  const Register& argv = x21;
+  const Register& argc = x22;
+  const Register& target = x23;
+
+  // Derive argv from the stack pointer so that it points to the first argument
+  // (arg[argc-2]), or just below the receiver in case there are no arguments.
+  //  - Adjust for the arg[] array.
+  Register temp_argv = x11;
+  __ Add(temp_argv, jssp, Operand(x0, LSL, kPointerSizeLog2));
+  //  - Adjust for the receiver.
+  __ Sub(temp_argv, temp_argv, 1 * kPointerSize);
+
+  // Enter the exit frame. Reserve three slots to preserve x21-x23 callee-saved
+  // registers.
+  FrameScope scope(masm, StackFrame::MANUAL);
+  __ EnterExitFrame(save_doubles(), x10, 3);
+  DCHECK(csp.Is(__ StackPointer()));
+
+  // Poke callee-saved registers into reserved space.
+  __ Poke(argv, 1 * kPointerSize);
+  __ Poke(argc, 2 * kPointerSize);
+  __ Poke(target, 3 * kPointerSize);
+
+  // We normally only keep tagged values in callee-saved registers, as they
+  // could be pushed onto the stack by called stubs and functions, and on the
+  // stack they can confuse the GC. However, we're only calling C functions
+  // which can push arbitrary data onto the stack anyway, and so the GC won't
+  // examine that part of the stack.
+  __ Mov(argc, argc_input);
+  __ Mov(target, target_input);
+  __ Mov(argv, temp_argv);
+
+  // x21 : argv
+  // x22 : argc
+  // x23 : call target
+  //
+  // The stack (on entry) holds the arguments and the receiver, with the
+  // receiver at the highest address:
+  //
+  //         argv[8]:     receiver
+  // argv -> argv[0]:     arg[argc-2]
+  //         ...          ...
+  //         argv[...]:   arg[1]
+  //         argv[...]:   arg[0]
+  //
+  // Immediately below (after) this is the exit frame, as constructed by
+  // EnterExitFrame:
+  //         fp[8]:    CallerPC (lr)
+  //   fp -> fp[0]:    CallerFP (old fp)
+  //         fp[-8]:   Space reserved for SPOffset.
+  //         fp[-16]:  CodeObject()
+  //         csp[...]: Saved doubles, if saved_doubles is true.
+  //         csp[32]:  Alignment padding, if necessary.
+  //         csp[24]:  Preserved x23 (used for target).
+  //         csp[16]:  Preserved x22 (used for argc).
+  //         csp[8]:   Preserved x21 (used for argv).
+  //  csp -> csp[0]:   Space reserved for the return address.
+  //
+  // After a successful call, the exit frame, preserved registers (x21-x23) and
+  // the arguments (including the receiver) are dropped or popped as
+  // appropriate. The stub then returns.
+  //
+  // After an unsuccessful call, the exit frame and suchlike are left
+  // untouched, and the stub either throws an exception by jumping to one of
+  // the exception_returned label.
+
+  DCHECK(csp.Is(__ StackPointer()));
+
+  // Prepare AAPCS64 arguments to pass to the builtin.
+  __ Mov(x0, argc);
+  __ Mov(x1, argv);
+  __ Mov(x2, ExternalReference::isolate_address(isolate()));
+
+  Label return_location;
+  __ Adr(x12, &return_location);
+  __ Poke(x12, 0);
+
+  if (__ emit_debug_code()) {
+    // Verify that the slot below fp[kSPOffset]-8 points to the return location
+    // (currently in x12).
+    UseScratchRegisterScope temps(masm);
+    Register temp = temps.AcquireX();
+    __ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset));
+    __ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSize)));
+    __ Cmp(temp, x12);
+    __ Check(eq, kReturnAddressNotFoundInFrame);
+  }
+
+  // Call the builtin.
+  __ Blr(target);
+  __ Bind(&return_location);
+
+  //  x0    result      The return code from the call.
+  //  x21   argv
+  //  x22   argc
+  //  x23   target
+  const Register& result = x0;
+
+  // Check result for exception sentinel.
+  Label exception_returned;
+  __ CompareRoot(result, Heap::kExceptionRootIndex);
+  __ B(eq, &exception_returned);
+
+  // The call succeeded, so unwind the stack and return.
+
+  // Restore callee-saved registers x21-x23.
+  __ Mov(x11, argc);
+
+  __ Peek(argv, 1 * kPointerSize);
+  __ Peek(argc, 2 * kPointerSize);
+  __ Peek(target, 3 * kPointerSize);
+
+  __ LeaveExitFrame(save_doubles(), x10, true);
+  DCHECK(jssp.Is(__ StackPointer()));
+  // Pop or drop the remaining stack slots and return from the stub.
+  //         jssp[24]:    Arguments array (of size argc), including receiver.
+  //         jssp[16]:    Preserved x23 (used for target).
+  //         jssp[8]:     Preserved x22 (used for argc).
+  //         jssp[0]:     Preserved x21 (used for argv).
+  __ Drop(x11);
+  __ AssertFPCRState();
+  __ Ret();
+
+  // The stack pointer is still csp if we aren't returning, and the frame
+  // hasn't changed (except for the return address).
+  __ SetStackPointer(csp);
+
+  // Handling of exception.
+  __ Bind(&exception_returned);
+
+  // Retrieve the pending exception.
+  ExternalReference pending_exception_address(
+      Isolate::kPendingExceptionAddress, isolate());
+  const Register& exception = result;
+  const Register& exception_address = x11;
+  __ Mov(exception_address, Operand(pending_exception_address));
+  __ Ldr(exception, MemOperand(exception_address));
+
+  // Clear the pending exception.
+  __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
+  __ Str(x10, MemOperand(exception_address));
+
+  //  x0    exception   The exception descriptor.
+  //  x21   argv
+  //  x22   argc
+  //  x23   target
+
+  // Special handling of termination exceptions, which are uncatchable by
+  // JavaScript code.
+  Label throw_termination_exception;
+  __ Cmp(exception, Operand(isolate()->factory()->termination_exception()));
+  __ B(eq, &throw_termination_exception);
+
+  // We didn't execute a return case, so the stack frame hasn't been updated
+  // (except for the return address slot). However, we don't need to initialize
+  // jssp because the throw method will immediately overwrite it when it
+  // unwinds the stack.
+  __ SetStackPointer(jssp);
+
+  ASM_LOCATION("Throw normal");
+  __ Mov(argv, 0);
+  __ Mov(argc, 0);
+  __ Mov(target, 0);
+  __ Throw(x0, x10, x11, x12, x13);
+
+  __ Bind(&throw_termination_exception);
+  ASM_LOCATION("Throw termination");
+  __ Mov(argv, 0);
+  __ Mov(argc, 0);
+  __ Mov(target, 0);
+  __ ThrowUncatchable(x0, x10, x11, x12, x13);
+}
+
+
+// This is the entry point from C++. 5 arguments are provided in x0-x4.
+// See use of the CALL_GENERATED_CODE macro for example in src/execution.cc.
+// Input:
+//   x0: code entry.
+//   x1: function.
+//   x2: receiver.
+//   x3: argc.
+//   x4: argv.
+// Output:
+//   x0: result.
+void JSEntryStub::Generate(MacroAssembler* masm) {
+  DCHECK(jssp.Is(__ StackPointer()));
+  Register code_entry = x0;
+
+  // Enable instruction instrumentation. This only works on the simulator, and
+  // will have no effect on the model or real hardware.
+  __ EnableInstrumentation();
+
+  Label invoke, handler_entry, exit;
+
+  // Push callee-saved registers and synchronize the system stack pointer (csp)
+  // and the JavaScript stack pointer (jssp).
+  //
+  // We must not write to jssp until after the PushCalleeSavedRegisters()
+  // call, since jssp is itself a callee-saved register.
+  __ SetStackPointer(csp);
+  __ PushCalleeSavedRegisters();
+  __ Mov(jssp, csp);
+  __ SetStackPointer(jssp);
+
+  // Configure the FPCR. We don't restore it, so this is technically not allowed
+  // according to AAPCS64. However, we only set default-NaN mode and this will
+  // be harmless for most C code. Also, it works for ARM.
+  __ ConfigureFPCR();
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm);
+
+  // Set up the reserved register for 0.0.
+  __ Fmov(fp_zero, 0.0);
+
+  // Build an entry frame (see layout below).
+  int marker = type();
+  int64_t bad_frame_pointer = -1L;  // Bad frame pointer to fail if it is used.
+  __ Mov(x13, bad_frame_pointer);
+  __ Mov(x12, Smi::FromInt(marker));
+  __ Mov(x11, ExternalReference(Isolate::kCEntryFPAddress, isolate()));
+  __ Ldr(x10, MemOperand(x11));
+
+  __ Push(x13, xzr, x12, x10);
+  // Set up fp.
+  __ Sub(fp, jssp, EntryFrameConstants::kCallerFPOffset);
+
+  // Push the JS entry frame marker. Also set js_entry_sp if this is the
+  // outermost JS call.
+  Label non_outermost_js, done;
+  ExternalReference js_entry_sp(Isolate::kJSEntrySPAddress, isolate());
+  __ Mov(x10, ExternalReference(js_entry_sp));
+  __ Ldr(x11, MemOperand(x10));
+  __ Cbnz(x11, &non_outermost_js);
+  __ Str(fp, MemOperand(x10));
+  __ Mov(x12, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
+  __ Push(x12);
+  __ B(&done);
+  __ Bind(&non_outermost_js);
+  // We spare one instruction by pushing xzr since the marker is 0.
+  DCHECK(Smi::FromInt(StackFrame::INNER_JSENTRY_FRAME) == NULL);
+  __ Push(xzr);
+  __ Bind(&done);
+
+  // The frame set up looks like this:
+  // jssp[0] : JS entry frame marker.
+  // jssp[1] : C entry FP.
+  // jssp[2] : stack frame marker.
+  // jssp[3] : stack frmae marker.
+  // jssp[4] : bad frame pointer 0xfff...ff   <- fp points here.
+
+
+  // Jump to a faked try block that does the invoke, with a faked catch
+  // block that sets the pending exception.
+  __ B(&invoke);
+
+  // Prevent the constant pool from being emitted between the record of the
+  // handler_entry position and the first instruction of the sequence here.
+  // There is no risk because Assembler::Emit() emits the instruction before
+  // checking for constant pool emission, but we do not want to depend on
+  // that.
+  {
+    Assembler::BlockPoolsScope block_pools(masm);
+    __ bind(&handler_entry);
+    handler_offset_ = handler_entry.pos();
+    // Caught exception: Store result (exception) in the pending exception
+    // field in the JSEnv and return a failure sentinel. Coming in here the
+    // fp will be invalid because the PushTryHandler below sets it to 0 to
+    // signal the existence of the JSEntry frame.
+    __ Mov(x10, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                          isolate())));
+  }
+  __ Str(code_entry, MemOperand(x10));
+  __ LoadRoot(x0, Heap::kExceptionRootIndex);
+  __ B(&exit);
+
+  // Invoke: Link this frame into the handler chain.  There's only one
+  // handler block in this code object, so its index is 0.
+  __ Bind(&invoke);
+  __ PushTryHandler(StackHandler::JS_ENTRY, 0);
+  // If an exception not caught by another handler occurs, this handler
+  // returns control to the code after the B(&invoke) above, which
+  // restores all callee-saved registers (including cp and fp) to their
+  // saved values before returning a failure to C.
+
+  // Clear any pending exceptions.
+  __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
+  __ Mov(x11, Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                        isolate())));
+  __ Str(x10, MemOperand(x11));
+
+  // Invoke the function by calling through the JS entry trampoline builtin.
+  // Notice that we cannot store a reference to the trampoline code directly in
+  // this stub, because runtime stubs are not traversed when doing GC.
+
+  // Expected registers by Builtins::JSEntryTrampoline
+  // x0: code entry.
+  // x1: function.
+  // x2: receiver.
+  // x3: argc.
+  // x4: argv.
+  ExternalReference entry(type() == StackFrame::ENTRY_CONSTRUCT
+                              ? Builtins::kJSConstructEntryTrampoline
+                              : Builtins::kJSEntryTrampoline,
+                          isolate());
+  __ Mov(x10, entry);
+
+  // Call the JSEntryTrampoline.
+  __ Ldr(x11, MemOperand(x10));  // Dereference the address.
+  __ Add(x12, x11, Code::kHeaderSize - kHeapObjectTag);
+  __ Blr(x12);
+
+  // Unlink this frame from the handler chain.
+  __ PopTryHandler();
+
+
+  __ Bind(&exit);
+  // x0 holds the result.
+  // The stack pointer points to the top of the entry frame pushed on entry from
+  // C++ (at the beginning of this stub):
+  // jssp[0] : JS entry frame marker.
+  // jssp[1] : C entry FP.
+  // jssp[2] : stack frame marker.
+  // jssp[3] : stack frmae marker.
+  // jssp[4] : bad frame pointer 0xfff...ff   <- fp points here.
+
+  // Check if the current stack frame is marked as the outermost JS frame.
+  Label non_outermost_js_2;
+  __ Pop(x10);
+  __ Cmp(x10, Smi::FromInt(StackFrame::OUTERMOST_JSENTRY_FRAME));
+  __ B(ne, &non_outermost_js_2);
+  __ Mov(x11, ExternalReference(js_entry_sp));
+  __ Str(xzr, MemOperand(x11));
+  __ Bind(&non_outermost_js_2);
+
+  // Restore the top frame descriptors from the stack.
+  __ Pop(x10);
+  __ Mov(x11, ExternalReference(Isolate::kCEntryFPAddress, isolate()));
+  __ Str(x10, MemOperand(x11));
+
+  // Reset the stack to the callee saved registers.
+  __ Drop(-EntryFrameConstants::kCallerFPOffset, kByteSizeInBytes);
+  // Restore the callee-saved registers and return.
+  DCHECK(jssp.Is(__ StackPointer()));
+  __ Mov(csp, jssp);
+  __ SetStackPointer(csp);
+  __ PopCalleeSavedRegisters();
+  // After this point, we must not modify jssp because it is a callee-saved
+  // register which we have just restored.
+  __ Ret();
+}
+
+
+void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
+  Label miss;
+  Register receiver = LoadDescriptor::ReceiverRegister();
+
+  NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(masm, receiver, x10,
+                                                          x11, &miss);
+
+  __ Bind(&miss);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::LOAD_IC));
+}
+
+
+void InstanceofStub::Generate(MacroAssembler* masm) {
+  // Stack on entry:
+  // jssp[0]: function.
+  // jssp[8]: object.
+  //
+  // Returns result in x0. Zero indicates instanceof, smi 1 indicates not
+  // instanceof.
+
+  Register result = x0;
+  Register function = right();
+  Register object = left();
+  Register scratch1 = x6;
+  Register scratch2 = x7;
+  Register res_true = x8;
+  Register res_false = x9;
+  // Only used if there was an inline map check site. (See
+  // LCodeGen::DoInstanceOfKnownGlobal().)
+  Register map_check_site = x4;
+  // Delta for the instructions generated between the inline map check and the
+  // instruction setting the result.
+  const int32_t kDeltaToLoadBoolResult = 4 * kInstructionSize;
+
+  Label not_js_object, slow;
+
+  if (!HasArgsInRegisters()) {
+    __ Pop(function, object);
+  }
+
+  if (ReturnTrueFalseObject()) {
+    __ LoadTrueFalseRoots(res_true, res_false);
+  } else {
+    // This is counter-intuitive, but correct.
+    __ Mov(res_true, Smi::FromInt(0));
+    __ Mov(res_false, Smi::FromInt(1));
+  }
+
+  // Check that the left hand side is a JS object and load its map as a side
+  // effect.
+  Register map = x12;
+  __ JumpIfSmi(object, &not_js_object);
+  __ IsObjectJSObjectType(object, map, scratch2, &not_js_object);
+
+  // If there is a call site cache, don't look in the global cache, but do the
+  // real lookup and update the call site cache.
+  if (!HasCallSiteInlineCheck() && !ReturnTrueFalseObject()) {
+    Label miss;
+    __ JumpIfNotRoot(function, Heap::kInstanceofCacheFunctionRootIndex, &miss);
+    __ JumpIfNotRoot(map, Heap::kInstanceofCacheMapRootIndex, &miss);
+    __ LoadRoot(result, Heap::kInstanceofCacheAnswerRootIndex);
+    __ Ret();
+    __ Bind(&miss);
+  }
+
+  // Get the prototype of the function.
+  Register prototype = x13;
+  __ TryGetFunctionPrototype(function, prototype, scratch2, &slow,
+                             MacroAssembler::kMissOnBoundFunction);
+
+  // Check that the function prototype is a JS object.
+  __ JumpIfSmi(prototype, &slow);
+  __ IsObjectJSObjectType(prototype, scratch1, scratch2, &slow);
+
+  // Update the global instanceof or call site inlined cache with the current
+  // map and function. The cached answer will be set when it is known below.
+  if (HasCallSiteInlineCheck()) {
+    // Patch the (relocated) inlined map check.
+    __ GetRelocatedValueLocation(map_check_site, scratch1);
+    // We have a cell, so need another level of dereferencing.
+    __ Ldr(scratch1, MemOperand(scratch1));
+    __ Str(map, FieldMemOperand(scratch1, Cell::kValueOffset));
+  } else {
+    __ StoreRoot(function, Heap::kInstanceofCacheFunctionRootIndex);
+    __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
+  }
+
+  Label return_true, return_result;
+  Register smi_value = scratch1;
+  {
+    // Loop through the prototype chain looking for the function prototype.
+    Register chain_map = x1;
+    Register chain_prototype = x14;
+    Register null_value = x15;
+    Label loop;
+    __ Ldr(chain_prototype, FieldMemOperand(map, Map::kPrototypeOffset));
+    __ LoadRoot(null_value, Heap::kNullValueRootIndex);
+    // Speculatively set a result.
+    __ Mov(result, res_false);
+    if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) {
+      // Value to store in the cache cannot be an object.
+      __ Mov(smi_value, Smi::FromInt(1));
+    }
+
+    __ Bind(&loop);
+
+    // If the chain prototype is the object prototype, return true.
+    __ Cmp(chain_prototype, prototype);
+    __ B(eq, &return_true);
+
+    // If the chain prototype is null, we've reached the end of the chain, so
+    // return false.
+    __ Cmp(chain_prototype, null_value);
+    __ B(eq, &return_result);
+
+    // Otherwise, load the next prototype in the chain, and loop.
+    __ Ldr(chain_map, FieldMemOperand(chain_prototype, HeapObject::kMapOffset));
+    __ Ldr(chain_prototype, FieldMemOperand(chain_map, Map::kPrototypeOffset));
+    __ B(&loop);
+  }
+
+  // Return sequence when no arguments are on the stack.
+  // We cannot fall through to here.
+  __ Bind(&return_true);
+  __ Mov(result, res_true);
+  if (!HasCallSiteInlineCheck() && ReturnTrueFalseObject()) {
+    // Value to store in the cache cannot be an object.
+    __ Mov(smi_value, Smi::FromInt(0));
+  }
+  __ Bind(&return_result);
+  if (HasCallSiteInlineCheck()) {
+    DCHECK(ReturnTrueFalseObject());
+    __ Add(map_check_site, map_check_site, kDeltaToLoadBoolResult);
+    __ GetRelocatedValueLocation(map_check_site, scratch2);
+    __ Str(result, MemOperand(scratch2));
+  } else {
+    Register cached_value = ReturnTrueFalseObject() ? smi_value : result;
+    __ StoreRoot(cached_value, Heap::kInstanceofCacheAnswerRootIndex);
+  }
+  __ Ret();
+
+  Label object_not_null, object_not_null_or_smi;
+
+  __ Bind(&not_js_object);
+  Register object_type = x14;
+  //   x0   result        result return register (uninit)
+  //   x10  function      pointer to function
+  //   x11  object        pointer to object
+  //   x14  object_type   type of object (uninit)
+
+  // Before null, smi and string checks, check that the rhs is a function.
+  // For a non-function rhs, an exception must be thrown.
+  __ JumpIfSmi(function, &slow);
+  __ JumpIfNotObjectType(
+      function, scratch1, object_type, JS_FUNCTION_TYPE, &slow);
+
+  __ Mov(result, res_false);
+
+  // Null is not instance of anything.
+  __ Cmp(object_type, Operand(isolate()->factory()->null_value()));
+  __ B(ne, &object_not_null);
+  __ Ret();
+
+  __ Bind(&object_not_null);
+  // Smi values are not instances of anything.
+  __ JumpIfNotSmi(object, &object_not_null_or_smi);
+  __ Ret();
+
+  __ Bind(&object_not_null_or_smi);
+  // String values are not instances of anything.
+  __ IsObjectJSStringType(object, scratch2, &slow);
+  __ Ret();
+
+  // Slow-case. Tail call builtin.
+  __ Bind(&slow);
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    // Arguments have either been passed into registers or have been previously
+    // popped. We need to push them before calling builtin.
+    __ Push(object, function);
+    __ InvokeBuiltin(Builtins::INSTANCE_OF, CALL_FUNCTION);
+  }
+  if (ReturnTrueFalseObject()) {
+    // Reload true/false because they were clobbered in the builtin call.
+    __ LoadTrueFalseRoots(res_true, res_false);
+    __ Cmp(result, 0);
+    __ Csel(result, res_true, res_false, eq);
+  }
+  __ Ret();
+}
+
+
+void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
+  Register arg_count = ArgumentsAccessReadDescriptor::parameter_count();
+  Register key = ArgumentsAccessReadDescriptor::index();
+  DCHECK(arg_count.is(x0));
+  DCHECK(key.is(x1));
+
+  // The displacement is the offset of the last parameter (if any) relative
+  // to the frame pointer.
+  static const int kDisplacement =
+      StandardFrameConstants::kCallerSPOffset - kPointerSize;
+
+  // Check that the key is a smi.
+  Label slow;
+  __ JumpIfNotSmi(key, &slow);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Register local_fp = x11;
+  Register caller_fp = x11;
+  Register caller_ctx = x12;
+  Label skip_adaptor;
+  __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ Ldr(caller_ctx, MemOperand(caller_fp,
+                                StandardFrameConstants::kContextOffset));
+  __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ Csel(local_fp, fp, caller_fp, ne);
+  __ B(ne, &skip_adaptor);
+
+  // Load the actual arguments limit found in the arguments adaptor frame.
+  __ Ldr(arg_count, MemOperand(caller_fp,
+                               ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ Bind(&skip_adaptor);
+
+  // Check index against formal parameters count limit. Use unsigned comparison
+  // to get negative check for free: branch if key < 0 or key >= arg_count.
+  __ Cmp(key, arg_count);
+  __ B(hs, &slow);
+
+  // Read the argument from the stack and return it.
+  __ Sub(x10, arg_count, key);
+  __ Add(x10, local_fp, Operand::UntagSmiAndScale(x10, kPointerSizeLog2));
+  __ Ldr(x0, MemOperand(x10, kDisplacement));
+  __ Ret();
+
+  // Slow case: handle non-smi or out-of-bounds access to arguments by calling
+  // the runtime system.
+  __ Bind(&slow);
+  __ Push(key);
+  __ TailCallRuntime(Runtime::kGetArgumentsProperty, 1, 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
+  // Stack layout on entry.
+  //  jssp[0]:  number of parameters (tagged)
+  //  jssp[8]:  address of receiver argument
+  //  jssp[16]: function
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Label runtime;
+  Register caller_fp = x10;
+  __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  // Load and untag the context.
+  __ Ldr(w11, UntagSmiMemOperand(caller_fp,
+                                 StandardFrameConstants::kContextOffset));
+  __ Cmp(w11, StackFrame::ARGUMENTS_ADAPTOR);
+  __ B(ne, &runtime);
+
+  // Patch the arguments.length and parameters pointer in the current frame.
+  __ Ldr(x11, MemOperand(caller_fp,
+                         ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ Poke(x11, 0 * kXRegSize);
+  __ Add(x10, caller_fp, Operand::UntagSmiAndScale(x11, kPointerSizeLog2));
+  __ Add(x10, x10, StandardFrameConstants::kCallerSPOffset);
+  __ Poke(x10, 1 * kXRegSize);
+
+  __ Bind(&runtime);
+  __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
+}
+
+
+void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
+  // Stack layout on entry.
+  //  jssp[0]:  number of parameters (tagged)
+  //  jssp[8]:  address of receiver argument
+  //  jssp[16]: function
+  //
+  // Returns pointer to result object in x0.
+
+  // Note: arg_count_smi is an alias of param_count_smi.
+  Register arg_count_smi = x3;
+  Register param_count_smi = x3;
+  Register param_count = x7;
+  Register recv_arg = x14;
+  Register function = x4;
+  __ Pop(param_count_smi, recv_arg, function);
+  __ SmiUntag(param_count, param_count_smi);
+
+  // Check if the calling frame is an arguments adaptor frame.
+  Register caller_fp = x11;
+  Register caller_ctx = x12;
+  Label runtime;
+  Label adaptor_frame, try_allocate;
+  __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ Ldr(caller_ctx, MemOperand(caller_fp,
+                                StandardFrameConstants::kContextOffset));
+  __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ B(eq, &adaptor_frame);
+
+  // No adaptor, parameter count = argument count.
+
+  //   x1   mapped_params number of mapped params, min(params, args) (uninit)
+  //   x2   arg_count     number of function arguments (uninit)
+  //   x3   arg_count_smi number of function arguments (smi)
+  //   x4   function      function pointer
+  //   x7   param_count   number of function parameters
+  //   x11  caller_fp     caller's frame pointer
+  //   x14  recv_arg      pointer to receiver arguments
+
+  Register arg_count = x2;
+  __ Mov(arg_count, param_count);
+  __ B(&try_allocate);
+
+  // We have an adaptor frame. Patch the parameters pointer.
+  __ Bind(&adaptor_frame);
+  __ Ldr(arg_count_smi,
+         MemOperand(caller_fp,
+                    ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ SmiUntag(arg_count, arg_count_smi);
+  __ Add(x10, caller_fp, Operand(arg_count, LSL, kPointerSizeLog2));
+  __ Add(recv_arg, x10, StandardFrameConstants::kCallerSPOffset);
+
+  // Compute the mapped parameter count = min(param_count, arg_count)
+  Register mapped_params = x1;
+  __ Cmp(param_count, arg_count);
+  __ Csel(mapped_params, param_count, arg_count, lt);
+
+  __ Bind(&try_allocate);
+
+  //   x0   alloc_obj     pointer to allocated objects: param map, backing
+  //                      store, arguments (uninit)
+  //   x1   mapped_params number of mapped parameters, min(params, args)
+  //   x2   arg_count     number of function arguments
+  //   x3   arg_count_smi number of function arguments (smi)
+  //   x4   function      function pointer
+  //   x7   param_count   number of function parameters
+  //   x10  size          size of objects to allocate (uninit)
+  //   x14  recv_arg      pointer to receiver arguments
+
+  // Compute the size of backing store, parameter map, and arguments object.
+  // 1. Parameter map, has two extra words containing context and backing
+  // store.
+  const int kParameterMapHeaderSize =
+      FixedArray::kHeaderSize + 2 * kPointerSize;
+
+  // Calculate the parameter map size, assuming it exists.
+  Register size = x10;
+  __ Mov(size, Operand(mapped_params, LSL, kPointerSizeLog2));
+  __ Add(size, size, kParameterMapHeaderSize);
+
+  // If there are no mapped parameters, set the running size total to zero.
+  // Otherwise, use the parameter map size calculated earlier.
+  __ Cmp(mapped_params, 0);
+  __ CzeroX(size, eq);
+
+  // 2. Add the size of the backing store and arguments object.
+  __ Add(size, size, Operand(arg_count, LSL, kPointerSizeLog2));
+  __ Add(size, size,
+         FixedArray::kHeaderSize + Heap::kSloppyArgumentsObjectSize);
+
+  // Do the allocation of all three objects in one go. Assign this to x0, as it
+  // will be returned to the caller.
+  Register alloc_obj = x0;
+  __ Allocate(size, alloc_obj, x11, x12, &runtime, TAG_OBJECT);
+
+  // Get the arguments boilerplate from the current (global) context.
+
+  //   x0   alloc_obj       pointer to allocated objects (param map, backing
+  //                        store, arguments)
+  //   x1   mapped_params   number of mapped parameters, min(params, args)
+  //   x2   arg_count       number of function arguments
+  //   x3   arg_count_smi   number of function arguments (smi)
+  //   x4   function        function pointer
+  //   x7   param_count     number of function parameters
+  //   x11  sloppy_args_map offset to args (or aliased args) map (uninit)
+  //   x14  recv_arg        pointer to receiver arguments
+
+  Register global_object = x10;
+  Register global_ctx = x10;
+  Register sloppy_args_map = x11;
+  Register aliased_args_map = x10;
+  __ Ldr(global_object, GlobalObjectMemOperand());
+  __ Ldr(global_ctx, FieldMemOperand(global_object,
+                                     GlobalObject::kNativeContextOffset));
+
+  __ Ldr(sloppy_args_map,
+         ContextMemOperand(global_ctx, Context::SLOPPY_ARGUMENTS_MAP_INDEX));
+  __ Ldr(aliased_args_map,
+         ContextMemOperand(global_ctx, Context::ALIASED_ARGUMENTS_MAP_INDEX));
+  __ Cmp(mapped_params, 0);
+  __ CmovX(sloppy_args_map, aliased_args_map, ne);
+
+  // Copy the JS object part.
+  __ Str(sloppy_args_map, FieldMemOperand(alloc_obj, JSObject::kMapOffset));
+  __ LoadRoot(x10, Heap::kEmptyFixedArrayRootIndex);
+  __ Str(x10, FieldMemOperand(alloc_obj, JSObject::kPropertiesOffset));
+  __ Str(x10, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
+
+  // Set up the callee in-object property.
+  STATIC_ASSERT(Heap::kArgumentsCalleeIndex == 1);
+  const int kCalleeOffset = JSObject::kHeaderSize +
+                            Heap::kArgumentsCalleeIndex * kPointerSize;
+  __ AssertNotSmi(function);
+  __ Str(function, FieldMemOperand(alloc_obj, kCalleeOffset));
+
+  // Use the length and set that as an in-object property.
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
+  const int kLengthOffset = JSObject::kHeaderSize +
+                            Heap::kArgumentsLengthIndex * kPointerSize;
+  __ Str(arg_count_smi, FieldMemOperand(alloc_obj, kLengthOffset));
+
+  // Set up the elements pointer in the allocated arguments object.
+  // If we allocated a parameter map, "elements" will point there, otherwise
+  // it will point to the backing store.
+
+  //   x0   alloc_obj     pointer to allocated objects (param map, backing
+  //                      store, arguments)
+  //   x1   mapped_params number of mapped parameters, min(params, args)
+  //   x2   arg_count     number of function arguments
+  //   x3   arg_count_smi number of function arguments (smi)
+  //   x4   function      function pointer
+  //   x5   elements      pointer to parameter map or backing store (uninit)
+  //   x6   backing_store pointer to backing store (uninit)
+  //   x7   param_count   number of function parameters
+  //   x14  recv_arg      pointer to receiver arguments
+
+  Register elements = x5;
+  __ Add(elements, alloc_obj, Heap::kSloppyArgumentsObjectSize);
+  __ Str(elements, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
+
+  // Initialize parameter map. If there are no mapped arguments, we're done.
+  Label skip_parameter_map;
+  __ Cmp(mapped_params, 0);
+  // Set up backing store address, because it is needed later for filling in
+  // the unmapped arguments.
+  Register backing_store = x6;
+  __ CmovX(backing_store, elements, eq);
+  __ B(eq, &skip_parameter_map);
+
+  __ LoadRoot(x10, Heap::kSloppyArgumentsElementsMapRootIndex);
+  __ Str(x10, FieldMemOperand(elements, FixedArray::kMapOffset));
+  __ Add(x10, mapped_params, 2);
+  __ SmiTag(x10);
+  __ Str(x10, FieldMemOperand(elements, FixedArray::kLengthOffset));
+  __ Str(cp, FieldMemOperand(elements,
+                             FixedArray::kHeaderSize + 0 * kPointerSize));
+  __ Add(x10, elements, Operand(mapped_params, LSL, kPointerSizeLog2));
+  __ Add(x10, x10, kParameterMapHeaderSize);
+  __ Str(x10, FieldMemOperand(elements,
+                              FixedArray::kHeaderSize + 1 * kPointerSize));
+
+  // Copy the parameter slots and the holes in the arguments.
+  // We need to fill in mapped_parameter_count slots. Then index the context,
+  // where parameters are stored in reverse order, at:
+  //
+  //   MIN_CONTEXT_SLOTS .. MIN_CONTEXT_SLOTS + parameter_count - 1
+  //
+  // The mapped parameter thus needs to get indices:
+  //
+  //   MIN_CONTEXT_SLOTS + parameter_count - 1 ..
+  //     MIN_CONTEXT_SLOTS + parameter_count - mapped_parameter_count
+  //
+  // We loop from right to left.
+
+  //   x0   alloc_obj     pointer to allocated objects (param map, backing
+  //                      store, arguments)
+  //   x1   mapped_params number of mapped parameters, min(params, args)
+  //   x2   arg_count     number of function arguments
+  //   x3   arg_count_smi number of function arguments (smi)
+  //   x4   function      function pointer
+  //   x5   elements      pointer to parameter map or backing store (uninit)
+  //   x6   backing_store pointer to backing store (uninit)
+  //   x7   param_count   number of function parameters
+  //   x11  loop_count    parameter loop counter (uninit)
+  //   x12  index         parameter index (smi, uninit)
+  //   x13  the_hole      hole value (uninit)
+  //   x14  recv_arg      pointer to receiver arguments
+
+  Register loop_count = x11;
+  Register index = x12;
+  Register the_hole = x13;
+  Label parameters_loop, parameters_test;
+  __ Mov(loop_count, mapped_params);
+  __ Add(index, param_count, static_cast<int>(Context::MIN_CONTEXT_SLOTS));
+  __ Sub(index, index, mapped_params);
+  __ SmiTag(index);
+  __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
+  __ Add(backing_store, elements, Operand(loop_count, LSL, kPointerSizeLog2));
+  __ Add(backing_store, backing_store, kParameterMapHeaderSize);
+
+  __ B(&parameters_test);
+
+  __ Bind(&parameters_loop);
+  __ Sub(loop_count, loop_count, 1);
+  __ Mov(x10, Operand(loop_count, LSL, kPointerSizeLog2));
+  __ Add(x10, x10, kParameterMapHeaderSize - kHeapObjectTag);
+  __ Str(index, MemOperand(elements, x10));
+  __ Sub(x10, x10, kParameterMapHeaderSize - FixedArray::kHeaderSize);
+  __ Str(the_hole, MemOperand(backing_store, x10));
+  __ Add(index, index, Smi::FromInt(1));
+  __ Bind(&parameters_test);
+  __ Cbnz(loop_count, &parameters_loop);
+
+  __ Bind(&skip_parameter_map);
+  // Copy arguments header and remaining slots (if there are any.)
+  __ LoadRoot(x10, Heap::kFixedArrayMapRootIndex);
+  __ Str(x10, FieldMemOperand(backing_store, FixedArray::kMapOffset));
+  __ Str(arg_count_smi, FieldMemOperand(backing_store,
+                                        FixedArray::kLengthOffset));
+
+  //   x0   alloc_obj     pointer to allocated objects (param map, backing
+  //                      store, arguments)
+  //   x1   mapped_params number of mapped parameters, min(params, args)
+  //   x2   arg_count     number of function arguments
+  //   x4   function      function pointer
+  //   x3   arg_count_smi number of function arguments (smi)
+  //   x6   backing_store pointer to backing store (uninit)
+  //   x14  recv_arg      pointer to receiver arguments
+
+  Label arguments_loop, arguments_test;
+  __ Mov(x10, mapped_params);
+  __ Sub(recv_arg, recv_arg, Operand(x10, LSL, kPointerSizeLog2));
+  __ B(&arguments_test);
+
+  __ Bind(&arguments_loop);
+  __ Sub(recv_arg, recv_arg, kPointerSize);
+  __ Ldr(x11, MemOperand(recv_arg));
+  __ Add(x12, backing_store, Operand(x10, LSL, kPointerSizeLog2));
+  __ Str(x11, FieldMemOperand(x12, FixedArray::kHeaderSize));
+  __ Add(x10, x10, 1);
+
+  __ Bind(&arguments_test);
+  __ Cmp(x10, arg_count);
+  __ B(lt, &arguments_loop);
+
+  __ Ret();
+
+  // Do the runtime call to allocate the arguments object.
+  __ Bind(&runtime);
+  __ Push(function, recv_arg, arg_count_smi);
+  __ TailCallRuntime(Runtime::kNewSloppyArguments, 3, 1);
+}
+
+
+void LoadIndexedInterceptorStub::Generate(MacroAssembler* masm) {
+  // Return address is in lr.
+  Label slow;
+
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register key = LoadDescriptor::NameRegister();
+
+  // Check that the key is an array index, that is Uint32.
+  __ TestAndBranchIfAnySet(key, kSmiTagMask | kSmiSignMask, &slow);
+
+  // Everything is fine, call runtime.
+  __ Push(receiver, key);
+  __ TailCallExternalReference(
+      ExternalReference(IC_Utility(IC::kLoadElementWithInterceptor),
+                        masm->isolate()),
+      2, 1);
+
+  __ Bind(&slow);
+  PropertyAccessCompiler::TailCallBuiltin(
+      masm, PropertyAccessCompiler::MissBuiltin(Code::KEYED_LOAD_IC));
+}
+
+
+void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
+  // Stack layout on entry.
+  //  jssp[0]:  number of parameters (tagged)
+  //  jssp[8]:  address of receiver argument
+  //  jssp[16]: function
+  //
+  // Returns pointer to result object in x0.
+
+  // Get the stub arguments from the frame, and make an untagged copy of the
+  // parameter count.
+  Register param_count_smi = x1;
+  Register params = x2;
+  Register function = x3;
+  Register param_count = x13;
+  __ Pop(param_count_smi, params, function);
+  __ SmiUntag(param_count, param_count_smi);
+
+  // Test if arguments adaptor needed.
+  Register caller_fp = x11;
+  Register caller_ctx = x12;
+  Label try_allocate, runtime;
+  __ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ Ldr(caller_ctx, MemOperand(caller_fp,
+                                StandardFrameConstants::kContextOffset));
+  __ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ B(ne, &try_allocate);
+
+  //   x1   param_count_smi   number of parameters passed to function (smi)
+  //   x2   params            pointer to parameters
+  //   x3   function          function pointer
+  //   x11  caller_fp         caller's frame pointer
+  //   x13  param_count       number of parameters passed to function
+
+  // Patch the argument length and parameters pointer.
+  __ Ldr(param_count_smi,
+         MemOperand(caller_fp,
+                    ArgumentsAdaptorFrameConstants::kLengthOffset));
+  __ SmiUntag(param_count, param_count_smi);
+  __ Add(x10, caller_fp, Operand(param_count, LSL, kPointerSizeLog2));
+  __ Add(params, x10, StandardFrameConstants::kCallerSPOffset);
+
+  // Try the new space allocation. Start out with computing the size of the
+  // arguments object and the elements array in words.
+  Register size = x10;
+  __ Bind(&try_allocate);
+  __ Add(size, param_count, FixedArray::kHeaderSize / kPointerSize);
+  __ Cmp(param_count, 0);
+  __ CzeroX(size, eq);
+  __ Add(size, size, Heap::kStrictArgumentsObjectSize / kPointerSize);
+
+  // Do the allocation of both objects in one go. Assign this to x0, as it will
+  // be returned to the caller.
+  Register alloc_obj = x0;
+  __ Allocate(size, alloc_obj, x11, x12, &runtime,
+              static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
+
+  // Get the arguments boilerplate from the current (native) context.
+  Register global_object = x10;
+  Register global_ctx = x10;
+  Register strict_args_map = x4;
+  __ Ldr(global_object, GlobalObjectMemOperand());
+  __ Ldr(global_ctx, FieldMemOperand(global_object,
+                                     GlobalObject::kNativeContextOffset));
+  __ Ldr(strict_args_map,
+         ContextMemOperand(global_ctx, Context::STRICT_ARGUMENTS_MAP_INDEX));
+
+  //   x0   alloc_obj         pointer to allocated objects: parameter array and
+  //                          arguments object
+  //   x1   param_count_smi   number of parameters passed to function (smi)
+  //   x2   params            pointer to parameters
+  //   x3   function          function pointer
+  //   x4   strict_args_map   offset to arguments map
+  //   x13  param_count       number of parameters passed to function
+  __ Str(strict_args_map, FieldMemOperand(alloc_obj, JSObject::kMapOffset));
+  __ LoadRoot(x5, Heap::kEmptyFixedArrayRootIndex);
+  __ Str(x5, FieldMemOperand(alloc_obj, JSObject::kPropertiesOffset));
+  __ Str(x5, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
+
+  // Set the smi-tagged length as an in-object property.
+  STATIC_ASSERT(Heap::kArgumentsLengthIndex == 0);
+  const int kLengthOffset = JSObject::kHeaderSize +
+                            Heap::kArgumentsLengthIndex * kPointerSize;
+  __ Str(param_count_smi, FieldMemOperand(alloc_obj, kLengthOffset));
+
+  // If there are no actual arguments, we're done.
+  Label done;
+  __ Cbz(param_count, &done);
+
+  // Set up the elements pointer in the allocated arguments object and
+  // initialize the header in the elements fixed array.
+  Register elements = x5;
+  __ Add(elements, alloc_obj, Heap::kStrictArgumentsObjectSize);
+  __ Str(elements, FieldMemOperand(alloc_obj, JSObject::kElementsOffset));
+  __ LoadRoot(x10, Heap::kFixedArrayMapRootIndex);
+  __ Str(x10, FieldMemOperand(elements, FixedArray::kMapOffset));
+  __ Str(param_count_smi, FieldMemOperand(elements, FixedArray::kLengthOffset));
+
+  //   x0   alloc_obj         pointer to allocated objects: parameter array and
+  //                          arguments object
+  //   x1   param_count_smi   number of parameters passed to function (smi)
+  //   x2   params            pointer to parameters
+  //   x3   function          function pointer
+  //   x4   array             pointer to array slot (uninit)
+  //   x5   elements          pointer to elements array of alloc_obj
+  //   x13  param_count       number of parameters passed to function
+
+  // Copy the fixed array slots.
+  Label loop;
+  Register array = x4;
+  // Set up pointer to first array slot.
+  __ Add(array, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+
+  __ Bind(&loop);
+  // Pre-decrement the parameters pointer by kPointerSize on each iteration.
+  // Pre-decrement in order to skip receiver.
+  __ Ldr(x10, MemOperand(params, -kPointerSize, PreIndex));
+  // Post-increment elements by kPointerSize on each iteration.
+  __ Str(x10, MemOperand(array, kPointerSize, PostIndex));
+  __ Sub(param_count, param_count, 1);
+  __ Cbnz(param_count, &loop);
+
+  // Return from stub.
+  __ Bind(&done);
+  __ Ret();
+
+  // Do the runtime call to allocate the arguments object.
+  __ Bind(&runtime);
+  __ Push(function, params, param_count_smi);
+  __ TailCallRuntime(Runtime::kNewStrictArguments, 3, 1);
+}
+
+
+void RegExpExecStub::Generate(MacroAssembler* masm) {
+#ifdef V8_INTERPRETED_REGEXP
+  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+#else  // V8_INTERPRETED_REGEXP
+
+  // Stack frame on entry.
+  //  jssp[0]: last_match_info (expected JSArray)
+  //  jssp[8]: previous index
+  //  jssp[16]: subject string
+  //  jssp[24]: JSRegExp object
+  Label runtime;
+
+  // Use of registers for this function.
+
+  // Variable registers:
+  //   x10-x13                                  used as scratch registers
+  //   w0       string_type                     type of subject string
+  //   x2       jsstring_length                 subject string length
+  //   x3       jsregexp_object                 JSRegExp object
+  //   w4       string_encoding                 Latin1 or UC16
+  //   w5       sliced_string_offset            if the string is a SlicedString
+  //                                            offset to the underlying string
+  //   w6       string_representation           groups attributes of the string:
+  //                                              - is a string
+  //                                              - type of the string
+  //                                              - is a short external string
+  Register string_type = w0;
+  Register jsstring_length = x2;
+  Register jsregexp_object = x3;
+  Register string_encoding = w4;
+  Register sliced_string_offset = w5;
+  Register string_representation = w6;
+
+  // These are in callee save registers and will be preserved by the call
+  // to the native RegExp code, as this code is called using the normal
+  // C calling convention. When calling directly from generated code the
+  // native RegExp code will not do a GC and therefore the content of
+  // these registers are safe to use after the call.
+
+  //   x19       subject                        subject string
+  //   x20       regexp_data                    RegExp data (FixedArray)
+  //   x21       last_match_info_elements       info relative to the last match
+  //                                            (FixedArray)
+  //   x22       code_object                    generated regexp code
+  Register subject = x19;
+  Register regexp_data = x20;
+  Register last_match_info_elements = x21;
+  Register code_object = x22;
+
+  // TODO(jbramley): Is it necessary to preserve these? I don't think ARM does.
+  CPURegList used_callee_saved_registers(subject,
+                                         regexp_data,
+                                         last_match_info_elements,
+                                         code_object);
+  __ PushCPURegList(used_callee_saved_registers);
+
+  // Stack frame.
+  //  jssp[0] : x19
+  //  jssp[8] : x20
+  //  jssp[16]: x21
+  //  jssp[24]: x22
+  //  jssp[32]: last_match_info (JSArray)
+  //  jssp[40]: previous index
+  //  jssp[48]: subject string
+  //  jssp[56]: JSRegExp object
+
+  const int kLastMatchInfoOffset = 4 * kPointerSize;
+  const int kPreviousIndexOffset = 5 * kPointerSize;
+  const int kSubjectOffset = 6 * kPointerSize;
+  const int kJSRegExpOffset = 7 * kPointerSize;
+
+  // Ensure that a RegExp stack is allocated.
+  ExternalReference address_of_regexp_stack_memory_address =
+      ExternalReference::address_of_regexp_stack_memory_address(isolate());
+  ExternalReference address_of_regexp_stack_memory_size =
+      ExternalReference::address_of_regexp_stack_memory_size(isolate());
+  __ Mov(x10, address_of_regexp_stack_memory_size);
+  __ Ldr(x10, MemOperand(x10));
+  __ Cbz(x10, &runtime);
+
+  // Check that the first argument is a JSRegExp object.
+  DCHECK(jssp.Is(__ StackPointer()));
+  __ Peek(jsregexp_object, kJSRegExpOffset);
+  __ JumpIfSmi(jsregexp_object, &runtime);
+  __ JumpIfNotObjectType(jsregexp_object, x10, x10, JS_REGEXP_TYPE, &runtime);
+
+  // Check that the RegExp has been compiled (data contains a fixed array).
+  __ Ldr(regexp_data, FieldMemOperand(jsregexp_object, JSRegExp::kDataOffset));
+  if (FLAG_debug_code) {
+    STATIC_ASSERT(kSmiTag == 0);
+    __ Tst(regexp_data, kSmiTagMask);
+    __ Check(ne, kUnexpectedTypeForRegExpDataFixedArrayExpected);
+    __ CompareObjectType(regexp_data, x10, x10, FIXED_ARRAY_TYPE);
+    __ Check(eq, kUnexpectedTypeForRegExpDataFixedArrayExpected);
+  }
+
+  // Check the type of the RegExp. Only continue if type is JSRegExp::IRREGEXP.
+  __ Ldr(x10, FieldMemOperand(regexp_data, JSRegExp::kDataTagOffset));
+  __ Cmp(x10, Smi::FromInt(JSRegExp::IRREGEXP));
+  __ B(ne, &runtime);
+
+  // Check that the number of captures fit in the static offsets vector buffer.
+  // We have always at least one capture for the whole match, plus additional
+  // ones due to capturing parentheses. A capture takes 2 registers.
+  // The number of capture registers then is (number_of_captures + 1) * 2.
+  __ Ldrsw(x10,
+           UntagSmiFieldMemOperand(regexp_data,
+                                   JSRegExp::kIrregexpCaptureCountOffset));
+  // Check (number_of_captures + 1) * 2 <= offsets vector size
+  //             number_of_captures * 2 <= offsets vector size - 2
+  STATIC_ASSERT(Isolate::kJSRegexpStaticOffsetsVectorSize >= 2);
+  __ Add(x10, x10, x10);
+  __ Cmp(x10, Isolate::kJSRegexpStaticOffsetsVectorSize - 2);
+  __ B(hi, &runtime);
+
+  // Initialize offset for possibly sliced string.
+  __ Mov(sliced_string_offset, 0);
+
+  DCHECK(jssp.Is(__ StackPointer()));
+  __ Peek(subject, kSubjectOffset);
+  __ JumpIfSmi(subject, &runtime);
+
+  __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
+  __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+
+  __ Ldr(jsstring_length, FieldMemOperand(subject, String::kLengthOffset));
+
+  // Handle subject string according to its encoding and representation:
+  // (1) Sequential string?  If yes, go to (5).
+  // (2) Anything but sequential or cons?  If yes, go to (6).
+  // (3) Cons string.  If the string is flat, replace subject with first string.
+  //     Otherwise bailout.
+  // (4) Is subject external?  If yes, go to (7).
+  // (5) Sequential string.  Load regexp code according to encoding.
+  // (E) Carry on.
+  /// [...]
+
+  // Deferred code at the end of the stub:
+  // (6) Not a long external string?  If yes, go to (8).
+  // (7) External string.  Make it, offset-wise, look like a sequential string.
+  //     Go to (5).
+  // (8) Short external string or not a string?  If yes, bail out to runtime.
+  // (9) Sliced string.  Replace subject with parent.  Go to (4).
+
+  Label check_underlying;   // (4)
+  Label seq_string;         // (5)
+  Label not_seq_nor_cons;   // (6)
+  Label external_string;    // (7)
+  Label not_long_external;  // (8)
+
+  // (1) Sequential string?  If yes, go to (5).
+  __ And(string_representation,
+         string_type,
+         kIsNotStringMask |
+             kStringRepresentationMask |
+             kShortExternalStringMask);
+  // We depend on the fact that Strings of type
+  // SeqString and not ShortExternalString are defined
+  // by the following pattern:
+  //   string_type: 0XX0 XX00
+  //                ^  ^   ^^
+  //                |  |   ||
+  //                |  |   is a SeqString
+  //                |  is not a short external String
+  //                is a String
+  STATIC_ASSERT((kStringTag | kSeqStringTag) == 0);
+  STATIC_ASSERT(kShortExternalStringTag != 0);
+  __ Cbz(string_representation, &seq_string);  // Go to (5).
+
+  // (2) Anything but sequential or cons?  If yes, go to (6).
+  STATIC_ASSERT(kConsStringTag < kExternalStringTag);
+  STATIC_ASSERT(kSlicedStringTag > kExternalStringTag);
+  STATIC_ASSERT(kIsNotStringMask > kExternalStringTag);
+  STATIC_ASSERT(kShortExternalStringTag > kExternalStringTag);
+  __ Cmp(string_representation, kExternalStringTag);
+  __ B(ge, &not_seq_nor_cons);  // Go to (6).
+
+  // (3) Cons string.  Check that it's flat.
+  __ Ldr(x10, FieldMemOperand(subject, ConsString::kSecondOffset));
+  __ JumpIfNotRoot(x10, Heap::kempty_stringRootIndex, &runtime);
+  // Replace subject with first string.
+  __ Ldr(subject, FieldMemOperand(subject, ConsString::kFirstOffset));
+
+  // (4) Is subject external?  If yes, go to (7).
+  __ Bind(&check_underlying);
+  // Reload the string type.
+  __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
+  __ Ldrb(string_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kSeqStringTag == 0);
+  // The underlying external string is never a short external string.
+  STATIC_ASSERT(ExternalString::kMaxShortLength < ConsString::kMinLength);
+  STATIC_ASSERT(ExternalString::kMaxShortLength < SlicedString::kMinLength);
+  __ TestAndBranchIfAnySet(string_type.X(),
+                           kStringRepresentationMask,
+                           &external_string);  // Go to (7).
+
+  // (5) Sequential string.  Load regexp code according to encoding.
+  __ Bind(&seq_string);
+
+  // Check that the third argument is a positive smi less than the subject
+  // string length. A negative value will be greater (unsigned comparison).
+  DCHECK(jssp.Is(__ StackPointer()));
+  __ Peek(x10, kPreviousIndexOffset);
+  __ JumpIfNotSmi(x10, &runtime);
+  __ Cmp(jsstring_length, x10);
+  __ B(ls, &runtime);
+
+  // Argument 2 (x1): We need to load argument 2 (the previous index) into x1
+  // before entering the exit frame.
+  __ SmiUntag(x1, x10);
+
+  // The third bit determines the string encoding in string_type.
+  STATIC_ASSERT(kOneByteStringTag == 0x04);
+  STATIC_ASSERT(kTwoByteStringTag == 0x00);
+  STATIC_ASSERT(kStringEncodingMask == 0x04);
+
+  // Find the code object based on the assumptions above.
+  // kDataOneByteCodeOffset and kDataUC16CodeOffset are adjacent, adds an offset
+  // of kPointerSize to reach the latter.
+  DCHECK_EQ(JSRegExp::kDataOneByteCodeOffset + kPointerSize,
+            JSRegExp::kDataUC16CodeOffset);
+  __ Mov(x10, kPointerSize);
+  // We will need the encoding later: Latin1 = 0x04
+  //                                  UC16   = 0x00
+  __ Ands(string_encoding, string_type, kStringEncodingMask);
+  __ CzeroX(x10, ne);
+  __ Add(x10, regexp_data, x10);
+  __ Ldr(code_object, FieldMemOperand(x10, JSRegExp::kDataOneByteCodeOffset));
+
+  // (E) Carry on.  String handling is done.
+
+  // Check that the irregexp code has been generated for the actual string
+  // encoding. If it has, the field contains a code object otherwise it contains
+  // a smi (code flushing support).
+  __ JumpIfSmi(code_object, &runtime);
+
+  // All checks done. Now push arguments for native regexp code.
+  __ IncrementCounter(isolate()->counters()->regexp_entry_native(), 1,
+                      x10,
+                      x11);
+
+  // Isolates: note we add an additional parameter here (isolate pointer).
+  __ EnterExitFrame(false, x10, 1);
+  DCHECK(csp.Is(__ StackPointer()));
+
+  // We have 9 arguments to pass to the regexp code, therefore we have to pass
+  // one on the stack and the rest as registers.
+
+  // Note that the placement of the argument on the stack isn't standard
+  // AAPCS64:
+  // csp[0]: Space for the return address placed by DirectCEntryStub.
+  // csp[8]: Argument 9, the current isolate address.
+
+  __ Mov(x10, ExternalReference::isolate_address(isolate()));
+  __ Poke(x10, kPointerSize);
+
+  Register length = w11;
+  Register previous_index_in_bytes = w12;
+  Register start = x13;
+
+  // Load start of the subject string.
+  __ Add(start, subject, SeqString::kHeaderSize - kHeapObjectTag);
+  // Load the length from the original subject string from the previous stack
+  // frame. Therefore we have to use fp, which points exactly to two pointer
+  // sizes below the previous sp. (Because creating a new stack frame pushes
+  // the previous fp onto the stack and decrements sp by 2 * kPointerSize.)
+  __ Ldr(subject, MemOperand(fp, kSubjectOffset + 2 * kPointerSize));
+  __ Ldr(length, UntagSmiFieldMemOperand(subject, String::kLengthOffset));
+
+  // Handle UC16 encoding, two bytes make one character.
+  //   string_encoding: if Latin1: 0x04
+  //                    if UC16:   0x00
+  STATIC_ASSERT(kStringEncodingMask == 0x04);
+  __ Ubfx(string_encoding, string_encoding, 2, 1);
+  __ Eor(string_encoding, string_encoding, 1);
+  //   string_encoding: if Latin1: 0
+  //                    if UC16:   1
+
+  // Convert string positions from characters to bytes.
+  // Previous index is in x1.
+  __ Lsl(previous_index_in_bytes, w1, string_encoding);
+  __ Lsl(length, length, string_encoding);
+  __ Lsl(sliced_string_offset, sliced_string_offset, string_encoding);
+
+  // Argument 1 (x0): Subject string.
+  __ Mov(x0, subject);
+
+  // Argument 2 (x1): Previous index, already there.
+
+  // Argument 3 (x2): Get the start of input.
+  // Start of input = start of string + previous index + substring offset
+  //                                                     (0 if the string
+  //                                                      is not sliced).
+  __ Add(w10, previous_index_in_bytes, sliced_string_offset);
+  __ Add(x2, start, Operand(w10, UXTW));
+
+  // Argument 4 (x3):
+  // End of input = start of input + (length of input - previous index)
+  __ Sub(w10, length, previous_index_in_bytes);
+  __ Add(x3, x2, Operand(w10, UXTW));
+
+  // Argument 5 (x4): static offsets vector buffer.
+  __ Mov(x4, ExternalReference::address_of_static_offsets_vector(isolate()));
+
+  // Argument 6 (x5): Set the number of capture registers to zero to force
+  // global regexps to behave as non-global. This stub is not used for global
+  // regexps.
+  __ Mov(x5, 0);
+
+  // Argument 7 (x6): Start (high end) of backtracking stack memory area.
+  __ Mov(x10, address_of_regexp_stack_memory_address);
+  __ Ldr(x10, MemOperand(x10));
+  __ Mov(x11, address_of_regexp_stack_memory_size);
+  __ Ldr(x11, MemOperand(x11));
+  __ Add(x6, x10, x11);
+
+  // Argument 8 (x7): Indicate that this is a direct call from JavaScript.
+  __ Mov(x7, 1);
+
+  // Locate the code entry and call it.
+  __ Add(code_object, code_object, Code::kHeaderSize - kHeapObjectTag);
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(masm, code_object);
+
+  __ LeaveExitFrame(false, x10, true);
+
+  // The generated regexp code returns an int32 in w0.
+  Label failure, exception;
+  __ CompareAndBranch(w0, NativeRegExpMacroAssembler::FAILURE, eq, &failure);
+  __ CompareAndBranch(w0,
+                      NativeRegExpMacroAssembler::EXCEPTION,
+                      eq,
+                      &exception);
+  __ CompareAndBranch(w0, NativeRegExpMacroAssembler::RETRY, eq, &runtime);
+
+  // Success: process the result from the native regexp code.
+  Register number_of_capture_registers = x12;
+
+  // Calculate number of capture registers (number_of_captures + 1) * 2
+  // and store it in the last match info.
+  __ Ldrsw(x10,
+           UntagSmiFieldMemOperand(regexp_data,
+                                   JSRegExp::kIrregexpCaptureCountOffset));
+  __ Add(x10, x10, x10);
+  __ Add(number_of_capture_registers, x10, 2);
+
+  // Check that the fourth object is a JSArray object.
+  DCHECK(jssp.Is(__ StackPointer()));
+  __ Peek(x10, kLastMatchInfoOffset);
+  __ JumpIfSmi(x10, &runtime);
+  __ JumpIfNotObjectType(x10, x11, x11, JS_ARRAY_TYPE, &runtime);
+
+  // Check that the JSArray is the fast case.
+  __ Ldr(last_match_info_elements,
+         FieldMemOperand(x10, JSArray::kElementsOffset));
+  __ Ldr(x10,
+         FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(x10, Heap::kFixedArrayMapRootIndex, &runtime);
+
+  // Check that the last match info has space for the capture registers and the
+  // additional information (overhead).
+  //     (number_of_captures + 1) * 2 + overhead <= last match info size
+  //     (number_of_captures * 2) + 2 + overhead <= last match info size
+  //      number_of_capture_registers + overhead <= last match info size
+  __ Ldrsw(x10,
+           UntagSmiFieldMemOperand(last_match_info_elements,
+                                   FixedArray::kLengthOffset));
+  __ Add(x11, number_of_capture_registers, RegExpImpl::kLastMatchOverhead);
+  __ Cmp(x11, x10);
+  __ B(gt, &runtime);
+
+  // Store the capture count.
+  __ SmiTag(x10, number_of_capture_registers);
+  __ Str(x10,
+         FieldMemOperand(last_match_info_elements,
+                         RegExpImpl::kLastCaptureCountOffset));
+  // Store last subject and last input.
+  __ Str(subject,
+         FieldMemOperand(last_match_info_elements,
+                         RegExpImpl::kLastSubjectOffset));
+  // Use x10 as the subject string in order to only need
+  // one RecordWriteStub.
+  __ Mov(x10, subject);
+  __ RecordWriteField(last_match_info_elements,
+                      RegExpImpl::kLastSubjectOffset,
+                      x10,
+                      x11,
+                      kLRHasNotBeenSaved,
+                      kDontSaveFPRegs);
+  __ Str(subject,
+         FieldMemOperand(last_match_info_elements,
+                         RegExpImpl::kLastInputOffset));
+  __ Mov(x10, subject);
+  __ RecordWriteField(last_match_info_elements,
+                      RegExpImpl::kLastInputOffset,
+                      x10,
+                      x11,
+                      kLRHasNotBeenSaved,
+                      kDontSaveFPRegs);
+
+  Register last_match_offsets = x13;
+  Register offsets_vector_index = x14;
+  Register current_offset = x15;
+
+  // Get the static offsets vector filled by the native regexp code
+  // and fill the last match info.
+  ExternalReference address_of_static_offsets_vector =
+      ExternalReference::address_of_static_offsets_vector(isolate());
+  __ Mov(offsets_vector_index, address_of_static_offsets_vector);
+
+  Label next_capture, done;
+  // Capture register counter starts from number of capture registers and
+  // iterates down to zero (inclusive).
+  __ Add(last_match_offsets,
+         last_match_info_elements,
+         RegExpImpl::kFirstCaptureOffset - kHeapObjectTag);
+  __ Bind(&next_capture);
+  __ Subs(number_of_capture_registers, number_of_capture_registers, 2);
+  __ B(mi, &done);
+  // Read two 32 bit values from the static offsets vector buffer into
+  // an X register
+  __ Ldr(current_offset,
+         MemOperand(offsets_vector_index, kWRegSize * 2, PostIndex));
+  // Store the smi values in the last match info.
+  __ SmiTag(x10, current_offset);
+  // Clearing the 32 bottom bits gives us a Smi.
+  STATIC_ASSERT(kSmiTag == 0);
+  __ Bic(x11, current_offset, kSmiShiftMask);
+  __ Stp(x10,
+         x11,
+         MemOperand(last_match_offsets, kXRegSize * 2, PostIndex));
+  __ B(&next_capture);
+  __ Bind(&done);
+
+  // Return last match info.
+  __ Peek(x0, kLastMatchInfoOffset);
+  __ PopCPURegList(used_callee_saved_registers);
+  // Drop the 4 arguments of the stub from the stack.
+  __ Drop(4);
+  __ Ret();
+
+  __ Bind(&exception);
+  Register exception_value = x0;
+  // A stack overflow (on the backtrack stack) may have occured
+  // in the RegExp code but no exception has been created yet.
+  // If there is no pending exception, handle that in the runtime system.
+  __ Mov(x10, Operand(isolate()->factory()->the_hole_value()));
+  __ Mov(x11,
+         Operand(ExternalReference(Isolate::kPendingExceptionAddress,
+                                   isolate())));
+  __ Ldr(exception_value, MemOperand(x11));
+  __ Cmp(x10, exception_value);
+  __ B(eq, &runtime);
+
+  __ Str(x10, MemOperand(x11));  // Clear pending exception.
+
+  // Check if the exception is a termination. If so, throw as uncatchable.
+  Label termination_exception;
+  __ JumpIfRoot(exception_value,
+                Heap::kTerminationExceptionRootIndex,
+                &termination_exception);
+
+  __ Throw(exception_value, x10, x11, x12, x13);
+
+  __ Bind(&termination_exception);
+  __ ThrowUncatchable(exception_value, x10, x11, x12, x13);
+
+  __ Bind(&failure);
+  __ Mov(x0, Operand(isolate()->factory()->null_value()));
+  __ PopCPURegList(used_callee_saved_registers);
+  // Drop the 4 arguments of the stub from the stack.
+  __ Drop(4);
+  __ Ret();
+
+  __ Bind(&runtime);
+  __ PopCPURegList(used_callee_saved_registers);
+  __ TailCallRuntime(Runtime::kRegExpExecRT, 4, 1);
+
+  // Deferred code for string handling.
+  // (6) Not a long external string?  If yes, go to (8).
+  __ Bind(&not_seq_nor_cons);
+  // Compare flags are still set.
+  __ B(ne, &not_long_external);  // Go to (8).
+
+  // (7) External string. Make it, offset-wise, look like a sequential string.
+  __ Bind(&external_string);
+  if (masm->emit_debug_code()) {
+    // Assert that we do not have a cons or slice (indirect strings) here.
+    // Sequential strings have already been ruled out.
+    __ Ldr(x10, FieldMemOperand(subject, HeapObject::kMapOffset));
+    __ Ldrb(x10, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+    __ Tst(x10, kIsIndirectStringMask);
+    __ Check(eq, kExternalStringExpectedButNotFound);
+    __ And(x10, x10, kStringRepresentationMask);
+    __ Cmp(x10, 0);
+    __ Check(ne, kExternalStringExpectedButNotFound);
+  }
+  __ Ldr(subject,
+         FieldMemOperand(subject, ExternalString::kResourceDataOffset));
+  // Move the pointer so that offset-wise, it looks like a sequential string.
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ Sub(subject, subject, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
+  __ B(&seq_string);    // Go to (5).
+
+  // (8) If this is a short external string or not a string, bail out to
+  // runtime.
+  __ Bind(&not_long_external);
+  STATIC_ASSERT(kShortExternalStringTag != 0);
+  __ TestAndBranchIfAnySet(string_representation,
+                           kShortExternalStringMask | kIsNotStringMask,
+                           &runtime);
+
+  // (9) Sliced string. Replace subject with parent.
+  __ Ldr(sliced_string_offset,
+         UntagSmiFieldMemOperand(subject, SlicedString::kOffsetOffset));
+  __ Ldr(subject, FieldMemOperand(subject, SlicedString::kParentOffset));
+  __ B(&check_underlying);    // Go to (4).
+#endif
+}
+
+
+static void GenerateRecordCallTarget(MacroAssembler* masm,
+                                     Register argc,
+                                     Register function,
+                                     Register feedback_vector,
+                                     Register index,
+                                     Register scratch1,
+                                     Register scratch2) {
+  ASM_LOCATION("GenerateRecordCallTarget");
+  DCHECK(!AreAliased(scratch1, scratch2,
+                     argc, function, feedback_vector, index));
+  // Cache the called function in a feedback vector slot. Cache states are
+  // uninitialized, monomorphic (indicated by a JSFunction), and megamorphic.
+  //  argc :            number of arguments to the construct function
+  //  function :        the function to call
+  //  feedback_vector : the feedback vector
+  //  index :           slot in feedback vector (smi)
+  Label initialize, done, miss, megamorphic, not_array_function;
+
+  DCHECK_EQ(*TypeFeedbackVector::MegamorphicSentinel(masm->isolate()),
+            masm->isolate()->heap()->megamorphic_symbol());
+  DCHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(masm->isolate()),
+            masm->isolate()->heap()->uninitialized_symbol());
+
+  // Load the cache state.
+  __ Add(scratch1, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Ldr(scratch1, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+
+  // A monomorphic cache hit or an already megamorphic state: invoke the
+  // function without changing the state.
+  __ Cmp(scratch1, function);
+  __ B(eq, &done);
+
+  if (!FLAG_pretenuring_call_new) {
+    // If we came here, we need to see if we are the array function.
+    // If we didn't have a matching function, and we didn't find the megamorph
+    // sentinel, then we have in the slot either some other function or an
+    // AllocationSite. Do a map check on the object in scratch1 register.
+    __ Ldr(scratch2, FieldMemOperand(scratch1, AllocationSite::kMapOffset));
+    __ JumpIfNotRoot(scratch2, Heap::kAllocationSiteMapRootIndex, &miss);
+
+    // Make sure the function is the Array() function
+    __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch1);
+    __ Cmp(function, scratch1);
+    __ B(ne, &megamorphic);
+    __ B(&done);
+  }
+
+  __ Bind(&miss);
+
+  // A monomorphic miss (i.e, here the cache is not uninitialized) goes
+  // megamorphic.
+  __ JumpIfRoot(scratch1, Heap::kUninitializedSymbolRootIndex, &initialize);
+  // MegamorphicSentinel is an immortal immovable object (undefined) so no
+  // write-barrier is needed.
+  __ Bind(&megamorphic);
+  __ Add(scratch1, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ LoadRoot(scratch2, Heap::kMegamorphicSymbolRootIndex);
+  __ Str(scratch2, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+  __ B(&done);
+
+  // An uninitialized cache is patched with the function or sentinel to
+  // indicate the ElementsKind if function is the Array constructor.
+  __ Bind(&initialize);
+
+  if (!FLAG_pretenuring_call_new) {
+    // Make sure the function is the Array() function
+    __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch1);
+    __ Cmp(function, scratch1);
+    __ B(ne, &not_array_function);
+
+    // The target function is the Array constructor,
+    // Create an AllocationSite if we don't already have it, store it in the
+    // slot.
+    {
+      FrameScope scope(masm, StackFrame::INTERNAL);
+      CreateAllocationSiteStub create_stub(masm->isolate());
+
+      // Arguments register must be smi-tagged to call out.
+      __ SmiTag(argc);
+      __ Push(argc, function, feedback_vector, index);
+
+      // CreateAllocationSiteStub expect the feedback vector in x2 and the slot
+      // index in x3.
+      DCHECK(feedback_vector.Is(x2) && index.Is(x3));
+      __ CallStub(&create_stub);
+
+      __ Pop(index, feedback_vector, function, argc);
+      __ SmiUntag(argc);
+    }
+    __ B(&done);
+
+    __ Bind(&not_array_function);
+  }
+
+  // An uninitialized cache is patched with the function.
+
+  __ Add(scratch1, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Str(function, MemOperand(scratch1, 0));
+
+  __ Push(function);
+  __ RecordWrite(feedback_vector, scratch1, function, kLRHasNotBeenSaved,
+                 kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Pop(function);
+
+  __ Bind(&done);
+}
+
+
+static void EmitContinueIfStrictOrNative(MacroAssembler* masm, Label* cont) {
+  // Do not transform the receiver for strict mode functions.
+  __ Ldr(x3, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(w4, FieldMemOperand(x3, SharedFunctionInfo::kCompilerHintsOffset));
+  __ Tbnz(w4, SharedFunctionInfo::kStrictModeFunction, cont);
+
+  // Do not transform the receiver for native (Compilerhints already in x3).
+  __ Tbnz(w4, SharedFunctionInfo::kNative, cont);
+}
+
+
+static void EmitSlowCase(MacroAssembler* masm,
+                         int argc,
+                         Register function,
+                         Register type,
+                         Label* non_function) {
+  // Check for function proxy.
+  // x10 : function type.
+  __ CompareAndBranch(type, JS_FUNCTION_PROXY_TYPE, ne, non_function);
+  __ Push(function);  // put proxy as additional argument
+  __ Mov(x0, argc + 1);
+  __ Mov(x2, 0);
+  __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY);
+  {
+    Handle<Code> adaptor =
+        masm->isolate()->builtins()->ArgumentsAdaptorTrampoline();
+    __ Jump(adaptor, RelocInfo::CODE_TARGET);
+  }
+
+  // CALL_NON_FUNCTION expects the non-function callee as receiver (instead
+  // of the original receiver from the call site).
+  __ Bind(non_function);
+  __ Poke(function, argc * kXRegSize);
+  __ Mov(x0, argc);  // Set up the number of arguments.
+  __ Mov(x2, 0);
+  __ GetBuiltinFunction(function, Builtins::CALL_NON_FUNCTION);
+  __ Jump(masm->isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+}
+
+
+static void EmitWrapCase(MacroAssembler* masm, int argc, Label* cont) {
+  // Wrap the receiver and patch it back onto the stack.
+  { FrameScope frame_scope(masm, StackFrame::INTERNAL);
+    __ Push(x1, x3);
+    __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+    __ Pop(x1);
+  }
+  __ Poke(x0, argc * kPointerSize);
+  __ B(cont);
+}
+
+
+static void CallFunctionNoFeedback(MacroAssembler* masm,
+                                   int argc, bool needs_checks,
+                                   bool call_as_method) {
+  // x1  function    the function to call
+  Register function = x1;
+  Register type = x4;
+  Label slow, non_function, wrap, cont;
+
+  // TODO(jbramley): This function has a lot of unnamed registers. Name them,
+  // and tidy things up a bit.
+
+  if (needs_checks) {
+    // Check that the function is really a JavaScript function.
+    __ JumpIfSmi(function, &non_function);
+
+    // Goto slow case if we do not have a function.
+    __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
+  }
+
+  // Fast-case: Invoke the function now.
+  // x1  function  pushed function
+  ParameterCount actual(argc);
+
+  if (call_as_method) {
+    if (needs_checks) {
+      EmitContinueIfStrictOrNative(masm, &cont);
+    }
+
+    // Compute the receiver in sloppy mode.
+    __ Peek(x3, argc * kPointerSize);
+
+    if (needs_checks) {
+      __ JumpIfSmi(x3, &wrap);
+      __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt);
+    } else {
+      __ B(&wrap);
+    }
+
+    __ Bind(&cont);
+  }
+
+  __ InvokeFunction(function,
+                    actual,
+                    JUMP_FUNCTION,
+                    NullCallWrapper());
+  if (needs_checks) {
+    // Slow-case: Non-function called.
+    __ Bind(&slow);
+    EmitSlowCase(masm, argc, function, type, &non_function);
+  }
+
+  if (call_as_method) {
+    __ Bind(&wrap);
+    EmitWrapCase(masm, argc, &cont);
+  }
+}
+
+
+void CallFunctionStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("CallFunctionStub::Generate");
+  CallFunctionNoFeedback(masm, argc(), NeedsChecks(), CallAsMethod());
+}
+
+
+void CallConstructStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("CallConstructStub::Generate");
+  // x0 : number of arguments
+  // x1 : the function to call
+  // x2 : feedback vector
+  // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol)
+  Register function = x1;
+  Label slow, non_function_call;
+
+  // Check that the function is not a smi.
+  __ JumpIfSmi(function, &non_function_call);
+  // Check that the function is a JSFunction.
+  Register object_type = x10;
+  __ JumpIfNotObjectType(function, object_type, object_type, JS_FUNCTION_TYPE,
+                         &slow);
+
+  if (RecordCallTarget()) {
+    GenerateRecordCallTarget(masm, x0, function, x2, x3, x4, x5);
+
+    __ Add(x5, x2, Operand::UntagSmiAndScale(x3, kPointerSizeLog2));
+    if (FLAG_pretenuring_call_new) {
+      // Put the AllocationSite from the feedback vector into x2.
+      // By adding kPointerSize we encode that we know the AllocationSite
+      // entry is at the feedback vector slot given by x3 + 1.
+      __ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize + kPointerSize));
+    } else {
+    Label feedback_register_initialized;
+      // Put the AllocationSite from the feedback vector into x2, or undefined.
+      __ Ldr(x2, FieldMemOperand(x5, FixedArray::kHeaderSize));
+      __ Ldr(x5, FieldMemOperand(x2, AllocationSite::kMapOffset));
+      __ JumpIfRoot(x5, Heap::kAllocationSiteMapRootIndex,
+                    &feedback_register_initialized);
+      __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+      __ bind(&feedback_register_initialized);
+    }
+
+    __ AssertUndefinedOrAllocationSite(x2, x5);
+  }
+
+  // Jump to the function-specific construct stub.
+  Register jump_reg = x4;
+  Register shared_func_info = jump_reg;
+  Register cons_stub = jump_reg;
+  Register cons_stub_code = jump_reg;
+  __ Ldr(shared_func_info,
+         FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(cons_stub,
+         FieldMemOperand(shared_func_info,
+                         SharedFunctionInfo::kConstructStubOffset));
+  __ Add(cons_stub_code, cons_stub, Code::kHeaderSize - kHeapObjectTag);
+  __ Br(cons_stub_code);
+
+  Label do_call;
+  __ Bind(&slow);
+  __ Cmp(object_type, JS_FUNCTION_PROXY_TYPE);
+  __ B(ne, &non_function_call);
+  __ GetBuiltinFunction(x1, Builtins::CALL_FUNCTION_PROXY_AS_CONSTRUCTOR);
+  __ B(&do_call);
+
+  __ Bind(&non_function_call);
+  __ GetBuiltinFunction(x1, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
+
+  __ Bind(&do_call);
+  // Set expected number of arguments to zero (not changing x0).
+  __ Mov(x2, 0);
+  __ Jump(isolate()->builtins()->ArgumentsAdaptorTrampoline(),
+          RelocInfo::CODE_TARGET);
+}
+
+
+static void EmitLoadTypeFeedbackVector(MacroAssembler* masm, Register vector) {
+  __ Ldr(vector, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Ldr(vector, FieldMemOperand(vector,
+                                 JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(vector, FieldMemOperand(vector,
+                                 SharedFunctionInfo::kFeedbackVectorOffset));
+}
+
+
+void CallIC_ArrayStub::Generate(MacroAssembler* masm) {
+  // x1 - function
+  // x3 - slot id
+  Label miss;
+  Register function = x1;
+  Register feedback_vector = x2;
+  Register index = x3;
+  Register scratch = x4;
+
+  EmitLoadTypeFeedbackVector(masm, feedback_vector);
+
+  __ LoadGlobalFunction(Context::ARRAY_FUNCTION_INDEX, scratch);
+  __ Cmp(function, scratch);
+  __ B(ne, &miss);
+
+  __ Mov(x0, Operand(arg_count()));
+
+  __ Add(scratch, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Ldr(scratch, FieldMemOperand(scratch, FixedArray::kHeaderSize));
+
+  // Verify that scratch contains an AllocationSite
+  Register map = x5;
+  __ Ldr(map, FieldMemOperand(scratch, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(map, Heap::kAllocationSiteMapRootIndex, &miss);
+
+  Register allocation_site = feedback_vector;
+  __ Mov(allocation_site, scratch);
+  ArrayConstructorStub stub(masm->isolate(), arg_count());
+  __ TailCallStub(&stub);
+
+  __ bind(&miss);
+  GenerateMiss(masm);
+
+  // The slow case, we need this no matter what to complete a call after a miss.
+  CallFunctionNoFeedback(masm,
+                         arg_count(),
+                         true,
+                         CallAsMethod());
+
+  __ Unreachable();
+}
+
+
+void CallICStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("CallICStub");
+
+  // x1 - function
+  // x3 - slot id (Smi)
+  Label extra_checks_or_miss, slow_start;
+  Label slow, non_function, wrap, cont;
+  Label have_js_function;
+  int argc = arg_count();
+  ParameterCount actual(argc);
+
+  Register function = x1;
+  Register feedback_vector = x2;
+  Register index = x3;
+  Register type = x4;
+
+  EmitLoadTypeFeedbackVector(masm, feedback_vector);
+
+  // The checks. First, does x1 match the recorded monomorphic target?
+  __ Add(x4, feedback_vector,
+         Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Ldr(x4, FieldMemOperand(x4, FixedArray::kHeaderSize));
+
+  __ Cmp(x4, function);
+  __ B(ne, &extra_checks_or_miss);
+
+  __ bind(&have_js_function);
+  if (CallAsMethod()) {
+    EmitContinueIfStrictOrNative(masm, &cont);
+
+    // Compute the receiver in sloppy mode.
+    __ Peek(x3, argc * kPointerSize);
+
+    __ JumpIfSmi(x3, &wrap);
+    __ JumpIfObjectType(x3, x10, type, FIRST_SPEC_OBJECT_TYPE, &wrap, lt);
+
+    __ Bind(&cont);
+  }
+
+  __ InvokeFunction(function,
+                    actual,
+                    JUMP_FUNCTION,
+                    NullCallWrapper());
+
+  __ bind(&slow);
+  EmitSlowCase(masm, argc, function, type, &non_function);
+
+  if (CallAsMethod()) {
+    __ bind(&wrap);
+    EmitWrapCase(masm, argc, &cont);
+  }
+
+  __ bind(&extra_checks_or_miss);
+  Label miss;
+
+  __ JumpIfRoot(x4, Heap::kMegamorphicSymbolRootIndex, &slow_start);
+  __ JumpIfRoot(x4, Heap::kUninitializedSymbolRootIndex, &miss);
+
+  if (!FLAG_trace_ic) {
+    // We are going megamorphic. If the feedback is a JSFunction, it is fine
+    // to handle it here. More complex cases are dealt with in the runtime.
+    __ AssertNotSmi(x4);
+    __ JumpIfNotObjectType(x4, x5, x5, JS_FUNCTION_TYPE, &miss);
+    __ Add(x4, feedback_vector,
+           Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+    __ LoadRoot(x5, Heap::kMegamorphicSymbolRootIndex);
+    __ Str(x5, FieldMemOperand(x4, FixedArray::kHeaderSize));
+    __ B(&slow_start);
+  }
+
+  // We are here because tracing is on or we are going monomorphic.
+  __ bind(&miss);
+  GenerateMiss(masm);
+
+  // the slow case
+  __ bind(&slow_start);
+
+  // Check that the function is really a JavaScript function.
+  __ JumpIfSmi(function, &non_function);
+
+  // Goto slow case if we do not have a function.
+  __ JumpIfNotObjectType(function, x10, type, JS_FUNCTION_TYPE, &slow);
+  __ B(&have_js_function);
+}
+
+
+void CallICStub::GenerateMiss(MacroAssembler* masm) {
+  ASM_LOCATION("CallICStub[Miss]");
+
+  // Get the receiver of the function from the stack; 1 ~ return address.
+  __ Peek(x4, (arg_count() + 1) * kPointerSize);
+
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Push the receiver and the function and feedback info.
+    __ Push(x4, x1, x2, x3);
+
+    // Call the entry.
+    IC::UtilityId id = GetICState() == DEFAULT ? IC::kCallIC_Miss
+                                               : IC::kCallIC_Customization_Miss;
+
+    ExternalReference miss = ExternalReference(IC_Utility(id),
+                                               masm->isolate());
+    __ CallExternalReference(miss, 4);
+
+    // Move result to edi and exit the internal frame.
+    __ Mov(x1, x0);
+  }
+}
+
+
+void StringCharCodeAtGenerator::GenerateFast(MacroAssembler* masm) {
+  // If the receiver is a smi trigger the non-string case.
+  __ JumpIfSmi(object_, receiver_not_string_);
+
+  // Fetch the instance type of the receiver into result register.
+  __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+  __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+
+  // If the receiver is not a string trigger the non-string case.
+  __ TestAndBranchIfAnySet(result_, kIsNotStringMask, receiver_not_string_);
+
+  // If the index is non-smi trigger the non-smi case.
+  __ JumpIfNotSmi(index_, &index_not_smi_);
+
+  __ Bind(&got_smi_index_);
+  // Check for index out of range.
+  __ Ldrsw(result_, UntagSmiFieldMemOperand(object_, String::kLengthOffset));
+  __ Cmp(result_, Operand::UntagSmi(index_));
+  __ B(ls, index_out_of_range_);
+
+  __ SmiUntag(index_);
+
+  StringCharLoadGenerator::Generate(masm,
+                                    object_,
+                                    index_.W(),
+                                    result_,
+                                    &call_runtime_);
+  __ SmiTag(result_);
+  __ Bind(&exit_);
+}
+
+
+void StringCharCodeAtGenerator::GenerateSlow(
+    MacroAssembler* masm,
+    const RuntimeCallHelper& call_helper) {
+  __ Abort(kUnexpectedFallthroughToCharCodeAtSlowCase);
+
+  __ Bind(&index_not_smi_);
+  // If index is a heap number, try converting it to an integer.
+  __ JumpIfNotHeapNumber(index_, index_not_number_);
+  call_helper.BeforeCall(masm);
+  // Save object_ on the stack and pass index_ as argument for runtime call.
+  __ Push(object_, index_);
+  if (index_flags_ == STRING_INDEX_IS_NUMBER) {
+    __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1);
+  } else {
+    DCHECK(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX);
+    // NumberToSmi discards numbers that are not exact integers.
+    __ CallRuntime(Runtime::kNumberToSmi, 1);
+  }
+  // Save the conversion result before the pop instructions below
+  // have a chance to overwrite it.
+  __ Mov(index_, x0);
+  __ Pop(object_);
+  // Reload the instance type.
+  __ Ldr(result_, FieldMemOperand(object_, HeapObject::kMapOffset));
+  __ Ldrb(result_, FieldMemOperand(result_, Map::kInstanceTypeOffset));
+  call_helper.AfterCall(masm);
+
+  // If index is still not a smi, it must be out of range.
+  __ JumpIfNotSmi(index_, index_out_of_range_);
+  // Otherwise, return to the fast path.
+  __ B(&got_smi_index_);
+
+  // Call runtime. We get here when the receiver is a string and the
+  // index is a number, but the code of getting the actual character
+  // is too complex (e.g., when the string needs to be flattened).
+  __ Bind(&call_runtime_);
+  call_helper.BeforeCall(masm);
+  __ SmiTag(index_);
+  __ Push(object_, index_);
+  __ CallRuntime(Runtime::kStringCharCodeAtRT, 2);
+  __ Mov(result_, x0);
+  call_helper.AfterCall(masm);
+  __ B(&exit_);
+
+  __ Abort(kUnexpectedFallthroughFromCharCodeAtSlowCase);
+}
+
+
+void StringCharFromCodeGenerator::GenerateFast(MacroAssembler* masm) {
+  __ JumpIfNotSmi(code_, &slow_case_);
+  __ Cmp(code_, Smi::FromInt(String::kMaxOneByteCharCode));
+  __ B(hi, &slow_case_);
+
+  __ LoadRoot(result_, Heap::kSingleCharacterStringCacheRootIndex);
+  // At this point code register contains smi tagged one-byte char code.
+  __ Add(result_, result_, Operand::UntagSmiAndScale(code_, kPointerSizeLog2));
+  __ Ldr(result_, FieldMemOperand(result_, FixedArray::kHeaderSize));
+  __ JumpIfRoot(result_, Heap::kUndefinedValueRootIndex, &slow_case_);
+  __ Bind(&exit_);
+}
+
+
+void StringCharFromCodeGenerator::GenerateSlow(
+    MacroAssembler* masm,
+    const RuntimeCallHelper& call_helper) {
+  __ Abort(kUnexpectedFallthroughToCharFromCodeSlowCase);
+
+  __ Bind(&slow_case_);
+  call_helper.BeforeCall(masm);
+  __ Push(code_);
+  __ CallRuntime(Runtime::kCharFromCode, 1);
+  __ Mov(result_, x0);
+  call_helper.AfterCall(masm);
+  __ B(&exit_);
+
+  __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase);
+}
+
+
+void CompareICStub::GenerateSmis(MacroAssembler* masm) {
+  // Inputs are in x0 (lhs) and x1 (rhs).
+  DCHECK(state() == CompareICState::SMI);
+  ASM_LOCATION("CompareICStub[Smis]");
+  Label miss;
+  // Bail out (to 'miss') unless both x0 and x1 are smis.
+  __ JumpIfEitherNotSmi(x0, x1, &miss);
+
+  if (GetCondition() == eq) {
+    // For equality we do not care about the sign of the result.
+    __ Sub(x0, x0, x1);
+  } else {
+    // Untag before subtracting to avoid handling overflow.
+    __ SmiUntag(x1);
+    __ Sub(x0, x1, Operand::UntagSmi(x0));
+  }
+  __ Ret();
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateNumbers(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::NUMBER);
+  ASM_LOCATION("CompareICStub[HeapNumbers]");
+
+  Label unordered, maybe_undefined1, maybe_undefined2;
+  Label miss, handle_lhs, values_in_d_regs;
+  Label untag_rhs, untag_lhs;
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+  FPRegister rhs_d = d0;
+  FPRegister lhs_d = d1;
+
+  if (left() == CompareICState::SMI) {
+    __ JumpIfNotSmi(lhs, &miss);
+  }
+  if (right() == CompareICState::SMI) {
+    __ JumpIfNotSmi(rhs, &miss);
+  }
+
+  __ SmiUntagToDouble(rhs_d, rhs, kSpeculativeUntag);
+  __ SmiUntagToDouble(lhs_d, lhs, kSpeculativeUntag);
+
+  // Load rhs if it's a heap number.
+  __ JumpIfSmi(rhs, &handle_lhs);
+  __ JumpIfNotHeapNumber(rhs, &maybe_undefined1);
+  __ Ldr(rhs_d, FieldMemOperand(rhs, HeapNumber::kValueOffset));
+
+  // Load lhs if it's a heap number.
+  __ Bind(&handle_lhs);
+  __ JumpIfSmi(lhs, &values_in_d_regs);
+  __ JumpIfNotHeapNumber(lhs, &maybe_undefined2);
+  __ Ldr(lhs_d, FieldMemOperand(lhs, HeapNumber::kValueOffset));
+
+  __ Bind(&values_in_d_regs);
+  __ Fcmp(lhs_d, rhs_d);
+  __ B(vs, &unordered);  // Overflow flag set if either is NaN.
+  STATIC_ASSERT((LESS == -1) && (EQUAL == 0) && (GREATER == 1));
+  __ Cset(result, gt);  // gt => 1, otherwise (lt, eq) => 0 (EQUAL).
+  __ Csinv(result, result, xzr, ge);  // lt => -1, gt => 1, eq => 0.
+  __ Ret();
+
+  __ Bind(&unordered);
+  CompareICStub stub(isolate(), op(), CompareICState::GENERIC,
+                     CompareICState::GENERIC, CompareICState::GENERIC);
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+
+  __ Bind(&maybe_undefined1);
+  if (Token::IsOrderedRelationalCompareOp(op())) {
+    __ JumpIfNotRoot(rhs, Heap::kUndefinedValueRootIndex, &miss);
+    __ JumpIfSmi(lhs, &unordered);
+    __ JumpIfNotHeapNumber(lhs, &maybe_undefined2);
+    __ B(&unordered);
+  }
+
+  __ Bind(&maybe_undefined2);
+  if (Token::IsOrderedRelationalCompareOp(op())) {
+    __ JumpIfRoot(lhs, Heap::kUndefinedValueRootIndex, &unordered);
+  }
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateInternalizedStrings(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::INTERNALIZED_STRING);
+  ASM_LOCATION("CompareICStub[InternalizedStrings]");
+  Label miss;
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(lhs, rhs, &miss);
+
+  // Check that both operands are internalized strings.
+  Register rhs_map = x10;
+  Register lhs_map = x11;
+  Register rhs_type = x10;
+  Register lhs_type = x11;
+  __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
+  __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
+
+  STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
+  __ Orr(x12, lhs_type, rhs_type);
+  __ TestAndBranchIfAnySet(
+      x12, kIsNotStringMask | kIsNotInternalizedMask, &miss);
+
+  // Internalized strings are compared by identity.
+  STATIC_ASSERT(EQUAL == 0);
+  __ Cmp(lhs, rhs);
+  __ Cset(result, ne);
+  __ Ret();
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateUniqueNames(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::UNIQUE_NAME);
+  ASM_LOCATION("CompareICStub[UniqueNames]");
+  DCHECK(GetCondition() == eq);
+  Label miss;
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+
+  Register lhs_instance_type = w2;
+  Register rhs_instance_type = w3;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(lhs, rhs, &miss);
+
+  // Check that both operands are unique names. This leaves the instance
+  // types loaded in tmp1 and tmp2.
+  __ Ldr(x10, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ Ldr(x11, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ Ldrb(lhs_instance_type, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+  __ Ldrb(rhs_instance_type, FieldMemOperand(x11, Map::kInstanceTypeOffset));
+
+  // To avoid a miss, each instance type should be either SYMBOL_TYPE or it
+  // should have kInternalizedTag set.
+  __ JumpIfNotUniqueNameInstanceType(lhs_instance_type, &miss);
+  __ JumpIfNotUniqueNameInstanceType(rhs_instance_type, &miss);
+
+  // Unique names are compared by identity.
+  STATIC_ASSERT(EQUAL == 0);
+  __ Cmp(lhs, rhs);
+  __ Cset(result, ne);
+  __ Ret();
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateStrings(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::STRING);
+  ASM_LOCATION("CompareICStub[Strings]");
+
+  Label miss;
+
+  bool equality = Token::IsEqualityOp(op());
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+
+  // Check that both operands are heap objects.
+  __ JumpIfEitherSmi(rhs, lhs, &miss);
+
+  // Check that both operands are strings.
+  Register rhs_map = x10;
+  Register lhs_map = x11;
+  Register rhs_type = x10;
+  Register lhs_type = x11;
+  __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ Ldrb(lhs_type, FieldMemOperand(lhs_map, Map::kInstanceTypeOffset));
+  __ Ldrb(rhs_type, FieldMemOperand(rhs_map, Map::kInstanceTypeOffset));
+  STATIC_ASSERT(kNotStringTag != 0);
+  __ Orr(x12, lhs_type, rhs_type);
+  __ Tbnz(x12, MaskToBit(kIsNotStringMask), &miss);
+
+  // Fast check for identical strings.
+  Label not_equal;
+  __ Cmp(lhs, rhs);
+  __ B(ne, &not_equal);
+  __ Mov(result, EQUAL);
+  __ Ret();
+
+  __ Bind(&not_equal);
+  // Handle not identical strings
+
+  // Check that both strings are internalized strings. If they are, we're done
+  // because we already know they are not identical. We know they are both
+  // strings.
+  if (equality) {
+    DCHECK(GetCondition() == eq);
+    STATIC_ASSERT(kInternalizedTag == 0);
+    Label not_internalized_strings;
+    __ Orr(x12, lhs_type, rhs_type);
+    __ TestAndBranchIfAnySet(
+        x12, kIsNotInternalizedMask, &not_internalized_strings);
+    // Result is in rhs (x0), and not EQUAL, as rhs is not a smi.
+    __ Ret();
+    __ Bind(&not_internalized_strings);
+  }
+
+  // Check that both strings are sequential one-byte.
+  Label runtime;
+  __ JumpIfBothInstanceTypesAreNotSequentialOneByte(lhs_type, rhs_type, x12,
+                                                    x13, &runtime);
+
+  // Compare flat one-byte strings. Returns when done.
+  if (equality) {
+    StringHelper::GenerateFlatOneByteStringEquals(masm, lhs, rhs, x10, x11,
+                                                  x12);
+  } else {
+    StringHelper::GenerateCompareFlatOneByteStrings(masm, lhs, rhs, x10, x11,
+                                                    x12, x13);
+  }
+
+  // Handle more complex cases in runtime.
+  __ Bind(&runtime);
+  __ Push(lhs, rhs);
+  if (equality) {
+    __ TailCallRuntime(Runtime::kStringEquals, 2, 1);
+  } else {
+    __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+  }
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateObjects(MacroAssembler* masm) {
+  DCHECK(state() == CompareICState::OBJECT);
+  ASM_LOCATION("CompareICStub[Objects]");
+
+  Label miss;
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+
+  __ JumpIfEitherSmi(rhs, lhs, &miss);
+
+  __ JumpIfNotObjectType(rhs, x10, x10, JS_OBJECT_TYPE, &miss);
+  __ JumpIfNotObjectType(lhs, x10, x10, JS_OBJECT_TYPE, &miss);
+
+  DCHECK(GetCondition() == eq);
+  __ Sub(result, rhs, lhs);
+  __ Ret();
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+void CompareICStub::GenerateKnownObjects(MacroAssembler* masm) {
+  ASM_LOCATION("CompareICStub[KnownObjects]");
+
+  Label miss;
+
+  Register result = x0;
+  Register rhs = x0;
+  Register lhs = x1;
+
+  __ JumpIfEitherSmi(rhs, lhs, &miss);
+
+  Register rhs_map = x10;
+  Register lhs_map = x11;
+  __ Ldr(rhs_map, FieldMemOperand(rhs, HeapObject::kMapOffset));
+  __ Ldr(lhs_map, FieldMemOperand(lhs, HeapObject::kMapOffset));
+  __ Cmp(rhs_map, Operand(known_map_));
+  __ B(ne, &miss);
+  __ Cmp(lhs_map, Operand(known_map_));
+  __ B(ne, &miss);
+
+  __ Sub(result, rhs, lhs);
+  __ Ret();
+
+  __ Bind(&miss);
+  GenerateMiss(masm);
+}
+
+
+// This method handles the case where a compare stub had the wrong
+// implementation. It calls a miss handler, which re-writes the stub. All other
+// CompareICStub::Generate* methods should fall back into this one if their
+// operands were not the expected types.
+void CompareICStub::GenerateMiss(MacroAssembler* masm) {
+  ASM_LOCATION("CompareICStub[Miss]");
+
+  Register stub_entry = x11;
+  {
+    ExternalReference miss =
+      ExternalReference(IC_Utility(IC::kCompareIC_Miss), isolate());
+
+    FrameScope scope(masm, StackFrame::INTERNAL);
+    Register op = x10;
+    Register left = x1;
+    Register right = x0;
+    // Preserve some caller-saved registers.
+    __ Push(x1, x0, lr);
+    // Push the arguments.
+    __ Mov(op, Smi::FromInt(this->op()));
+    __ Push(left, right, op);
+
+    // Call the miss handler. This also pops the arguments.
+    __ CallExternalReference(miss, 3);
+
+    // Compute the entry point of the rewritten stub.
+    __ Add(stub_entry, x0, Code::kHeaderSize - kHeapObjectTag);
+    // Restore caller-saved registers.
+    __ Pop(lr, x0, x1);
+  }
+
+  // Tail-call to the new stub.
+  __ Jump(stub_entry);
+}
+
+
+void SubStringStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("SubStringStub::Generate");
+  Label runtime;
+
+  // Stack frame on entry.
+  //  lr: return address
+  //  jssp[0]:  substring "to" offset
+  //  jssp[8]:  substring "from" offset
+  //  jssp[16]: pointer to string object
+
+  // This stub is called from the native-call %_SubString(...), so
+  // nothing can be assumed about the arguments. It is tested that:
+  //  "string" is a sequential string,
+  //  both "from" and "to" are smis, and
+  //  0 <= from <= to <= string.length (in debug mode.)
+  // If any of these assumptions fail, we call the runtime system.
+
+  static const int kToOffset = 0 * kPointerSize;
+  static const int kFromOffset = 1 * kPointerSize;
+  static const int kStringOffset = 2 * kPointerSize;
+
+  Register to = x0;
+  Register from = x15;
+  Register input_string = x10;
+  Register input_length = x11;
+  Register input_type = x12;
+  Register result_string = x0;
+  Register result_length = x1;
+  Register temp = x3;
+
+  __ Peek(to, kToOffset);
+  __ Peek(from, kFromOffset);
+
+  // Check that both from and to are smis. If not, jump to runtime.
+  __ JumpIfEitherNotSmi(from, to, &runtime);
+  __ SmiUntag(from);
+  __ SmiUntag(to);
+
+  // Calculate difference between from and to. If to < from, branch to runtime.
+  __ Subs(result_length, to, from);
+  __ B(mi, &runtime);
+
+  // Check from is positive.
+  __ Tbnz(from, kWSignBit, &runtime);
+
+  // Make sure first argument is a string.
+  __ Peek(input_string, kStringOffset);
+  __ JumpIfSmi(input_string, &runtime);
+  __ IsObjectJSStringType(input_string, input_type, &runtime);
+
+  Label single_char;
+  __ Cmp(result_length, 1);
+  __ B(eq, &single_char);
+
+  // Short-cut for the case of trivial substring.
+  Label return_x0;
+  __ Ldrsw(input_length,
+           UntagSmiFieldMemOperand(input_string, String::kLengthOffset));
+
+  __ Cmp(result_length, input_length);
+  __ CmovX(x0, input_string, eq);
+  // Return original string.
+  __ B(eq, &return_x0);
+
+  // Longer than original string's length or negative: unsafe arguments.
+  __ B(hi, &runtime);
+
+  // Shorter than original string's length: an actual substring.
+
+  //   x0   to               substring end character offset
+  //   x1   result_length    length of substring result
+  //   x10  input_string     pointer to input string object
+  //   x10  unpacked_string  pointer to unpacked string object
+  //   x11  input_length     length of input string
+  //   x12  input_type       instance type of input string
+  //   x15  from             substring start character offset
+
+  // Deal with different string types: update the index if necessary and put
+  // the underlying string into register unpacked_string.
+  Label underlying_unpacked, sliced_string, seq_or_external_string;
+  Label update_instance_type;
+  // If the string is not indirect, it can only be sequential or external.
+  STATIC_ASSERT(kIsIndirectStringMask == (kSlicedStringTag & kConsStringTag));
+  STATIC_ASSERT(kIsIndirectStringMask != 0);
+
+  // Test for string types, and branch/fall through to appropriate unpacking
+  // code.
+  __ Tst(input_type, kIsIndirectStringMask);
+  __ B(eq, &seq_or_external_string);
+  __ Tst(input_type, kSlicedNotConsMask);
+  __ B(ne, &sliced_string);
+
+  Register unpacked_string = input_string;
+
+  // Cons string. Check whether it is flat, then fetch first part.
+  __ Ldr(temp, FieldMemOperand(input_string, ConsString::kSecondOffset));
+  __ JumpIfNotRoot(temp, Heap::kempty_stringRootIndex, &runtime);
+  __ Ldr(unpacked_string,
+         FieldMemOperand(input_string, ConsString::kFirstOffset));
+  __ B(&update_instance_type);
+
+  __ Bind(&sliced_string);
+  // Sliced string. Fetch parent and correct start index by offset.
+  __ Ldrsw(temp,
+           UntagSmiFieldMemOperand(input_string, SlicedString::kOffsetOffset));
+  __ Add(from, from, temp);
+  __ Ldr(unpacked_string,
+         FieldMemOperand(input_string, SlicedString::kParentOffset));
+
+  __ Bind(&update_instance_type);
+  __ Ldr(temp, FieldMemOperand(unpacked_string, HeapObject::kMapOffset));
+  __ Ldrb(input_type, FieldMemOperand(temp, Map::kInstanceTypeOffset));
+  // Now control must go to &underlying_unpacked. Since the no code is generated
+  // before then we fall through instead of generating a useless branch.
+
+  __ Bind(&seq_or_external_string);
+  // Sequential or external string. Registers unpacked_string and input_string
+  // alias, so there's nothing to do here.
+  // Note that if code is added here, the above code must be updated.
+
+  //   x0   result_string    pointer to result string object (uninit)
+  //   x1   result_length    length of substring result
+  //   x10  unpacked_string  pointer to unpacked string object
+  //   x11  input_length     length of input string
+  //   x12  input_type       instance type of input string
+  //   x15  from             substring start character offset
+  __ Bind(&underlying_unpacked);
+
+  if (FLAG_string_slices) {
+    Label copy_routine;
+    __ Cmp(result_length, SlicedString::kMinLength);
+    // Short slice. Copy instead of slicing.
+    __ B(lt, &copy_routine);
+    // Allocate new sliced string. At this point we do not reload the instance
+    // type including the string encoding because we simply rely on the info
+    // provided by the original string. It does not matter if the original
+    // string's encoding is wrong because we always have to recheck encoding of
+    // the newly created string's parent anyway due to externalized strings.
+    Label two_byte_slice, set_slice_header;
+    STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0);
+    STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0);
+    __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_slice);
+    __ AllocateOneByteSlicedString(result_string, result_length, x3, x4,
+                                   &runtime);
+    __ B(&set_slice_header);
+
+    __ Bind(&two_byte_slice);
+    __ AllocateTwoByteSlicedString(result_string, result_length, x3, x4,
+                                   &runtime);
+
+    __ Bind(&set_slice_header);
+    __ SmiTag(from);
+    __ Str(from, FieldMemOperand(result_string, SlicedString::kOffsetOffset));
+    __ Str(unpacked_string,
+           FieldMemOperand(result_string, SlicedString::kParentOffset));
+    __ B(&return_x0);
+
+    __ Bind(&copy_routine);
+  }
+
+  //   x0   result_string    pointer to result string object (uninit)
+  //   x1   result_length    length of substring result
+  //   x10  unpacked_string  pointer to unpacked string object
+  //   x11  input_length     length of input string
+  //   x12  input_type       instance type of input string
+  //   x13  unpacked_char0   pointer to first char of unpacked string (uninit)
+  //   x13  substring_char0  pointer to first char of substring (uninit)
+  //   x14  result_char0     pointer to first char of result (uninit)
+  //   x15  from             substring start character offset
+  Register unpacked_char0 = x13;
+  Register substring_char0 = x13;
+  Register result_char0 = x14;
+  Label two_byte_sequential, sequential_string, allocate_result;
+  STATIC_ASSERT(kExternalStringTag != 0);
+  STATIC_ASSERT(kSeqStringTag == 0);
+
+  __ Tst(input_type, kExternalStringTag);
+  __ B(eq, &sequential_string);
+
+  __ Tst(input_type, kShortExternalStringTag);
+  __ B(ne, &runtime);
+  __ Ldr(unpacked_char0,
+         FieldMemOperand(unpacked_string, ExternalString::kResourceDataOffset));
+  // unpacked_char0 points to the first character of the underlying string.
+  __ B(&allocate_result);
+
+  __ Bind(&sequential_string);
+  // Locate first character of underlying subject string.
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ Add(unpacked_char0, unpacked_string,
+         SeqOneByteString::kHeaderSize - kHeapObjectTag);
+
+  __ Bind(&allocate_result);
+  // Sequential one-byte string. Allocate the result.
+  STATIC_ASSERT((kOneByteStringTag & kStringEncodingMask) != 0);
+  __ Tbz(input_type, MaskToBit(kStringEncodingMask), &two_byte_sequential);
+
+  // Allocate and copy the resulting one-byte string.
+  __ AllocateOneByteString(result_string, result_length, x3, x4, x5, &runtime);
+
+  // Locate first character of substring to copy.
+  __ Add(substring_char0, unpacked_char0, from);
+
+  // Locate first character of result.
+  __ Add(result_char0, result_string,
+         SeqOneByteString::kHeaderSize - kHeapObjectTag);
+
+  STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong);
+  __ B(&return_x0);
+
+  // Allocate and copy the resulting two-byte string.
+  __ Bind(&two_byte_sequential);
+  __ AllocateTwoByteString(result_string, result_length, x3, x4, x5, &runtime);
+
+  // Locate first character of substring to copy.
+  __ Add(substring_char0, unpacked_char0, Operand(from, LSL, 1));
+
+  // Locate first character of result.
+  __ Add(result_char0, result_string,
+         SeqTwoByteString::kHeaderSize - kHeapObjectTag);
+
+  STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  __ Add(result_length, result_length, result_length);
+  __ CopyBytes(result_char0, substring_char0, result_length, x3, kCopyLong);
+
+  __ Bind(&return_x0);
+  Counters* counters = isolate()->counters();
+  __ IncrementCounter(counters->sub_string_native(), 1, x3, x4);
+  __ Drop(3);
+  __ Ret();
+
+  __ Bind(&runtime);
+  __ TailCallRuntime(Runtime::kSubString, 3, 1);
+
+  __ bind(&single_char);
+  // x1: result_length
+  // x10: input_string
+  // x12: input_type
+  // x15: from (untagged)
+  __ SmiTag(from);
+  StringCharAtGenerator generator(
+      input_string, from, result_length, x0,
+      &runtime, &runtime, &runtime, STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm);
+  __ Drop(3);
+  __ Ret();
+  generator.SkipSlow(masm, &runtime);
+}
+
+
+void StringHelper::GenerateFlatOneByteStringEquals(
+    MacroAssembler* masm, Register left, Register right, Register scratch1,
+    Register scratch2, Register scratch3) {
+  DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3));
+  Register result = x0;
+  Register left_length = scratch1;
+  Register right_length = scratch2;
+
+  // Compare lengths. If lengths differ, strings can't be equal. Lengths are
+  // smis, and don't need to be untagged.
+  Label strings_not_equal, check_zero_length;
+  __ Ldr(left_length, FieldMemOperand(left, String::kLengthOffset));
+  __ Ldr(right_length, FieldMemOperand(right, String::kLengthOffset));
+  __ Cmp(left_length, right_length);
+  __ B(eq, &check_zero_length);
+
+  __ Bind(&strings_not_equal);
+  __ Mov(result, Smi::FromInt(NOT_EQUAL));
+  __ Ret();
+
+  // Check if the length is zero. If so, the strings must be equal (and empty.)
+  Label compare_chars;
+  __ Bind(&check_zero_length);
+  STATIC_ASSERT(kSmiTag == 0);
+  __ Cbnz(left_length, &compare_chars);
+  __ Mov(result, Smi::FromInt(EQUAL));
+  __ Ret();
+
+  // Compare characters. Falls through if all characters are equal.
+  __ Bind(&compare_chars);
+  GenerateOneByteCharsCompareLoop(masm, left, right, left_length, scratch2,
+                                  scratch3, &strings_not_equal);
+
+  // Characters in strings are equal.
+  __ Mov(result, Smi::FromInt(EQUAL));
+  __ Ret();
+}
+
+
+void StringHelper::GenerateCompareFlatOneByteStrings(
+    MacroAssembler* masm, Register left, Register right, Register scratch1,
+    Register scratch2, Register scratch3, Register scratch4) {
+  DCHECK(!AreAliased(left, right, scratch1, scratch2, scratch3, scratch4));
+  Label result_not_equal, compare_lengths;
+
+  // Find minimum length and length difference.
+  Register length_delta = scratch3;
+  __ Ldr(scratch1, FieldMemOperand(left, String::kLengthOffset));
+  __ Ldr(scratch2, FieldMemOperand(right, String::kLengthOffset));
+  __ Subs(length_delta, scratch1, scratch2);
+
+  Register min_length = scratch1;
+  __ Csel(min_length, scratch2, scratch1, gt);
+  __ Cbz(min_length, &compare_lengths);
+
+  // Compare loop.
+  GenerateOneByteCharsCompareLoop(masm, left, right, min_length, scratch2,
+                                  scratch4, &result_not_equal);
+
+  // Compare lengths - strings up to min-length are equal.
+  __ Bind(&compare_lengths);
+
+  DCHECK(Smi::FromInt(EQUAL) == static_cast<Smi*>(0));
+
+  // Use length_delta as result if it's zero.
+  Register result = x0;
+  __ Subs(result, length_delta, 0);
+
+  __ Bind(&result_not_equal);
+  Register greater = x10;
+  Register less = x11;
+  __ Mov(greater, Smi::FromInt(GREATER));
+  __ Mov(less, Smi::FromInt(LESS));
+  __ CmovX(result, greater, gt);
+  __ CmovX(result, less, lt);
+  __ Ret();
+}
+
+
+void StringHelper::GenerateOneByteCharsCompareLoop(
+    MacroAssembler* masm, Register left, Register right, Register length,
+    Register scratch1, Register scratch2, Label* chars_not_equal) {
+  DCHECK(!AreAliased(left, right, length, scratch1, scratch2));
+
+  // Change index to run from -length to -1 by adding length to string
+  // start. This means that loop ends when index reaches zero, which
+  // doesn't need an additional compare.
+  __ SmiUntag(length);
+  __ Add(scratch1, length, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ Add(left, left, scratch1);
+  __ Add(right, right, scratch1);
+
+  Register index = length;
+  __ Neg(index, length);  // index = -length;
+
+  // Compare loop
+  Label loop;
+  __ Bind(&loop);
+  __ Ldrb(scratch1, MemOperand(left, index));
+  __ Ldrb(scratch2, MemOperand(right, index));
+  __ Cmp(scratch1, scratch2);
+  __ B(ne, chars_not_equal);
+  __ Add(index, index, 1);
+  __ Cbnz(index, &loop);
+}
+
+
+void StringCompareStub::Generate(MacroAssembler* masm) {
+  Label runtime;
+
+  Counters* counters = isolate()->counters();
+
+  // Stack frame on entry.
+  //  sp[0]: right string
+  //  sp[8]: left string
+  Register right = x10;
+  Register left = x11;
+  Register result = x0;
+  __ Pop(right, left);
+
+  Label not_same;
+  __ Subs(result, right, left);
+  __ B(ne, &not_same);
+  STATIC_ASSERT(EQUAL == 0);
+  __ IncrementCounter(counters->string_compare_native(), 1, x3, x4);
+  __ Ret();
+
+  __ Bind(&not_same);
+
+  // Check that both objects are sequential one-byte strings.
+  __ JumpIfEitherIsNotSequentialOneByteStrings(left, right, x12, x13, &runtime);
+
+  // Compare flat one-byte strings natively. Remove arguments from stack first,
+  // as this function will generate a return.
+  __ IncrementCounter(counters->string_compare_native(), 1, x3, x4);
+  StringHelper::GenerateCompareFlatOneByteStrings(masm, left, right, x12, x13,
+                                                  x14, x15);
+
+  __ Bind(&runtime);
+
+  // Push arguments back on to the stack.
+  //  sp[0] = right string
+  //  sp[8] = left string.
+  __ Push(left, right);
+
+  // Call the runtime.
+  // Returns -1 (less), 0 (equal), or 1 (greater) tagged as a small integer.
+  __ TailCallRuntime(Runtime::kStringCompare, 2, 1);
+}
+
+
+void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x1    : left
+  //  -- x0    : right
+  //  -- lr    : return address
+  // -----------------------------------
+
+  // Load x2 with the allocation site.  We stick an undefined dummy value here
+  // and replace it with the real allocation site later when we instantiate this
+  // stub in BinaryOpICWithAllocationSiteStub::GetCodeCopyFromTemplate().
+  __ LoadObject(x2, handle(isolate()->heap()->undefined_value()));
+
+  // Make sure that we actually patched the allocation site.
+  if (FLAG_debug_code) {
+    __ AssertNotSmi(x2, kExpectedAllocationSite);
+    __ Ldr(x10, FieldMemOperand(x2, HeapObject::kMapOffset));
+    __ AssertRegisterIsRoot(x10, Heap::kAllocationSiteMapRootIndex,
+                            kExpectedAllocationSite);
+  }
+
+  // Tail call into the stub that handles binary operations with allocation
+  // sites.
+  BinaryOpWithAllocationSiteStub stub(isolate(), state());
+  __ TailCallStub(&stub);
+}
+
+
+void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
+  // We need some extra registers for this stub, they have been allocated
+  // but we need to save them before using them.
+  regs_.Save(masm);
+
+  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
+    Label dont_need_remembered_set;
+
+    Register val = regs_.scratch0();
+    __ Ldr(val, MemOperand(regs_.address()));
+    __ JumpIfNotInNewSpace(val, &dont_need_remembered_set);
+
+    __ CheckPageFlagSet(regs_.object(), val, 1 << MemoryChunk::SCAN_ON_SCAVENGE,
+                        &dont_need_remembered_set);
+
+    // First notify the incremental marker if necessary, then update the
+    // remembered set.
+    CheckNeedsToInformIncrementalMarker(
+        masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
+    InformIncrementalMarker(masm);
+    regs_.Restore(masm);  // Restore the extra scratch registers we used.
+
+    __ RememberedSetHelper(object(), address(),
+                           value(),  // scratch1
+                           save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
+
+    __ Bind(&dont_need_remembered_set);
+  }
+
+  CheckNeedsToInformIncrementalMarker(
+      masm, kReturnOnNoNeedToInformIncrementalMarker, mode);
+  InformIncrementalMarker(masm);
+  regs_.Restore(masm);  // Restore the extra scratch registers we used.
+  __ Ret();
+}
+
+
+void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
+  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
+  Register address =
+    x0.Is(regs_.address()) ? regs_.scratch0() : regs_.address();
+  DCHECK(!address.Is(regs_.object()));
+  DCHECK(!address.Is(x0));
+  __ Mov(address, regs_.address());
+  __ Mov(x0, regs_.object());
+  __ Mov(x1, address);
+  __ Mov(x2, ExternalReference::isolate_address(isolate()));
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  ExternalReference function =
+      ExternalReference::incremental_marking_record_write_function(
+          isolate());
+  __ CallCFunction(function, 3, 0);
+
+  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
+}
+
+
+void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
+    MacroAssembler* masm,
+    OnNoNeedToInformIncrementalMarker on_no_need,
+    Mode mode) {
+  Label on_black;
+  Label need_incremental;
+  Label need_incremental_pop_scratch;
+
+  Register mem_chunk = regs_.scratch0();
+  Register counter = regs_.scratch1();
+  __ Bic(mem_chunk, regs_.object(), Page::kPageAlignmentMask);
+  __ Ldr(counter,
+         MemOperand(mem_chunk, MemoryChunk::kWriteBarrierCounterOffset));
+  __ Subs(counter, counter, 1);
+  __ Str(counter,
+         MemOperand(mem_chunk, MemoryChunk::kWriteBarrierCounterOffset));
+  __ B(mi, &need_incremental);
+
+  // If the object is not black we don't have to inform the incremental marker.
+  __ JumpIfBlack(regs_.object(), regs_.scratch0(), regs_.scratch1(), &on_black);
+
+  regs_.Restore(masm);  // Restore the extra scratch registers we used.
+  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
+    __ RememberedSetHelper(object(), address(),
+                           value(),  // scratch1
+                           save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
+  } else {
+    __ Ret();
+  }
+
+  __ Bind(&on_black);
+  // Get the value from the slot.
+  Register val = regs_.scratch0();
+  __ Ldr(val, MemOperand(regs_.address()));
+
+  if (mode == INCREMENTAL_COMPACTION) {
+    Label ensure_not_white;
+
+    __ CheckPageFlagClear(val, regs_.scratch1(),
+                          MemoryChunk::kEvacuationCandidateMask,
+                          &ensure_not_white);
+
+    __ CheckPageFlagClear(regs_.object(),
+                          regs_.scratch1(),
+                          MemoryChunk::kSkipEvacuationSlotsRecordingMask,
+                          &need_incremental);
+
+    __ Bind(&ensure_not_white);
+  }
+
+  // We need extra registers for this, so we push the object and the address
+  // register temporarily.
+  __ Push(regs_.address(), regs_.object());
+  __ EnsureNotWhite(val,
+                    regs_.scratch1(),  // Scratch.
+                    regs_.object(),    // Scratch.
+                    regs_.address(),   // Scratch.
+                    regs_.scratch2(),  // Scratch.
+                    &need_incremental_pop_scratch);
+  __ Pop(regs_.object(), regs_.address());
+
+  regs_.Restore(masm);  // Restore the extra scratch registers we used.
+  if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
+    __ RememberedSetHelper(object(), address(),
+                           value(),  // scratch1
+                           save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
+  } else {
+    __ Ret();
+  }
+
+  __ Bind(&need_incremental_pop_scratch);
+  __ Pop(regs_.object(), regs_.address());
+
+  __ Bind(&need_incremental);
+  // Fall through when we need to inform the incremental marker.
+}
+
+
+void RecordWriteStub::Generate(MacroAssembler* masm) {
+  Label skip_to_incremental_noncompacting;
+  Label skip_to_incremental_compacting;
+
+  // We patch these two first instructions back and forth between a nop and
+  // real branch when we start and stop incremental heap marking.
+  // Initially the stub is expected to be in STORE_BUFFER_ONLY mode, so 2 nops
+  // are generated.
+  // See RecordWriteStub::Patch for details.
+  {
+    InstructionAccurateScope scope(masm, 2);
+    __ adr(xzr, &skip_to_incremental_noncompacting);
+    __ adr(xzr, &skip_to_incremental_compacting);
+  }
+
+  if (remembered_set_action() == EMIT_REMEMBERED_SET) {
+    __ RememberedSetHelper(object(), address(),
+                           value(),  // scratch1
+                           save_fp_regs_mode(), MacroAssembler::kReturnAtEnd);
+  }
+  __ Ret();
+
+  __ Bind(&skip_to_incremental_noncompacting);
+  GenerateIncremental(masm, INCREMENTAL);
+
+  __ Bind(&skip_to_incremental_compacting);
+  GenerateIncremental(masm, INCREMENTAL_COMPACTION);
+}
+
+
+void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
+  // x0     value            element value to store
+  // x3     index_smi        element index as smi
+  // sp[0]  array_index_smi  array literal index in function as smi
+  // sp[1]  array            array literal
+
+  Register value = x0;
+  Register index_smi = x3;
+
+  Register array = x1;
+  Register array_map = x2;
+  Register array_index_smi = x4;
+  __ PeekPair(array_index_smi, array, 0);
+  __ Ldr(array_map, FieldMemOperand(array, JSObject::kMapOffset));
+
+  Label double_elements, smi_element, fast_elements, slow_elements;
+  Register bitfield2 = x10;
+  __ Ldrb(bitfield2, FieldMemOperand(array_map, Map::kBitField2Offset));
+
+  // Jump if array's ElementsKind is not FAST*_SMI_ELEMENTS, FAST_ELEMENTS or
+  // FAST_HOLEY_ELEMENTS.
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  STATIC_ASSERT(FAST_ELEMENTS == 2);
+  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+  __ Cmp(bitfield2, Map::kMaximumBitField2FastHoleyElementValue);
+  __ B(hi, &double_elements);
+
+  __ JumpIfSmi(value, &smi_element);
+
+  // Jump if array's ElementsKind is not FAST_ELEMENTS or FAST_HOLEY_ELEMENTS.
+  __ Tbnz(bitfield2, MaskToBit(FAST_ELEMENTS << Map::ElementsKindBits::kShift),
+          &fast_elements);
+
+  // Store into the array literal requires an elements transition. Call into
+  // the runtime.
+  __ Bind(&slow_elements);
+  __ Push(array, index_smi, value);
+  __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Ldr(x11, FieldMemOperand(x10, JSFunction::kLiteralsOffset));
+  __ Push(x11, array_index_smi);
+  __ TailCallRuntime(Runtime::kStoreArrayLiteralElement, 5, 1);
+
+  // Array literal has ElementsKind of FAST_*_ELEMENTS and value is an object.
+  __ Bind(&fast_elements);
+  __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
+  __ Add(x11, x10, Operand::UntagSmiAndScale(index_smi, kPointerSizeLog2));
+  __ Add(x11, x11, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Str(value, MemOperand(x11));
+  // Update the write barrier for the array store.
+  __ RecordWrite(x10, x11, value, kLRHasNotBeenSaved, kDontSaveFPRegs,
+                 EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ Ret();
+
+  // Array literal has ElementsKind of FAST_*_SMI_ELEMENTS or FAST_*_ELEMENTS,
+  // and value is Smi.
+  __ Bind(&smi_element);
+  __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
+  __ Add(x11, x10, Operand::UntagSmiAndScale(index_smi, kPointerSizeLog2));
+  __ Str(value, FieldMemOperand(x11, FixedArray::kHeaderSize));
+  __ Ret();
+
+  __ Bind(&double_elements);
+  __ Ldr(x10, FieldMemOperand(array, JSObject::kElementsOffset));
+  __ StoreNumberToDoubleElements(value, index_smi, x10, x11, d0,
+                                 &slow_elements);
+  __ Ret();
+}
+
+
+void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
+  CEntryStub ces(isolate(), 1, kSaveFPRegs);
+  __ Call(ces.GetCode(), RelocInfo::CODE_TARGET);
+  int parameter_count_offset =
+      StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
+  __ Ldr(x1, MemOperand(fp, parameter_count_offset));
+  if (function_mode() == JS_FUNCTION_STUB_MODE) {
+    __ Add(x1, x1, 1);
+  }
+  masm->LeaveFrame(StackFrame::STUB_FAILURE_TRAMPOLINE);
+  __ Drop(x1);
+  // Return to IC Miss stub, continuation still on stack.
+  __ Ret();
+}
+
+
+void LoadICTrampolineStub::Generate(MacroAssembler* masm) {
+  EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
+  VectorLoadStub stub(isolate(), state());
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void KeyedLoadICTrampolineStub::Generate(MacroAssembler* masm) {
+  EmitLoadTypeFeedbackVector(masm, VectorLoadICDescriptor::VectorRegister());
+  VectorKeyedLoadStub stub(isolate());
+  __ Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+static unsigned int GetProfileEntryHookCallSize(MacroAssembler* masm) {
+  // The entry hook is a "BumpSystemStackPointer" instruction (sub),
+  // followed by a "Push lr" instruction, followed by a call.
+  unsigned int size =
+      Assembler::kCallSizeWithRelocation + (2 * kInstructionSize);
+  if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+    // If ALWAYS_ALIGN_CSP then there will be an extra bic instruction in
+    // "BumpSystemStackPointer".
+    size += kInstructionSize;
+  }
+  return size;
+}
+
+
+void ProfileEntryHookStub::MaybeCallEntryHook(MacroAssembler* masm) {
+  if (masm->isolate()->function_entry_hook() != NULL) {
+    ProfileEntryHookStub stub(masm->isolate());
+    Assembler::BlockConstPoolScope no_const_pools(masm);
+    DontEmitDebugCodeScope no_debug_code(masm);
+    Label entry_hook_call_start;
+    __ Bind(&entry_hook_call_start);
+    __ Push(lr);
+    __ CallStub(&stub);
+    DCHECK(masm->SizeOfCodeGeneratedSince(&entry_hook_call_start) ==
+           GetProfileEntryHookCallSize(masm));
+
+    __ Pop(lr);
+  }
+}
+
+
+void ProfileEntryHookStub::Generate(MacroAssembler* masm) {
+  MacroAssembler::NoUseRealAbortsScope no_use_real_aborts(masm);
+
+  // Save all kCallerSaved registers (including lr), since this can be called
+  // from anywhere.
+  // TODO(jbramley): What about FP registers?
+  __ PushCPURegList(kCallerSaved);
+  DCHECK(kCallerSaved.IncludesAliasOf(lr));
+  const int kNumSavedRegs = kCallerSaved.Count();
+
+  // Compute the function's address as the first argument.
+  __ Sub(x0, lr, GetProfileEntryHookCallSize(masm));
+
+#if V8_HOST_ARCH_ARM64
+  uintptr_t entry_hook =
+      reinterpret_cast<uintptr_t>(isolate()->function_entry_hook());
+  __ Mov(x10, entry_hook);
+#else
+  // Under the simulator we need to indirect the entry hook through a trampoline
+  // function at a known address.
+  ApiFunction dispatcher(FUNCTION_ADDR(EntryHookTrampoline));
+  __ Mov(x10, Operand(ExternalReference(&dispatcher,
+                                        ExternalReference::BUILTIN_CALL,
+                                        isolate())));
+  // It additionally takes an isolate as a third parameter
+  __ Mov(x2, ExternalReference::isolate_address(isolate()));
+#endif
+
+  // The caller's return address is above the saved temporaries.
+  // Grab its location for the second argument to the hook.
+  __ Add(x1, __ StackPointer(), kNumSavedRegs * kPointerSize);
+
+  {
+    // Create a dummy frame, as CallCFunction requires this.
+    FrameScope frame(masm, StackFrame::MANUAL);
+    __ CallCFunction(x10, 2, 0);
+  }
+
+  __ PopCPURegList(kCallerSaved);
+  __ Ret();
+}
+
+
+void DirectCEntryStub::Generate(MacroAssembler* masm) {
+  // When calling into C++ code the stack pointer must be csp.
+  // Therefore this code must use csp for peek/poke operations when the
+  // stub is generated. When the stub is called
+  // (via DirectCEntryStub::GenerateCall), the caller must setup an ExitFrame
+  // and configure the stack pointer *before* doing the call.
+  const Register old_stack_pointer = __ StackPointer();
+  __ SetStackPointer(csp);
+
+  // Put return address on the stack (accessible to GC through exit frame pc).
+  __ Poke(lr, 0);
+  // Call the C++ function.
+  __ Blr(x10);
+  // Return to calling code.
+  __ Peek(lr, 0);
+  __ AssertFPCRState();
+  __ Ret();
+
+  __ SetStackPointer(old_stack_pointer);
+}
+
+void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
+                                    Register target) {
+  // Make sure the caller configured the stack pointer (see comment in
+  // DirectCEntryStub::Generate).
+  DCHECK(csp.Is(__ StackPointer()));
+
+  intptr_t code =
+      reinterpret_cast<intptr_t>(GetCode().location());
+  __ Mov(lr, Operand(code, RelocInfo::CODE_TARGET));
+  __ Mov(x10, target);
+  // Branch to the stub.
+  __ Blr(lr);
+}
+
+
+// Probe the name dictionary in the 'elements' register.
+// Jump to the 'done' label if a property with the given name is found.
+// Jump to the 'miss' label otherwise.
+//
+// If lookup was successful 'scratch2' will be equal to elements + 4 * index.
+// 'elements' and 'name' registers are preserved on miss.
+void NameDictionaryLookupStub::GeneratePositiveLookup(
+    MacroAssembler* masm,
+    Label* miss,
+    Label* done,
+    Register elements,
+    Register name,
+    Register scratch1,
+    Register scratch2) {
+  DCHECK(!AreAliased(elements, name, scratch1, scratch2));
+
+  // Assert that name contains a string.
+  __ AssertName(name);
+
+  // Compute the capacity mask.
+  __ Ldrsw(scratch1, UntagSmiFieldMemOperand(elements, kCapacityOffset));
+  __ Sub(scratch1, scratch1, 1);
+
+  // Generate an unrolled loop that performs a few probes before giving up.
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    __ Ldr(scratch2, FieldMemOperand(name, Name::kHashFieldOffset));
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      DCHECK(NameDictionary::GetProbeOffset(i) <
+          1 << (32 - Name::kHashFieldOffset));
+      __ Add(scratch2, scratch2, Operand(
+          NameDictionary::GetProbeOffset(i) << Name::kHashShift));
+    }
+    __ And(scratch2, scratch1, Operand(scratch2, LSR, Name::kHashShift));
+
+    // Scale the index by multiplying by the element size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    __ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
+
+    // Check if the key is identical to the name.
+    UseScratchRegisterScope temps(masm);
+    Register scratch3 = temps.AcquireX();
+    __ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
+    __ Ldr(scratch3, FieldMemOperand(scratch2, kElementsStartOffset));
+    __ Cmp(name, scratch3);
+    __ B(eq, done);
+  }
+
+  // The inlined probes didn't find the entry.
+  // Call the complete stub to scan the whole dictionary.
+
+  CPURegList spill_list(CPURegister::kRegister, kXRegSizeInBits, 0, 6);
+  spill_list.Combine(lr);
+  spill_list.Remove(scratch1);
+  spill_list.Remove(scratch2);
+
+  __ PushCPURegList(spill_list);
+
+  if (name.is(x0)) {
+    DCHECK(!elements.is(x1));
+    __ Mov(x1, name);
+    __ Mov(x0, elements);
+  } else {
+    __ Mov(x0, elements);
+    __ Mov(x1, name);
+  }
+
+  Label not_found;
+  NameDictionaryLookupStub stub(masm->isolate(), POSITIVE_LOOKUP);
+  __ CallStub(&stub);
+  __ Cbz(x0, &not_found);
+  __ Mov(scratch2, x2);  // Move entry index into scratch2.
+  __ PopCPURegList(spill_list);
+  __ B(done);
+
+  __ Bind(&not_found);
+  __ PopCPURegList(spill_list);
+  __ B(miss);
+}
+
+
+void NameDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm,
+                                                      Label* miss,
+                                                      Label* done,
+                                                      Register receiver,
+                                                      Register properties,
+                                                      Handle<Name> name,
+                                                      Register scratch0) {
+  DCHECK(!AreAliased(receiver, properties, scratch0));
+  DCHECK(name->IsUniqueName());
+  // If names of slots in range from 1 to kProbes - 1 for the hash value are
+  // not equal to the name and kProbes-th slot is not used (its name is the
+  // undefined value), it guarantees the hash table doesn't contain the
+  // property. It's true even if some slots represent deleted properties
+  // (their names are the hole value).
+  for (int i = 0; i < kInlinedProbes; i++) {
+    // scratch0 points to properties hash.
+    // Compute the masked index: (hash + i + i * i) & mask.
+    Register index = scratch0;
+    // Capacity is smi 2^n.
+    __ Ldrsw(index, UntagSmiFieldMemOperand(properties, kCapacityOffset));
+    __ Sub(index, index, 1);
+    __ And(index, index, name->Hash() + NameDictionary::GetProbeOffset(i));
+
+    // Scale the index by multiplying by the entry size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    __ Add(index, index, Operand(index, LSL, 1));  // index *= 3.
+
+    Register entity_name = scratch0;
+    // Having undefined at this place means the name is not contained.
+    Register tmp = index;
+    __ Add(tmp, properties, Operand(index, LSL, kPointerSizeLog2));
+    __ Ldr(entity_name, FieldMemOperand(tmp, kElementsStartOffset));
+
+    __ JumpIfRoot(entity_name, Heap::kUndefinedValueRootIndex, done);
+
+    // Stop if found the property.
+    __ Cmp(entity_name, Operand(name));
+    __ B(eq, miss);
+
+    Label good;
+    __ JumpIfRoot(entity_name, Heap::kTheHoleValueRootIndex, &good);
+
+    // Check if the entry name is not a unique name.
+    __ Ldr(entity_name, FieldMemOperand(entity_name, HeapObject::kMapOffset));
+    __ Ldrb(entity_name,
+            FieldMemOperand(entity_name, Map::kInstanceTypeOffset));
+    __ JumpIfNotUniqueNameInstanceType(entity_name, miss);
+    __ Bind(&good);
+  }
+
+  CPURegList spill_list(CPURegister::kRegister, kXRegSizeInBits, 0, 6);
+  spill_list.Combine(lr);
+  spill_list.Remove(scratch0);  // Scratch registers don't need to be preserved.
+
+  __ PushCPURegList(spill_list);
+
+  __ Ldr(x0, FieldMemOperand(receiver, JSObject::kPropertiesOffset));
+  __ Mov(x1, Operand(name));
+  NameDictionaryLookupStub stub(masm->isolate(), NEGATIVE_LOOKUP);
+  __ CallStub(&stub);
+  // Move stub return value to scratch0. Note that scratch0 is not included in
+  // spill_list and won't be clobbered by PopCPURegList.
+  __ Mov(scratch0, x0);
+  __ PopCPURegList(spill_list);
+
+  __ Cbz(scratch0, done);
+  __ B(miss);
+}
+
+
+void NameDictionaryLookupStub::Generate(MacroAssembler* masm) {
+  // This stub overrides SometimesSetsUpAFrame() to return false. That means
+  // we cannot call anything that could cause a GC from this stub.
+  //
+  // Arguments are in x0 and x1:
+  //   x0: property dictionary.
+  //   x1: the name of the property we are looking for.
+  //
+  // Return value is in x0 and is zero if lookup failed, non zero otherwise.
+  // If the lookup is successful, x2 will contains the index of the entry.
+
+  Register result = x0;
+  Register dictionary = x0;
+  Register key = x1;
+  Register index = x2;
+  Register mask = x3;
+  Register hash = x4;
+  Register undefined = x5;
+  Register entry_key = x6;
+
+  Label in_dictionary, maybe_in_dictionary, not_in_dictionary;
+
+  __ Ldrsw(mask, UntagSmiFieldMemOperand(dictionary, kCapacityOffset));
+  __ Sub(mask, mask, 1);
+
+  __ Ldr(hash, FieldMemOperand(key, Name::kHashFieldOffset));
+  __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex);
+
+  for (int i = kInlinedProbes; i < kTotalProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    // Capacity is smi 2^n.
+    if (i > 0) {
+      // Add the probe offset (i + i * i) left shifted to avoid right shifting
+      // the hash in a separate instruction. The value hash + i + i * i is right
+      // shifted in the following and instruction.
+      DCHECK(NameDictionary::GetProbeOffset(i) <
+             1 << (32 - Name::kHashFieldOffset));
+      __ Add(index, hash,
+             NameDictionary::GetProbeOffset(i) << Name::kHashShift);
+    } else {
+      __ Mov(index, hash);
+    }
+    __ And(index, mask, Operand(index, LSR, Name::kHashShift));
+
+    // Scale the index by multiplying by the entry size.
+    DCHECK(NameDictionary::kEntrySize == 3);
+    __ Add(index, index, Operand(index, LSL, 1));  // index *= 3.
+
+    __ Add(index, dictionary, Operand(index, LSL, kPointerSizeLog2));
+    __ Ldr(entry_key, FieldMemOperand(index, kElementsStartOffset));
+
+    // Having undefined at this place means the name is not contained.
+    __ Cmp(entry_key, undefined);
+    __ B(eq, &not_in_dictionary);
+
+    // Stop if found the property.
+    __ Cmp(entry_key, key);
+    __ B(eq, &in_dictionary);
+
+    if (i != kTotalProbes - 1 && mode() == NEGATIVE_LOOKUP) {
+      // Check if the entry name is not a unique name.
+      __ Ldr(entry_key, FieldMemOperand(entry_key, HeapObject::kMapOffset));
+      __ Ldrb(entry_key, FieldMemOperand(entry_key, Map::kInstanceTypeOffset));
+      __ JumpIfNotUniqueNameInstanceType(entry_key, &maybe_in_dictionary);
+    }
+  }
+
+  __ Bind(&maybe_in_dictionary);
+  // If we are doing negative lookup then probing failure should be
+  // treated as a lookup success. For positive lookup, probing failure
+  // should be treated as lookup failure.
+  if (mode() == POSITIVE_LOOKUP) {
+    __ Mov(result, 0);
+    __ Ret();
+  }
+
+  __ Bind(&in_dictionary);
+  __ Mov(result, 1);
+  __ Ret();
+
+  __ Bind(&not_in_dictionary);
+  __ Mov(result, 0);
+  __ Ret();
+}
+
+
+template<class T>
+static void CreateArrayDispatch(MacroAssembler* masm,
+                                AllocationSiteOverrideMode mode) {
+  ASM_LOCATION("CreateArrayDispatch");
+  if (mode == DISABLE_ALLOCATION_SITES) {
+    T stub(masm->isolate(), GetInitialFastElementsKind(), mode);
+     __ TailCallStub(&stub);
+
+  } else if (mode == DONT_OVERRIDE) {
+    Register kind = x3;
+    int last_index =
+        GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
+    for (int i = 0; i <= last_index; ++i) {
+      Label next;
+      ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
+      // TODO(jbramley): Is this the best way to handle this? Can we make the
+      // tail calls conditional, rather than hopping over each one?
+      __ CompareAndBranch(kind, candidate_kind, ne, &next);
+      T stub(masm->isolate(), candidate_kind);
+      __ TailCallStub(&stub);
+      __ Bind(&next);
+    }
+
+    // If we reached this point there is a problem.
+    __ Abort(kUnexpectedElementsKindInArrayConstructor);
+
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+// TODO(jbramley): If this needs to be a special case, make it a proper template
+// specialization, and not a separate function.
+static void CreateArrayDispatchOneArgument(MacroAssembler* masm,
+                                           AllocationSiteOverrideMode mode) {
+  ASM_LOCATION("CreateArrayDispatchOneArgument");
+  // x0 - argc
+  // x1 - constructor?
+  // x2 - allocation site (if mode != DISABLE_ALLOCATION_SITES)
+  // x3 - kind (if mode != DISABLE_ALLOCATION_SITES)
+  // sp[0] - last argument
+
+  Register allocation_site = x2;
+  Register kind = x3;
+
+  Label normal_sequence;
+  if (mode == DONT_OVERRIDE) {
+    STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+    STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+    STATIC_ASSERT(FAST_ELEMENTS == 2);
+    STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+    STATIC_ASSERT(FAST_DOUBLE_ELEMENTS == 4);
+    STATIC_ASSERT(FAST_HOLEY_DOUBLE_ELEMENTS == 5);
+
+    // Is the low bit set? If so, the array is holey.
+    __ Tbnz(kind, 0, &normal_sequence);
+  }
+
+  // Look at the last argument.
+  // TODO(jbramley): What does a 0 argument represent?
+  __ Peek(x10, 0);
+  __ Cbz(x10, &normal_sequence);
+
+  if (mode == DISABLE_ALLOCATION_SITES) {
+    ElementsKind initial = GetInitialFastElementsKind();
+    ElementsKind holey_initial = GetHoleyElementsKind(initial);
+
+    ArraySingleArgumentConstructorStub stub_holey(masm->isolate(),
+                                                  holey_initial,
+                                                  DISABLE_ALLOCATION_SITES);
+    __ TailCallStub(&stub_holey);
+
+    __ Bind(&normal_sequence);
+    ArraySingleArgumentConstructorStub stub(masm->isolate(),
+                                            initial,
+                                            DISABLE_ALLOCATION_SITES);
+    __ TailCallStub(&stub);
+  } else if (mode == DONT_OVERRIDE) {
+    // We are going to create a holey array, but our kind is non-holey.
+    // Fix kind and retry (only if we have an allocation site in the slot).
+    __ Orr(kind, kind, 1);
+
+    if (FLAG_debug_code) {
+      __ Ldr(x10, FieldMemOperand(allocation_site, 0));
+      __ JumpIfNotRoot(x10, Heap::kAllocationSiteMapRootIndex,
+                       &normal_sequence);
+      __ Assert(eq, kExpectedAllocationSite);
+    }
+
+    // Save the resulting elements kind in type info. We can't just store 'kind'
+    // in the AllocationSite::transition_info field because elements kind is
+    // restricted to a portion of the field; upper bits need to be left alone.
+    STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0);
+    __ Ldr(x11, FieldMemOperand(allocation_site,
+                                AllocationSite::kTransitionInfoOffset));
+    __ Add(x11, x11, Smi::FromInt(kFastElementsKindPackedToHoley));
+    __ Str(x11, FieldMemOperand(allocation_site,
+                                AllocationSite::kTransitionInfoOffset));
+
+    __ Bind(&normal_sequence);
+    int last_index =
+        GetSequenceIndexFromFastElementsKind(TERMINAL_FAST_ELEMENTS_KIND);
+    for (int i = 0; i <= last_index; ++i) {
+      Label next;
+      ElementsKind candidate_kind = GetFastElementsKindFromSequenceIndex(i);
+      __ CompareAndBranch(kind, candidate_kind, ne, &next);
+      ArraySingleArgumentConstructorStub stub(masm->isolate(), candidate_kind);
+      __ TailCallStub(&stub);
+      __ Bind(&next);
+    }
+
+    // If we reached this point there is a problem.
+    __ Abort(kUnexpectedElementsKindInArrayConstructor);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+template<class T>
+static void ArrayConstructorStubAheadOfTimeHelper(Isolate* isolate) {
+  int to_index = GetSequenceIndexFromFastElementsKind(
+      TERMINAL_FAST_ELEMENTS_KIND);
+  for (int i = 0; i <= to_index; ++i) {
+    ElementsKind kind = GetFastElementsKindFromSequenceIndex(i);
+    T stub(isolate, kind);
+    stub.GetCode();
+    if (AllocationSite::GetMode(kind) != DONT_TRACK_ALLOCATION_SITE) {
+      T stub1(isolate, kind, DISABLE_ALLOCATION_SITES);
+      stub1.GetCode();
+    }
+  }
+}
+
+
+void ArrayConstructorStubBase::GenerateStubsAheadOfTime(Isolate* isolate) {
+  ArrayConstructorStubAheadOfTimeHelper<ArrayNoArgumentConstructorStub>(
+      isolate);
+  ArrayConstructorStubAheadOfTimeHelper<ArraySingleArgumentConstructorStub>(
+      isolate);
+  ArrayConstructorStubAheadOfTimeHelper<ArrayNArgumentsConstructorStub>(
+      isolate);
+}
+
+
+void InternalArrayConstructorStubBase::GenerateStubsAheadOfTime(
+    Isolate* isolate) {
+  ElementsKind kinds[2] = { FAST_ELEMENTS, FAST_HOLEY_ELEMENTS };
+  for (int i = 0; i < 2; i++) {
+    // For internal arrays we only need a few things
+    InternalArrayNoArgumentConstructorStub stubh1(isolate, kinds[i]);
+    stubh1.GetCode();
+    InternalArraySingleArgumentConstructorStub stubh2(isolate, kinds[i]);
+    stubh2.GetCode();
+    InternalArrayNArgumentsConstructorStub stubh3(isolate, kinds[i]);
+    stubh3.GetCode();
+  }
+}
+
+
+void ArrayConstructorStub::GenerateDispatchToArrayStub(
+    MacroAssembler* masm,
+    AllocationSiteOverrideMode mode) {
+  Register argc = x0;
+  if (argument_count() == ANY) {
+    Label zero_case, n_case;
+    __ Cbz(argc, &zero_case);
+    __ Cmp(argc, 1);
+    __ B(ne, &n_case);
+
+    // One argument.
+    CreateArrayDispatchOneArgument(masm, mode);
+
+    __ Bind(&zero_case);
+    // No arguments.
+    CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+
+    __ Bind(&n_case);
+    // N arguments.
+    CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+
+  } else if (argument_count() == NONE) {
+    CreateArrayDispatch<ArrayNoArgumentConstructorStub>(masm, mode);
+  } else if (argument_count() == ONE) {
+    CreateArrayDispatchOneArgument(masm, mode);
+  } else if (argument_count() == MORE_THAN_ONE) {
+    CreateArrayDispatch<ArrayNArgumentsConstructorStub>(masm, mode);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void ArrayConstructorStub::Generate(MacroAssembler* masm) {
+  ASM_LOCATION("ArrayConstructorStub::Generate");
+  // ----------- S t a t e -------------
+  //  -- x0 : argc (only if argument_count() == ANY)
+  //  -- x1 : constructor
+  //  -- x2 : AllocationSite or undefined
+  //  -- sp[0] : return address
+  //  -- sp[4] : last argument
+  // -----------------------------------
+  Register constructor = x1;
+  Register allocation_site = x2;
+
+  if (FLAG_debug_code) {
+    // The array construct code is only set for the global and natives
+    // builtin Array functions which always have maps.
+
+    Label unexpected_map, map_ok;
+    // Initial map for the builtin Array function should be a map.
+    __ Ldr(x10, FieldMemOperand(constructor,
+                                JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    __ JumpIfSmi(x10, &unexpected_map);
+    __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok);
+    __ Bind(&unexpected_map);
+    __ Abort(kUnexpectedInitialMapForArrayFunction);
+    __ Bind(&map_ok);
+
+    // We should either have undefined in the allocation_site register or a
+    // valid AllocationSite.
+    __ AssertUndefinedOrAllocationSite(allocation_site, x10);
+  }
+
+  Register kind = x3;
+  Label no_info;
+  // Get the elements kind and case on that.
+  __ JumpIfRoot(allocation_site, Heap::kUndefinedValueRootIndex, &no_info);
+
+  __ Ldrsw(kind,
+           UntagSmiFieldMemOperand(allocation_site,
+                                   AllocationSite::kTransitionInfoOffset));
+  __ And(kind, kind, AllocationSite::ElementsKindBits::kMask);
+  GenerateDispatchToArrayStub(masm, DONT_OVERRIDE);
+
+  __ Bind(&no_info);
+  GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES);
+}
+
+
+void InternalArrayConstructorStub::GenerateCase(
+    MacroAssembler* masm, ElementsKind kind) {
+  Label zero_case, n_case;
+  Register argc = x0;
+
+  __ Cbz(argc, &zero_case);
+  __ CompareAndBranch(argc, 1, ne, &n_case);
+
+  // One argument.
+  if (IsFastPackedElementsKind(kind)) {
+    Label packed_case;
+
+    // We might need to create a holey array; look at the first argument.
+    __ Peek(x10, 0);
+    __ Cbz(x10, &packed_case);
+
+    InternalArraySingleArgumentConstructorStub
+        stub1_holey(isolate(), GetHoleyElementsKind(kind));
+    __ TailCallStub(&stub1_holey);
+
+    __ Bind(&packed_case);
+  }
+  InternalArraySingleArgumentConstructorStub stub1(isolate(), kind);
+  __ TailCallStub(&stub1);
+
+  __ Bind(&zero_case);
+  // No arguments.
+  InternalArrayNoArgumentConstructorStub stub0(isolate(), kind);
+  __ TailCallStub(&stub0);
+
+  __ Bind(&n_case);
+  // N arguments.
+  InternalArrayNArgumentsConstructorStub stubN(isolate(), kind);
+  __ TailCallStub(&stubN);
+}
+
+
+void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0 : argc
+  //  -- x1 : constructor
+  //  -- sp[0] : return address
+  //  -- sp[4] : last argument
+  // -----------------------------------
+
+  Register constructor = x1;
+
+  if (FLAG_debug_code) {
+    // The array construct code is only set for the global and natives
+    // builtin Array functions which always have maps.
+
+    Label unexpected_map, map_ok;
+    // Initial map for the builtin Array function should be a map.
+    __ Ldr(x10, FieldMemOperand(constructor,
+                                JSFunction::kPrototypeOrInitialMapOffset));
+    // Will both indicate a NULL and a Smi.
+    __ JumpIfSmi(x10, &unexpected_map);
+    __ JumpIfObjectType(x10, x10, x11, MAP_TYPE, &map_ok);
+    __ Bind(&unexpected_map);
+    __ Abort(kUnexpectedInitialMapForArrayFunction);
+    __ Bind(&map_ok);
+  }
+
+  Register kind = w3;
+  // Figure out the right elements kind
+  __ Ldr(x10, FieldMemOperand(constructor,
+                              JSFunction::kPrototypeOrInitialMapOffset));
+
+  // Retrieve elements_kind from map.
+  __ LoadElementsKindFromMap(kind, x10);
+
+  if (FLAG_debug_code) {
+    Label done;
+    __ Cmp(x3, FAST_ELEMENTS);
+    __ Ccmp(x3, FAST_HOLEY_ELEMENTS, ZFlag, ne);
+    __ Assert(eq, kInvalidElementsKindForInternalArrayOrInternalPackedArray);
+  }
+
+  Label fast_elements_case;
+  __ CompareAndBranch(kind, FAST_ELEMENTS, eq, &fast_elements_case);
+  GenerateCase(masm, FAST_HOLEY_ELEMENTS);
+
+  __ Bind(&fast_elements_case);
+  GenerateCase(masm, FAST_ELEMENTS);
+}
+
+
+void CallApiFunctionStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- x0                  : callee
+  //  -- x4                  : call_data
+  //  -- x2                  : holder
+  //  -- x1                  : api_function_address
+  //  -- cp                  : context
+  //  --
+  //  -- sp[0]               : last argument
+  //  -- ...
+  //  -- sp[(argc - 1) * 8]  : first argument
+  //  -- sp[argc * 8]        : receiver
+  // -----------------------------------
+
+  Register callee = x0;
+  Register call_data = x4;
+  Register holder = x2;
+  Register api_function_address = x1;
+  Register context = cp;
+
+  int argc = this->argc();
+  bool is_store = this->is_store();
+  bool call_data_undefined = this->call_data_undefined();
+
+  typedef FunctionCallbackArguments FCA;
+
+  STATIC_ASSERT(FCA::kContextSaveIndex == 6);
+  STATIC_ASSERT(FCA::kCalleeIndex == 5);
+  STATIC_ASSERT(FCA::kDataIndex == 4);
+  STATIC_ASSERT(FCA::kReturnValueOffset == 3);
+  STATIC_ASSERT(FCA::kReturnValueDefaultValueIndex == 2);
+  STATIC_ASSERT(FCA::kIsolateIndex == 1);
+  STATIC_ASSERT(FCA::kHolderIndex == 0);
+  STATIC_ASSERT(FCA::kArgsLength == 7);
+
+  // FunctionCallbackArguments: context, callee and call data.
+  __ Push(context, callee, call_data);
+
+  // Load context from callee
+  __ Ldr(context, FieldMemOperand(callee, JSFunction::kContextOffset));
+
+  if (!call_data_undefined) {
+    __ LoadRoot(call_data, Heap::kUndefinedValueRootIndex);
+  }
+  Register isolate_reg = x5;
+  __ Mov(isolate_reg, ExternalReference::isolate_address(isolate()));
+
+  // FunctionCallbackArguments:
+  //    return value, return value default, isolate, holder.
+  __ Push(call_data, call_data, isolate_reg, holder);
+
+  // Prepare arguments.
+  Register args = x6;
+  __ Mov(args, masm->StackPointer());
+
+  // Allocate the v8::Arguments structure in the arguments' space, since it's
+  // not controlled by GC.
+  const int kApiStackSpace = 4;
+
+  // Allocate space for CallApiFunctionAndReturn can store some scratch
+  // registeres on the stack.
+  const int kCallApiFunctionSpillSpace = 4;
+
+  FrameScope frame_scope(masm, StackFrame::MANUAL);
+  __ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
+
+  DCHECK(!AreAliased(x0, api_function_address));
+  // x0 = FunctionCallbackInfo&
+  // Arguments is after the return address.
+  __ Add(x0, masm->StackPointer(), 1 * kPointerSize);
+  // FunctionCallbackInfo::implicit_args_ and FunctionCallbackInfo::values_
+  __ Add(x10, args, Operand((FCA::kArgsLength - 1 + argc) * kPointerSize));
+  __ Stp(args, x10, MemOperand(x0, 0 * kPointerSize));
+  // FunctionCallbackInfo::length_ = argc and
+  // FunctionCallbackInfo::is_construct_call = 0
+  __ Mov(x10, argc);
+  __ Stp(x10, xzr, MemOperand(x0, 2 * kPointerSize));
+
+  const int kStackUnwindSpace = argc + FCA::kArgsLength + 1;
+  ExternalReference thunk_ref =
+      ExternalReference::invoke_function_callback(isolate());
+
+  AllowExternalCallThatCantCauseGC scope(masm);
+  MemOperand context_restore_operand(
+      fp, (2 + FCA::kContextSaveIndex) * kPointerSize);
+  // Stores return the first js argument
+  int return_value_offset = 0;
+  if (is_store) {
+    return_value_offset = 2 + FCA::kArgsLength;
+  } else {
+    return_value_offset = 2 + FCA::kReturnValueOffset;
+  }
+  MemOperand return_value_operand(fp, return_value_offset * kPointerSize);
+
+  const int spill_offset = 1 + kApiStackSpace;
+  __ CallApiFunctionAndReturn(api_function_address,
+                              thunk_ref,
+                              kStackUnwindSpace,
+                              spill_offset,
+                              return_value_operand,
+                              &context_restore_operand);
+}
+
+
+void CallApiGetterStub::Generate(MacroAssembler* masm) {
+  // ----------- S t a t e -------------
+  //  -- sp[0]                  : name
+  //  -- sp[8 - kArgsLength*8]  : PropertyCallbackArguments object
+  //  -- ...
+  //  -- x2                     : api_function_address
+  // -----------------------------------
+
+  Register api_function_address = ApiGetterDescriptor::function_address();
+  DCHECK(api_function_address.is(x2));
+
+  __ Mov(x0, masm->StackPointer());  // x0 = Handle<Name>
+  __ Add(x1, x0, 1 * kPointerSize);  // x1 = PCA
+
+  const int kApiStackSpace = 1;
+
+  // Allocate space for CallApiFunctionAndReturn can store some scratch
+  // registeres on the stack.
+  const int kCallApiFunctionSpillSpace = 4;
+
+  FrameScope frame_scope(masm, StackFrame::MANUAL);
+  __ EnterExitFrame(false, x10, kApiStackSpace + kCallApiFunctionSpillSpace);
+
+  // Create PropertyAccessorInfo instance on the stack above the exit frame with
+  // x1 (internal::Object** args_) as the data.
+  __ Poke(x1, 1 * kPointerSize);
+  __ Add(x1, masm->StackPointer(), 1 * kPointerSize);  // x1 = AccessorInfo&
+
+  const int kStackUnwindSpace = PropertyCallbackArguments::kArgsLength + 1;
+
+  ExternalReference thunk_ref =
+      ExternalReference::invoke_accessor_getter_callback(isolate());
+
+  const int spill_offset = 1 + kApiStackSpace;
+  __ CallApiFunctionAndReturn(api_function_address,
+                              thunk_ref,
+                              kStackUnwindSpace,
+                              spill_offset,
+                              MemOperand(fp, 6 * kPointerSize),
+                              NULL);
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/code-stubs-arm64.h b/src/arm64/code-stubs-arm64.h
new file mode 100644
index 0000000..03dab5b
--- /dev/null
+++ b/src/arm64/code-stubs-arm64.h
@@ -0,0 +1,387 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_CODE_STUBS_ARM64_H_
+#define V8_ARM64_CODE_STUBS_ARM64_H_
+
+namespace v8 {
+namespace internal {
+
+
+void ArrayNativeCode(MacroAssembler* masm, Label* call_generic_code);
+
+
+class StringHelper : public AllStatic {
+ public:
+  // Compares two flat one-byte strings and returns result in x0.
+  static void GenerateCompareFlatOneByteStrings(
+      MacroAssembler* masm, Register left, Register right, Register scratch1,
+      Register scratch2, Register scratch3, Register scratch4);
+
+  // Compare two flat one-byte strings for equality and returns result in x0.
+  static void GenerateFlatOneByteStringEquals(MacroAssembler* masm,
+                                              Register left, Register right,
+                                              Register scratch1,
+                                              Register scratch2,
+                                              Register scratch3);
+
+ private:
+  static void GenerateOneByteCharsCompareLoop(
+      MacroAssembler* masm, Register left, Register right, Register length,
+      Register scratch1, Register scratch2, Label* chars_not_equal);
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringHelper);
+};
+
+
+class StoreRegistersStateStub: public PlatformCodeStub {
+ public:
+  explicit StoreRegistersStateStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  static Register to_be_pushed_lr() { return ip0; }
+
+  static void GenerateAheadOfTime(Isolate* isolate);
+
+ private:
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(StoreRegistersState, PlatformCodeStub);
+};
+
+
+class RestoreRegistersStateStub: public PlatformCodeStub {
+ public:
+  explicit RestoreRegistersStateStub(Isolate* isolate)
+      : PlatformCodeStub(isolate) {}
+
+  static void GenerateAheadOfTime(Isolate* isolate);
+
+ private:
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(RestoreRegistersState, PlatformCodeStub);
+};
+
+
+class RecordWriteStub: public PlatformCodeStub {
+ public:
+  // Stub to record the write of 'value' at 'address' in 'object'.
+  // Typically 'address' = 'object' + <some offset>.
+  // See MacroAssembler::RecordWriteField() for example.
+  RecordWriteStub(Isolate* isolate,
+                  Register object,
+                  Register value,
+                  Register address,
+                  RememberedSetAction remembered_set_action,
+                  SaveFPRegsMode fp_mode)
+      : PlatformCodeStub(isolate),
+        regs_(object,   // An input reg.
+              address,  // An input reg.
+              value) {  // One scratch reg.
+    DCHECK(object.Is64Bits());
+    DCHECK(value.Is64Bits());
+    DCHECK(address.Is64Bits());
+    minor_key_ = ObjectBits::encode(object.code()) |
+                 ValueBits::encode(value.code()) |
+                 AddressBits::encode(address.code()) |
+                 RememberedSetActionBits::encode(remembered_set_action) |
+                 SaveFPRegsModeBits::encode(fp_mode);
+  }
+
+  RecordWriteStub(uint32_t key, Isolate* isolate)
+      : PlatformCodeStub(key, isolate), regs_(object(), address(), value()) {}
+
+  enum Mode {
+    STORE_BUFFER_ONLY,
+    INCREMENTAL,
+    INCREMENTAL_COMPACTION
+  };
+
+  virtual bool SometimesSetsUpAFrame() { return false; }
+
+  static Mode GetMode(Code* stub) {
+    // Find the mode depending on the first two instructions.
+    Instruction* instr1 =
+      reinterpret_cast<Instruction*>(stub->instruction_start());
+    Instruction* instr2 = instr1->following();
+
+    if (instr1->IsUncondBranchImm()) {
+      DCHECK(instr2->IsPCRelAddressing() && (instr2->Rd() == xzr.code()));
+      return INCREMENTAL;
+    }
+
+    DCHECK(instr1->IsPCRelAddressing() && (instr1->Rd() == xzr.code()));
+
+    if (instr2->IsUncondBranchImm()) {
+      return INCREMENTAL_COMPACTION;
+    }
+
+    DCHECK(instr2->IsPCRelAddressing());
+
+    return STORE_BUFFER_ONLY;
+  }
+
+  // We patch the two first instructions of the stub back and forth between an
+  // adr and branch when we start and stop incremental heap marking.
+  // The branch is
+  //   b label
+  // The adr is
+  //   adr xzr label
+  // so effectively a nop.
+  static void Patch(Code* stub, Mode mode) {
+    // We are going to patch the two first instructions of the stub.
+    PatchingAssembler patcher(
+        reinterpret_cast<Instruction*>(stub->instruction_start()), 2);
+    Instruction* instr1 = patcher.InstructionAt(0);
+    Instruction* instr2 = patcher.InstructionAt(kInstructionSize);
+    // Instructions must be either 'adr' or 'b'.
+    DCHECK(instr1->IsPCRelAddressing() || instr1->IsUncondBranchImm());
+    DCHECK(instr2->IsPCRelAddressing() || instr2->IsUncondBranchImm());
+    // Retrieve the offsets to the labels.
+    int32_t offset_to_incremental_noncompacting = instr1->ImmPCOffset();
+    int32_t offset_to_incremental_compacting = instr2->ImmPCOffset();
+
+    switch (mode) {
+      case STORE_BUFFER_ONLY:
+        DCHECK(GetMode(stub) == INCREMENTAL ||
+               GetMode(stub) == INCREMENTAL_COMPACTION);
+        patcher.adr(xzr, offset_to_incremental_noncompacting);
+        patcher.adr(xzr, offset_to_incremental_compacting);
+        break;
+      case INCREMENTAL:
+        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
+        patcher.b(offset_to_incremental_noncompacting >> kInstructionSizeLog2);
+        patcher.adr(xzr, offset_to_incremental_compacting);
+        break;
+      case INCREMENTAL_COMPACTION:
+        DCHECK(GetMode(stub) == STORE_BUFFER_ONLY);
+        patcher.adr(xzr, offset_to_incremental_noncompacting);
+        patcher.b(offset_to_incremental_compacting >> kInstructionSizeLog2);
+        break;
+    }
+    DCHECK(GetMode(stub) == mode);
+  }
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+
+ private:
+  // This is a helper class to manage the registers associated with the stub.
+  // The 'object' and 'address' registers must be preserved.
+  class RegisterAllocation {
+   public:
+    RegisterAllocation(Register object,
+                       Register address,
+                       Register scratch)
+        : object_(object),
+          address_(address),
+          scratch0_(scratch),
+          saved_regs_(kCallerSaved),
+          saved_fp_regs_(kCallerSavedFP) {
+      DCHECK(!AreAliased(scratch, object, address));
+
+      // The SaveCallerSaveRegisters method needs to save caller-saved
+      // registers, but we don't bother saving MacroAssembler scratch registers.
+      saved_regs_.Remove(MacroAssembler::DefaultTmpList());
+      saved_fp_regs_.Remove(MacroAssembler::DefaultFPTmpList());
+
+      // We would like to require more scratch registers for this stub,
+      // but the number of registers comes down to the ones used in
+      // FullCodeGen::SetVar(), which is architecture independent.
+      // We allocate 2 extra scratch registers that we'll save on the stack.
+      CPURegList pool_available = GetValidRegistersForAllocation();
+      CPURegList used_regs(object, address, scratch);
+      pool_available.Remove(used_regs);
+      scratch1_ = Register(pool_available.PopLowestIndex());
+      scratch2_ = Register(pool_available.PopLowestIndex());
+
+      // The scratch registers will be restored by other means so we don't need
+      // to save them with the other caller saved registers.
+      saved_regs_.Remove(scratch0_);
+      saved_regs_.Remove(scratch1_);
+      saved_regs_.Remove(scratch2_);
+    }
+
+    void Save(MacroAssembler* masm) {
+      // We don't have to save scratch0_ because it was given to us as
+      // a scratch register.
+      masm->Push(scratch1_, scratch2_);
+    }
+
+    void Restore(MacroAssembler* masm) {
+      masm->Pop(scratch2_, scratch1_);
+    }
+
+    // If we have to call into C then we need to save and restore all caller-
+    // saved registers that were not already preserved.
+    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
+      // TODO(all): This can be very expensive, and it is likely that not every
+      // register will need to be preserved. Can we improve this?
+      masm->PushCPURegList(saved_regs_);
+      if (mode == kSaveFPRegs) {
+        masm->PushCPURegList(saved_fp_regs_);
+      }
+    }
+
+    void RestoreCallerSaveRegisters(MacroAssembler*masm, SaveFPRegsMode mode) {
+      // TODO(all): This can be very expensive, and it is likely that not every
+      // register will need to be preserved. Can we improve this?
+      if (mode == kSaveFPRegs) {
+        masm->PopCPURegList(saved_fp_regs_);
+      }
+      masm->PopCPURegList(saved_regs_);
+    }
+
+    Register object() { return object_; }
+    Register address() { return address_; }
+    Register scratch0() { return scratch0_; }
+    Register scratch1() { return scratch1_; }
+    Register scratch2() { return scratch2_; }
+
+   private:
+    Register object_;
+    Register address_;
+    Register scratch0_;
+    Register scratch1_;
+    Register scratch2_;
+    CPURegList saved_regs_;
+    CPURegList saved_fp_regs_;
+
+    // TODO(all): We should consider moving this somewhere else.
+    static CPURegList GetValidRegistersForAllocation() {
+      // The list of valid registers for allocation is defined as all the
+      // registers without those with a special meaning.
+      //
+      // The default list excludes registers x26 to x31 because they are
+      // reserved for the following purpose:
+      //  - x26 root register
+      //  - x27 context pointer register
+      //  - x28 jssp
+      //  - x29 frame pointer
+      //  - x30 link register(lr)
+      //  - x31 xzr/stack pointer
+      CPURegList list(CPURegister::kRegister, kXRegSizeInBits, 0, 25);
+
+      // We also remove MacroAssembler's scratch registers.
+      list.Remove(MacroAssembler::DefaultTmpList());
+
+      return list;
+    }
+
+    friend class RecordWriteStub;
+  };
+
+  enum OnNoNeedToInformIncrementalMarker {
+    kReturnOnNoNeedToInformIncrementalMarker,
+    kUpdateRememberedSetOnNoNeedToInformIncrementalMarker
+  };
+
+  virtual inline Major MajorKey() const FINAL OVERRIDE { return RecordWrite; }
+
+  virtual void Generate(MacroAssembler* masm) OVERRIDE;
+  void GenerateIncremental(MacroAssembler* masm, Mode mode);
+  void CheckNeedsToInformIncrementalMarker(
+      MacroAssembler* masm,
+      OnNoNeedToInformIncrementalMarker on_no_need,
+      Mode mode);
+  void InformIncrementalMarker(MacroAssembler* masm);
+
+  void Activate(Code* code) {
+    code->GetHeap()->incremental_marking()->ActivateGeneratedStub(code);
+  }
+
+  Register object() const {
+    return Register::from_code(ObjectBits::decode(minor_key_));
+  }
+
+  Register value() const {
+    return Register::from_code(ValueBits::decode(minor_key_));
+  }
+
+  Register address() const {
+    return Register::from_code(AddressBits::decode(minor_key_));
+  }
+
+  RememberedSetAction remembered_set_action() const {
+    return RememberedSetActionBits::decode(minor_key_);
+  }
+
+  SaveFPRegsMode save_fp_regs_mode() const {
+    return SaveFPRegsModeBits::decode(minor_key_);
+  }
+
+  class ObjectBits: public BitField<int, 0, 5> {};
+  class ValueBits: public BitField<int, 5, 5> {};
+  class AddressBits: public BitField<int, 10, 5> {};
+  class RememberedSetActionBits: public BitField<RememberedSetAction, 15, 1> {};
+  class SaveFPRegsModeBits: public BitField<SaveFPRegsMode, 16, 1> {};
+
+  Label slow_;
+  RegisterAllocation regs_;
+};
+
+
+// Helper to call C++ functions from generated code. The caller must prepare
+// the exit frame before doing the call with GenerateCall.
+class DirectCEntryStub: public PlatformCodeStub {
+ public:
+  explicit DirectCEntryStub(Isolate* isolate) : PlatformCodeStub(isolate) {}
+  void GenerateCall(MacroAssembler* masm, Register target);
+
+ private:
+  bool NeedsImmovableCode() { return true; }
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(DirectCEntry, PlatformCodeStub);
+};
+
+
+class NameDictionaryLookupStub: public PlatformCodeStub {
+ public:
+  enum LookupMode { POSITIVE_LOOKUP, NEGATIVE_LOOKUP };
+
+  NameDictionaryLookupStub(Isolate* isolate, LookupMode mode)
+      : PlatformCodeStub(isolate) {
+    minor_key_ = LookupModeBits::encode(mode);
+  }
+
+  static void GenerateNegativeLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register receiver,
+                                     Register properties,
+                                     Handle<Name> name,
+                                     Register scratch0);
+
+  static void GeneratePositiveLookup(MacroAssembler* masm,
+                                     Label* miss,
+                                     Label* done,
+                                     Register elements,
+                                     Register name,
+                                     Register scratch1,
+                                     Register scratch2);
+
+  virtual bool SometimesSetsUpAFrame() { return false; }
+
+ private:
+  static const int kInlinedProbes = 4;
+  static const int kTotalProbes = 20;
+
+  static const int kCapacityOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kCapacityIndex * kPointerSize;
+
+  static const int kElementsStartOffset =
+      NameDictionary::kHeaderSize +
+      NameDictionary::kElementsStartIndex * kPointerSize;
+
+  LookupMode mode() const { return LookupModeBits::decode(minor_key_); }
+
+  class LookupModeBits: public BitField<LookupMode, 0, 1> {};
+
+  DEFINE_NULL_CALL_INTERFACE_DESCRIPTOR();
+  DEFINE_PLATFORM_CODE_STUB(NameDictionaryLookup, PlatformCodeStub);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_CODE_STUBS_ARM64_H_
diff --git a/src/arm64/codegen-arm64.cc b/src/arm64/codegen-arm64.cc
new file mode 100644
index 0000000..91eaba7
--- /dev/null
+++ b/src/arm64/codegen-arm64.cc
@@ -0,0 +1,626 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/simulator-arm64.h"
+#include "src/codegen.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm)
+
+#if defined(USE_SIMULATOR)
+byte* fast_exp_arm64_machine_code = NULL;
+double fast_exp_simulator(double x) {
+  Simulator * simulator = Simulator::current(Isolate::Current());
+  Simulator::CallArgument args[] = {
+      Simulator::CallArgument(x),
+      Simulator::CallArgument::End()
+  };
+  return simulator->CallDouble(fast_exp_arm64_machine_code, args);
+}
+#endif
+
+
+UnaryMathFunction CreateExpFunction() {
+  if (!FLAG_fast_math) return &std::exp;
+
+  // Use the Math.exp implemetation in MathExpGenerator::EmitMathExp() to create
+  // an AAPCS64-compliant exp() function. This will be faster than the C
+  // library's exp() function, but probably less accurate.
+  size_t actual_size;
+  byte* buffer =
+      static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return &std::exp;
+
+  ExternalReference::InitializeMathExpData();
+  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+  masm.SetStackPointer(csp);
+
+  // The argument will be in d0 on entry.
+  DoubleRegister input = d0;
+  // Use other caller-saved registers for all other values.
+  DoubleRegister result = d1;
+  DoubleRegister double_temp1 = d2;
+  DoubleRegister double_temp2 = d3;
+  Register temp1 = x10;
+  Register temp2 = x11;
+  Register temp3 = x12;
+
+  MathExpGenerator::EmitMathExp(&masm, input, result,
+                                double_temp1, double_temp2,
+                                temp1, temp2, temp3);
+  // Move the result to the return register.
+  masm.Fmov(d0, result);
+  masm.Ret();
+
+  CodeDesc desc;
+  masm.GetCode(&desc);
+  DCHECK(!RelocInfo::RequiresRelocation(desc));
+
+  CpuFeatures::FlushICache(buffer, actual_size);
+  base::OS::ProtectCode(buffer, actual_size);
+
+#if !defined(USE_SIMULATOR)
+  return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#else
+  fast_exp_arm64_machine_code = buffer;
+  return &fast_exp_simulator;
+#endif
+}
+
+
+UnaryMathFunction CreateSqrtFunction() {
+  return &std::sqrt;
+}
+
+
+// -------------------------------------------------------------------------
+// Platform-specific RuntimeCallHelper functions.
+
+void StubRuntimeCallHelper::BeforeCall(MacroAssembler* masm) const {
+  masm->EnterFrame(StackFrame::INTERNAL);
+  DCHECK(!masm->has_frame());
+  masm->set_has_frame(true);
+}
+
+
+void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
+  masm->LeaveFrame(StackFrame::INTERNAL);
+  DCHECK(masm->has_frame());
+  masm->set_has_frame(false);
+}
+
+
+// -------------------------------------------------------------------------
+// Code generators
+
+void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
+    Label* allocation_memento_found) {
+  ASM_LOCATION(
+      "ElementsTransitionGenerator::GenerateMapChangeElementsTransition");
+  DCHECK(!AreAliased(receiver, key, value, target_map));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    DCHECK(allocation_memento_found != NULL);
+    __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11,
+                                         allocation_memento_found);
+  }
+
+  // Set transitioned map.
+  __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ RecordWriteField(receiver,
+                      HeapObject::kMapOffset,
+                      target_map,
+                      x10,
+                      kLRHasNotBeenSaved,
+                      kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+void ElementsTransitionGenerator::GenerateSmiToDouble(
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
+    Label* fail) {
+  ASM_LOCATION("ElementsTransitionGenerator::GenerateSmiToDouble");
+  Label gc_required, only_change_map;
+  Register elements = x4;
+  Register length = x5;
+  Register array_size = x6;
+  Register array = x7;
+
+  Register scratch = x6;
+
+  // Verify input registers don't conflict with locals.
+  DCHECK(!AreAliased(receiver, key, value, target_map,
+                     elements, length, array_size, array));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail);
+  }
+
+  // Check for empty arrays, which only require a map transition and no changes
+  // to the backing store.
+  __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map);
+
+  __ Push(lr);
+  __ Ldrsw(length, UntagSmiFieldMemOperand(elements,
+                                           FixedArray::kLengthOffset));
+
+  // Allocate new FixedDoubleArray.
+  __ Lsl(array_size, length, kDoubleSizeLog2);
+  __ Add(array_size, array_size, FixedDoubleArray::kHeaderSize);
+  __ Allocate(array_size, array, x10, x11, &gc_required, DOUBLE_ALIGNMENT);
+  // Register array is non-tagged heap object.
+
+  // Set the destination FixedDoubleArray's length and map.
+  Register map_root = array_size;
+  __ LoadRoot(map_root, Heap::kFixedDoubleArrayMapRootIndex);
+  __ SmiTag(x11, length);
+  __ Str(x11, MemOperand(array, FixedDoubleArray::kLengthOffset));
+  __ Str(map_root, MemOperand(array, HeapObject::kMapOffset));
+
+  __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
+                      kLRHasBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+
+  // Replace receiver's backing store with newly created FixedDoubleArray.
+  __ Add(x10, array, kHeapObjectTag);
+  __ Str(x10, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ RecordWriteField(receiver, JSObject::kElementsOffset, x10,
+                      scratch, kLRHasBeenSaved, kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+
+  // Prepare for conversion loop.
+  Register src_elements = x10;
+  Register dst_elements = x11;
+  Register dst_end = x12;
+  __ Add(src_elements, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Add(dst_elements, array, FixedDoubleArray::kHeaderSize);
+  __ Add(dst_end, dst_elements, Operand(length, LSL, kDoubleSizeLog2));
+
+  FPRegister nan_d = d1;
+  __ Fmov(nan_d, rawbits_to_double(kHoleNanInt64));
+
+  Label entry, done;
+  __ B(&entry);
+
+  __ Bind(&only_change_map);
+  __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ B(&done);
+
+  // Call into runtime if GC is required.
+  __ Bind(&gc_required);
+  __ Pop(lr);
+  __ B(fail);
+
+  // Iterate over the array, copying and coverting smis to doubles. If an
+  // element is non-smi, write a hole to the destination.
+  {
+    Label loop;
+    __ Bind(&loop);
+    __ Ldr(x13, MemOperand(src_elements, kPointerSize, PostIndex));
+    __ SmiUntagToDouble(d0, x13, kSpeculativeUntag);
+    __ Tst(x13, kSmiTagMask);
+    __ Fcsel(d0, d0, nan_d, eq);
+    __ Str(d0, MemOperand(dst_elements, kDoubleSize, PostIndex));
+
+    __ Bind(&entry);
+    __ Cmp(dst_elements, dst_end);
+    __ B(lt, &loop);
+  }
+
+  __ Pop(lr);
+  __ Bind(&done);
+}
+
+
+void ElementsTransitionGenerator::GenerateDoubleToObject(
+    MacroAssembler* masm,
+    Register receiver,
+    Register key,
+    Register value,
+    Register target_map,
+    AllocationSiteMode mode,
+    Label* fail) {
+  ASM_LOCATION("ElementsTransitionGenerator::GenerateDoubleToObject");
+  Register elements = x4;
+  Register array_size = x6;
+  Register array = x7;
+  Register length = x5;
+
+  // Verify input registers don't conflict with locals.
+  DCHECK(!AreAliased(receiver, key, value, target_map,
+                     elements, array_size, array, length));
+
+  if (mode == TRACK_ALLOCATION_SITE) {
+    __ JumpIfJSArrayHasAllocationMemento(receiver, x10, x11, fail);
+  }
+
+  // Check for empty arrays, which only require a map transition and no changes
+  // to the backing store.
+  Label only_change_map;
+
+  __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ JumpIfRoot(elements, Heap::kEmptyFixedArrayRootIndex, &only_change_map);
+
+  __ Push(lr);
+  // TODO(all): These registers may not need to be pushed. Examine
+  // RecordWriteStub and check whether it's needed.
+  __ Push(target_map, receiver, key, value);
+  __ Ldrsw(length, UntagSmiFieldMemOperand(elements,
+                                           FixedArray::kLengthOffset));
+  // Allocate new FixedArray.
+  Label gc_required;
+  __ Mov(array_size, FixedDoubleArray::kHeaderSize);
+  __ Add(array_size, array_size, Operand(length, LSL, kPointerSizeLog2));
+  __ Allocate(array_size, array, x10, x11, &gc_required, NO_ALLOCATION_FLAGS);
+
+  // Set destination FixedDoubleArray's length and map.
+  Register map_root = array_size;
+  __ LoadRoot(map_root, Heap::kFixedArrayMapRootIndex);
+  __ SmiTag(x11, length);
+  __ Str(x11, MemOperand(array, FixedDoubleArray::kLengthOffset));
+  __ Str(map_root, MemOperand(array, HeapObject::kMapOffset));
+
+  // Prepare for conversion loop.
+  Register src_elements = x10;
+  Register dst_elements = x11;
+  Register dst_end = x12;
+  __ Add(src_elements, elements,
+         FixedDoubleArray::kHeaderSize - kHeapObjectTag);
+  __ Add(dst_elements, array, FixedArray::kHeaderSize);
+  __ Add(array, array, kHeapObjectTag);
+  __ Add(dst_end, dst_elements, Operand(length, LSL, kPointerSizeLog2));
+
+  Register the_hole = x14;
+  Register heap_num_map = x15;
+  __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
+  __ LoadRoot(heap_num_map, Heap::kHeapNumberMapRootIndex);
+
+  Label entry;
+  __ B(&entry);
+
+  // Call into runtime if GC is required.
+  __ Bind(&gc_required);
+  __ Pop(value, key, receiver, target_map);
+  __ Pop(lr);
+  __ B(fail);
+
+  {
+    Label loop, convert_hole;
+    __ Bind(&loop);
+    __ Ldr(x13, MemOperand(src_elements, kPointerSize, PostIndex));
+    __ Cmp(x13, kHoleNanInt64);
+    __ B(eq, &convert_hole);
+
+    // Non-hole double, copy value into a heap number.
+    Register heap_num = length;
+    Register scratch = array_size;
+    Register scratch2 = elements;
+    __ AllocateHeapNumber(heap_num, &gc_required, scratch, scratch2,
+                          x13, heap_num_map);
+    __ Mov(x13, dst_elements);
+    __ Str(heap_num, MemOperand(dst_elements, kPointerSize, PostIndex));
+    __ RecordWrite(array, x13, heap_num, kLRHasBeenSaved, kDontSaveFPRegs,
+                   EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+
+    __ B(&entry);
+
+    // Replace the-hole NaN with the-hole pointer.
+    __ Bind(&convert_hole);
+    __ Str(the_hole, MemOperand(dst_elements, kPointerSize, PostIndex));
+
+    __ Bind(&entry);
+    __ Cmp(dst_elements, dst_end);
+    __ B(lt, &loop);
+  }
+
+  __ Pop(value, key, receiver, target_map);
+  // Replace receiver's backing store with newly created and filled FixedArray.
+  __ Str(array, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ RecordWriteField(receiver, JSObject::kElementsOffset, array, x13,
+                      kLRHasBeenSaved, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+  __ Pop(lr);
+
+  __ Bind(&only_change_map);
+  __ Str(target_map, FieldMemOperand(receiver, HeapObject::kMapOffset));
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, x13,
+                      kLRHasNotBeenSaved, kDontSaveFPRegs, OMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
+}
+
+
+CodeAgingHelper::CodeAgingHelper() {
+  DCHECK(young_sequence_.length() == kNoCodeAgeSequenceLength);
+  // The sequence of instructions that is patched out for aging code is the
+  // following boilerplate stack-building prologue that is found both in
+  // FUNCTION and OPTIMIZED_FUNCTION code:
+  PatchingAssembler patcher(young_sequence_.start(),
+                            young_sequence_.length() / kInstructionSize);
+  // The young sequence is the frame setup code for FUNCTION code types. It is
+  // generated by FullCodeGenerator::Generate.
+  MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher);
+
+#ifdef DEBUG
+  const int length = kCodeAgeStubEntryOffset / kInstructionSize;
+  DCHECK(old_sequence_.length() >= kCodeAgeStubEntryOffset);
+  PatchingAssembler patcher_old(old_sequence_.start(), length);
+  MacroAssembler::EmitCodeAgeSequence(&patcher_old, NULL);
+#endif
+}
+
+
+#ifdef DEBUG
+bool CodeAgingHelper::IsOld(byte* candidate) const {
+  return memcmp(candidate, old_sequence_.start(), kCodeAgeStubEntryOffset) == 0;
+}
+#endif
+
+
+bool Code::IsYoungSequence(Isolate* isolate, byte* sequence) {
+  return MacroAssembler::IsYoungSequence(isolate, sequence);
+}
+
+
+void Code::GetCodeAgeAndParity(Isolate* isolate, byte* sequence, Age* age,
+                               MarkingParity* parity) {
+  if (IsYoungSequence(isolate, sequence)) {
+    *age = kNoAgeCodeAge;
+    *parity = NO_MARKING_PARITY;
+  } else {
+    byte* target = sequence + kCodeAgeStubEntryOffset;
+    Code* stub = GetCodeFromTargetAddress(Memory::Address_at(target));
+    GetCodeAgeAndParity(stub, age, parity);
+  }
+}
+
+
+void Code::PatchPlatformCodeAge(Isolate* isolate,
+                                byte* sequence,
+                                Code::Age age,
+                                MarkingParity parity) {
+  PatchingAssembler patcher(sequence,
+                            kNoCodeAgeSequenceLength / kInstructionSize);
+  if (age == kNoAgeCodeAge) {
+    MacroAssembler::EmitFrameSetupForCodeAgePatching(&patcher);
+  } else {
+    Code * stub = GetCodeAgeStub(isolate, age, parity);
+    MacroAssembler::EmitCodeAgeSequence(&patcher, stub);
+  }
+}
+
+
+void StringCharLoadGenerator::Generate(MacroAssembler* masm,
+                                       Register string,
+                                       Register index,
+                                       Register result,
+                                       Label* call_runtime) {
+  DCHECK(string.Is64Bits() && index.Is32Bits() && result.Is64Bits());
+  // Fetch the instance type of the receiver into result register.
+  __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
+
+  // We need special handling for indirect strings.
+  Label check_sequential;
+  __ TestAndBranchIfAllClear(result, kIsIndirectStringMask, &check_sequential);
+
+  // Dispatch on the indirect string shape: slice or cons.
+  Label cons_string;
+  __ TestAndBranchIfAllClear(result, kSlicedNotConsMask, &cons_string);
+
+  // Handle slices.
+  Label indirect_string_loaded;
+  __ Ldr(result.W(),
+         UntagSmiFieldMemOperand(string, SlicedString::kOffsetOffset));
+  __ Ldr(string, FieldMemOperand(string, SlicedString::kParentOffset));
+  __ Add(index, index, result.W());
+  __ B(&indirect_string_loaded);
+
+  // Handle cons strings.
+  // Check whether the right hand side is the empty string (i.e. if
+  // this is really a flat string in a cons string). If that is not
+  // the case we would rather go to the runtime system now to flatten
+  // the string.
+  __ Bind(&cons_string);
+  __ Ldr(result, FieldMemOperand(string, ConsString::kSecondOffset));
+  __ JumpIfNotRoot(result, Heap::kempty_stringRootIndex, call_runtime);
+  // Get the first of the two strings and load its instance type.
+  __ Ldr(string, FieldMemOperand(string, ConsString::kFirstOffset));
+
+  __ Bind(&indirect_string_loaded);
+  __ Ldr(result, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ Ldrb(result, FieldMemOperand(result, Map::kInstanceTypeOffset));
+
+  // Distinguish sequential and external strings. Only these two string
+  // representations can reach here (slices and flat cons strings have been
+  // reduced to the underlying sequential or external string).
+  Label external_string, check_encoding;
+  __ Bind(&check_sequential);
+  STATIC_ASSERT(kSeqStringTag == 0);
+  __ TestAndBranchIfAnySet(result, kStringRepresentationMask, &external_string);
+
+  // Prepare sequential strings
+  STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqOneByteString::kHeaderSize);
+  __ Add(string, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
+  __ B(&check_encoding);
+
+  // Handle external strings.
+  __ Bind(&external_string);
+  if (FLAG_debug_code) {
+    // Assert that we do not have a cons or slice (indirect strings) here.
+    // Sequential strings have already been ruled out.
+    __ Tst(result, kIsIndirectStringMask);
+    __ Assert(eq, kExternalStringExpectedButNotFound);
+  }
+  // Rule out short external strings.
+  STATIC_ASSERT(kShortExternalStringTag != 0);
+  // TestAndBranchIfAnySet can emit Tbnz. Do not use it because call_runtime
+  // can be bound far away in deferred code.
+  __ Tst(result, kShortExternalStringMask);
+  __ B(ne, call_runtime);
+  __ Ldr(string, FieldMemOperand(string, ExternalString::kResourceDataOffset));
+
+  Label one_byte, done;
+  __ Bind(&check_encoding);
+  STATIC_ASSERT(kTwoByteStringTag == 0);
+  __ TestAndBranchIfAnySet(result, kStringEncodingMask, &one_byte);
+  // Two-byte string.
+  __ Ldrh(result, MemOperand(string, index, SXTW, 1));
+  __ B(&done);
+  __ Bind(&one_byte);
+  // One-byte string.
+  __ Ldrb(result, MemOperand(string, index, SXTW));
+  __ Bind(&done);
+}
+
+
+static MemOperand ExpConstant(Register base, int index) {
+  return MemOperand(base, index * kDoubleSize);
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+                                   DoubleRegister input,
+                                   DoubleRegister result,
+                                   DoubleRegister double_temp1,
+                                   DoubleRegister double_temp2,
+                                   Register temp1,
+                                   Register temp2,
+                                   Register temp3) {
+  // TODO(jbramley): There are several instances where fnmsub could be used
+  // instead of fmul and fsub. Doing this changes the result, but since this is
+  // an estimation anyway, does it matter?
+
+  DCHECK(!AreAliased(input, result,
+                     double_temp1, double_temp2,
+                     temp1, temp2, temp3));
+  DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
+  DCHECK(!masm->serializer_enabled());  // External references not serializable.
+
+  Label done;
+  DoubleRegister double_temp3 = result;
+  Register constants = temp3;
+
+  // The algorithm used relies on some magic constants which are initialized in
+  // ExternalReference::InitializeMathExpData().
+
+  // Load the address of the start of the array.
+  __ Mov(constants, ExternalReference::math_exp_constants(0));
+
+  // We have to do a four-way split here:
+  //  - If input <= about -708.4, the output always rounds to zero.
+  //  - If input >= about 709.8, the output always rounds to +infinity.
+  //  - If the input is NaN, the output is NaN.
+  //  - Otherwise, the result needs to be calculated.
+  Label result_is_finite_non_zero;
+  // Assert that we can load offset 0 (the small input threshold) and offset 1
+  // (the large input threshold) with a single ldp.
+  DCHECK(kDRegSize == (ExpConstant(constants, 1).offset() -
+                              ExpConstant(constants, 0).offset()));
+  __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0));
+
+  __ Fcmp(input, double_temp1);
+  __ Fccmp(input, double_temp2, NoFlag, hi);
+  // At this point, the condition flags can be in one of five states:
+  //  NZCV
+  //  1000      -708.4 < input < 709.8    result = exp(input)
+  //  0110      input == 709.8            result = +infinity
+  //  0010      input > 709.8             result = +infinity
+  //  0011      input is NaN              result = input
+  //  0000      input <= -708.4           result = +0.0
+
+  // Continue the common case first. 'mi' tests N == 1.
+  __ B(&result_is_finite_non_zero, mi);
+
+  // TODO(jbramley): Consider adding a +infinity register for ARM64.
+  __ Ldr(double_temp2, ExpConstant(constants, 2));    // Synthesize +infinity.
+
+  // Select between +0.0 and +infinity. 'lo' tests C == 0.
+  __ Fcsel(result, fp_zero, double_temp2, lo);
+  // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0.
+  __ Fcsel(result, result, input, vc);
+  __ B(&done);
+
+  // The rest is magic, as described in InitializeMathExpData().
+  __ Bind(&result_is_finite_non_zero);
+
+  // Assert that we can load offset 3 and offset 4 with a single ldp.
+  DCHECK(kDRegSize == (ExpConstant(constants, 4).offset() -
+                              ExpConstant(constants, 3).offset()));
+  __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3));
+  __ Fmadd(double_temp1, double_temp1, input, double_temp3);
+  __ Fmov(temp2.W(), double_temp1.S());
+  __ Fsub(double_temp1, double_temp1, double_temp3);
+
+  // Assert that we can load offset 5 and offset 6 with a single ldp.
+  DCHECK(kDRegSize == (ExpConstant(constants, 6).offset() -
+                              ExpConstant(constants, 5).offset()));
+  __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5));
+  // TODO(jbramley): Consider using Fnmsub here.
+  __ Fmul(double_temp1, double_temp1, double_temp2);
+  __ Fsub(double_temp1, double_temp1, input);
+
+  __ Fmul(double_temp2, double_temp1, double_temp1);
+  __ Fsub(double_temp3, double_temp3, double_temp1);
+  __ Fmul(double_temp3, double_temp3, double_temp2);
+
+  __ Mov(temp1.W(), Operand(temp2.W(), LSR, 11));
+
+  __ Ldr(double_temp2, ExpConstant(constants, 7));
+  // TODO(jbramley): Consider using Fnmsub here.
+  __ Fmul(double_temp3, double_temp3, double_temp2);
+  __ Fsub(double_temp3, double_temp3, double_temp1);
+
+  // The 8th constant is 1.0, so use an immediate move rather than a load.
+  // We can't generate a runtime assertion here as we would need to call Abort
+  // in the runtime and we don't have an Isolate when we generate this code.
+  __ Fmov(double_temp2, 1.0);
+  __ Fadd(double_temp3, double_temp3, double_temp2);
+
+  __ And(temp2, temp2, 0x7ff);
+  __ Add(temp1, temp1, 0x3ff);
+
+  // Do the final table lookup.
+  __ Mov(temp3, ExternalReference::math_exp_log_table());
+
+  __ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeLog2));
+  __ Ldp(temp2.W(), temp3.W(), MemOperand(temp3));
+  __ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20));
+  __ Bfi(temp2, temp1, 32, 32);
+  __ Fmov(double_temp1, temp2);
+
+  __ Fmul(result, double_temp3, double_temp1);
+
+  __ Bind(&done);
+}
+
+#undef __
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/codegen-arm64.h b/src/arm64/codegen-arm64.h
new file mode 100644
index 0000000..2f01c51
--- /dev/null
+++ b/src/arm64/codegen-arm64.h
@@ -0,0 +1,48 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_CODEGEN_ARM64_H_
+#define V8_ARM64_CODEGEN_ARM64_H_
+
+#include "src/ast.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+class StringCharLoadGenerator : public AllStatic {
+ public:
+  // Generates the code for handling different string types and loading the
+  // indexed character into |result|.  We expect |index| as untagged input and
+  // |result| as untagged output. Register index is asserted to be a 32-bit W
+  // register.
+  static void Generate(MacroAssembler* masm,
+                       Register string,
+                       Register index,
+                       Register result,
+                       Label* call_runtime);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
+};
+
+
+class MathExpGenerator : public AllStatic {
+ public:
+  static void EmitMathExp(MacroAssembler* masm,
+                          DoubleRegister input,
+                          DoubleRegister result,
+                          DoubleRegister double_scratch1,
+                          DoubleRegister double_scratch2,
+                          Register temp1,
+                          Register temp2,
+                          Register temp3);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_CODEGEN_ARM64_H_
diff --git a/src/arm64/constants-arm64.h b/src/arm64/constants-arm64.h
new file mode 100644
index 0000000..8db120b
--- /dev/null
+++ b/src/arm64/constants-arm64.h
@@ -0,0 +1,1252 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_CONSTANTS_ARM64_H_
+#define V8_ARM64_CONSTANTS_ARM64_H_
+
+
+// Assert that this is an LP64 system.
+STATIC_ASSERT(sizeof(int) == sizeof(int32_t));     // NOLINT(runtime/sizeof)
+STATIC_ASSERT(sizeof(long) == sizeof(int64_t));    // NOLINT(runtime/int)
+STATIC_ASSERT(sizeof(void *) == sizeof(int64_t));  // NOLINT(runtime/sizeof)
+STATIC_ASSERT(sizeof(1) == sizeof(int32_t));       // NOLINT(runtime/sizeof)
+STATIC_ASSERT(sizeof(1L) == sizeof(int64_t));      // NOLINT(runtime/sizeof)
+
+
+// Get the standard printf format macros for C99 stdint types.
+#ifndef __STDC_FORMAT_MACROS
+#define __STDC_FORMAT_MACROS
+#endif
+#include <inttypes.h>
+
+
+namespace v8 {
+namespace internal {
+
+
+const unsigned kInstructionSize = 4;
+const unsigned kInstructionSizeLog2 = 2;
+const unsigned kLoadLiteralScaleLog2 = 2;
+const unsigned kMaxLoadLiteralRange = 1 * MB;
+
+const unsigned kNumberOfRegisters = 32;
+const unsigned kNumberOfFPRegisters = 32;
+// Callee saved registers are x19-x30(lr).
+const int kNumberOfCalleeSavedRegisters = 11;
+const int kFirstCalleeSavedRegisterIndex = 19;
+// Callee saved FP registers are d8-d15.
+const int kNumberOfCalleeSavedFPRegisters = 8;
+const int kFirstCalleeSavedFPRegisterIndex = 8;
+// Callee saved registers with no specific purpose in JS are x19-x25.
+const unsigned kJSCalleeSavedRegList = 0x03f80000;
+// TODO(all): k<Y>RegSize should probably be k<Y>RegSizeInBits.
+const unsigned kWRegSizeInBits = 32;
+const unsigned kWRegSizeInBitsLog2 = 5;
+const unsigned kWRegSize = kWRegSizeInBits >> 3;
+const unsigned kWRegSizeLog2 = kWRegSizeInBitsLog2 - 3;
+const unsigned kXRegSizeInBits = 64;
+const unsigned kXRegSizeInBitsLog2 = 6;
+const unsigned kXRegSize = kXRegSizeInBits >> 3;
+const unsigned kXRegSizeLog2 = kXRegSizeInBitsLog2 - 3;
+const unsigned kSRegSizeInBits = 32;
+const unsigned kSRegSizeInBitsLog2 = 5;
+const unsigned kSRegSize = kSRegSizeInBits >> 3;
+const unsigned kSRegSizeLog2 = kSRegSizeInBitsLog2 - 3;
+const unsigned kDRegSizeInBits = 64;
+const unsigned kDRegSizeInBitsLog2 = 6;
+const unsigned kDRegSize = kDRegSizeInBits >> 3;
+const unsigned kDRegSizeLog2 = kDRegSizeInBitsLog2 - 3;
+const int64_t kWRegMask = 0x00000000ffffffffL;
+const int64_t kXRegMask = 0xffffffffffffffffL;
+const int64_t kSRegMask = 0x00000000ffffffffL;
+const int64_t kDRegMask = 0xffffffffffffffffL;
+// TODO(all) check if the expression below works on all compilers or if it
+// triggers an overflow error.
+const int64_t kDSignBit = 63;
+const int64_t kDSignMask = 0x1L << kDSignBit;
+const int64_t kSSignBit = 31;
+const int64_t kSSignMask = 0x1L << kSSignBit;
+const int64_t kXSignBit = 63;
+const int64_t kXSignMask = 0x1L << kXSignBit;
+const int64_t kWSignBit = 31;
+const int64_t kWSignMask = 0x1L << kWSignBit;
+const int64_t kDQuietNanBit = 51;
+const int64_t kDQuietNanMask = 0x1L << kDQuietNanBit;
+const int64_t kSQuietNanBit = 22;
+const int64_t kSQuietNanMask = 0x1L << kSQuietNanBit;
+const int64_t kByteMask = 0xffL;
+const int64_t kHalfWordMask = 0xffffL;
+const int64_t kWordMask = 0xffffffffL;
+const uint64_t kXMaxUInt = 0xffffffffffffffffUL;
+const uint64_t kWMaxUInt = 0xffffffffUL;
+const int64_t kXMaxInt = 0x7fffffffffffffffL;
+const int64_t kXMinInt = 0x8000000000000000L;
+const int32_t kWMaxInt = 0x7fffffff;
+const int32_t kWMinInt = 0x80000000;
+const unsigned kFramePointerRegCode = 29;
+const unsigned kLinkRegCode = 30;
+const unsigned kZeroRegCode = 31;
+const unsigned kJSSPCode = 28;
+const unsigned kSPRegInternalCode = 63;
+const unsigned kRegCodeMask = 0x1f;
+const unsigned kShiftAmountWRegMask = 0x1f;
+const unsigned kShiftAmountXRegMask = 0x3f;
+// Standard machine types defined by AAPCS64.
+const unsigned kByteSize = 8;
+const unsigned kByteSizeInBytes = kByteSize >> 3;
+const unsigned kHalfWordSize = 16;
+const unsigned kHalfWordSizeLog2 = 4;
+const unsigned kHalfWordSizeInBytes = kHalfWordSize >> 3;
+const unsigned kHalfWordSizeInBytesLog2 = kHalfWordSizeLog2 - 3;
+const unsigned kWordSize = 32;
+const unsigned kWordSizeLog2 = 5;
+const unsigned kWordSizeInBytes = kWordSize >> 3;
+const unsigned kWordSizeInBytesLog2 = kWordSizeLog2 - 3;
+const unsigned kDoubleWordSize = 64;
+const unsigned kDoubleWordSizeInBytes = kDoubleWordSize >> 3;
+const unsigned kQuadWordSize = 128;
+const unsigned kQuadWordSizeInBytes = kQuadWordSize >> 3;
+// AArch64 floating-point specifics. These match IEEE-754.
+const unsigned kDoubleMantissaBits = 52;
+const unsigned kDoubleExponentBits = 11;
+const unsigned kDoubleExponentBias = 1023;
+const unsigned kFloatMantissaBits = 23;
+const unsigned kFloatExponentBits = 8;
+
+#define REGISTER_CODE_LIST(R)                                                  \
+R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                                 \
+R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                                \
+R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                                \
+R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
+
+#define INSTRUCTION_FIELDS_LIST(V_)                                            \
+/* Register fields */                                                          \
+V_(Rd, 4, 0, Bits)                        /* Destination register.     */      \
+V_(Rn, 9, 5, Bits)                        /* First source register.    */      \
+V_(Rm, 20, 16, Bits)                      /* Second source register.   */      \
+V_(Ra, 14, 10, Bits)                      /* Third source register.    */      \
+V_(Rt, 4, 0, Bits)                        /* Load dest / store source. */      \
+V_(Rt2, 14, 10, Bits)                     /* Load second dest /        */      \
+                                         /* store second source.      */       \
+V_(PrefetchMode, 4, 0, Bits)                                                   \
+                                                                               \
+/* Common bits */                                                              \
+V_(SixtyFourBits, 31, 31, Bits)                                                \
+V_(FlagsUpdate, 29, 29, Bits)                                                  \
+                                                                               \
+/* PC relative addressing */                                                   \
+V_(ImmPCRelHi, 23, 5, SignedBits)                                              \
+V_(ImmPCRelLo, 30, 29, Bits)                                                   \
+                                                                               \
+/* Add/subtract/logical shift register */                                      \
+V_(ShiftDP, 23, 22, Bits)                                                      \
+V_(ImmDPShift, 15, 10, Bits)                                                   \
+                                                                               \
+/* Add/subtract immediate */                                                   \
+V_(ImmAddSub, 21, 10, Bits)                                                    \
+V_(ShiftAddSub, 23, 22, Bits)                                                  \
+                                                                               \
+/* Add/substract extend */                                                     \
+V_(ImmExtendShift, 12, 10, Bits)                                               \
+V_(ExtendMode, 15, 13, Bits)                                                   \
+                                                                               \
+/* Move wide */                                                                \
+V_(ImmMoveWide, 20, 5, Bits)                                                   \
+V_(ShiftMoveWide, 22, 21, Bits)                                                \
+                                                                               \
+/* Logical immediate, bitfield and extract */                                  \
+V_(BitN, 22, 22, Bits)                                                         \
+V_(ImmRotate, 21, 16, Bits)                                                    \
+V_(ImmSetBits, 15, 10, Bits)                                                   \
+V_(ImmR, 21, 16, Bits)                                                         \
+V_(ImmS, 15, 10, Bits)                                                         \
+                                                                               \
+/* Test and branch immediate */                                                \
+V_(ImmTestBranch, 18, 5, SignedBits)                                           \
+V_(ImmTestBranchBit40, 23, 19, Bits)                                           \
+V_(ImmTestBranchBit5, 31, 31, Bits)                                            \
+                                                                               \
+/* Conditionals */                                                             \
+V_(Condition, 15, 12, Bits)                                                    \
+V_(ConditionBranch, 3, 0, Bits)                                                \
+V_(Nzcv, 3, 0, Bits)                                                           \
+V_(ImmCondCmp, 20, 16, Bits)                                                   \
+V_(ImmCondBranch, 23, 5, SignedBits)                                           \
+                                                                               \
+/* Floating point */                                                           \
+V_(FPType, 23, 22, Bits)                                                       \
+V_(ImmFP, 20, 13, Bits)                                                        \
+V_(FPScale, 15, 10, Bits)                                                      \
+                                                                               \
+/* Load Store */                                                               \
+V_(ImmLS, 20, 12, SignedBits)                                                  \
+V_(ImmLSUnsigned, 21, 10, Bits)                                                \
+V_(ImmLSPair, 21, 15, SignedBits)                                              \
+V_(SizeLS, 31, 30, Bits)                                                       \
+V_(ImmShiftLS, 12, 12, Bits)                                                   \
+                                                                               \
+/* Other immediates */                                                         \
+V_(ImmUncondBranch, 25, 0, SignedBits)                                         \
+V_(ImmCmpBranch, 23, 5, SignedBits)                                            \
+V_(ImmLLiteral, 23, 5, SignedBits)                                             \
+V_(ImmException, 20, 5, Bits)                                                  \
+V_(ImmHint, 11, 5, Bits)                                                       \
+V_(ImmBarrierDomain, 11, 10, Bits)                                             \
+V_(ImmBarrierType, 9, 8, Bits)                                                 \
+                                                                               \
+/* System (MRS, MSR) */                                                        \
+V_(ImmSystemRegister, 19, 5, Bits)                                             \
+V_(SysO0, 19, 19, Bits)                                                        \
+V_(SysOp1, 18, 16, Bits)                                                       \
+V_(SysOp2, 7, 5, Bits)                                                         \
+V_(CRn, 15, 12, Bits)                                                          \
+V_(CRm, 11, 8, Bits)                                                           \
+
+
+#define SYSTEM_REGISTER_FIELDS_LIST(V_, M_)                                    \
+/* NZCV */                                                                     \
+V_(Flags, 31, 28, Bits, uint32_t)                                              \
+V_(N,     31, 31, Bits, bool)                                                  \
+V_(Z,     30, 30, Bits, bool)                                                  \
+V_(C,     29, 29, Bits, bool)                                                  \
+V_(V,     28, 28, Bits, uint32_t)                                              \
+M_(NZCV, Flags_mask)                                                           \
+                                                                               \
+/* FPCR */                                                                     \
+V_(AHP,   26, 26, Bits, bool)                                                  \
+V_(DN,    25, 25, Bits, bool)                                                  \
+V_(FZ,    24, 24, Bits, bool)                                                  \
+V_(RMode, 23, 22, Bits, FPRounding)                                            \
+M_(FPCR, AHP_mask | DN_mask | FZ_mask | RMode_mask)
+
+
+// Fields offsets.
+#define DECLARE_FIELDS_OFFSETS(Name, HighBit, LowBit, unused_1, unused_2)      \
+  const int Name##_offset = LowBit;                                            \
+  const int Name##_width = HighBit - LowBit + 1;                               \
+  const uint32_t Name##_mask = ((1 << Name##_width) - 1) << LowBit;
+#define DECLARE_INSTRUCTION_FIELDS_OFFSETS(Name, HighBit, LowBit, unused_1)    \
+  DECLARE_FIELDS_OFFSETS(Name, HighBit, LowBit, unused_1, unused_2)
+#define NOTHING(A, B)
+INSTRUCTION_FIELDS_LIST(DECLARE_INSTRUCTION_FIELDS_OFFSETS)
+SYSTEM_REGISTER_FIELDS_LIST(DECLARE_FIELDS_OFFSETS, NOTHING)
+#undef NOTHING
+#undef DECLARE_FIELDS_OFFSETS
+#undef DECLARE_INSTRUCTION_FIELDS_OFFSETS
+
+// ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST), formed
+// from ImmPCRelLo and ImmPCRelHi.
+const int ImmPCRel_mask = ImmPCRelLo_mask | ImmPCRelHi_mask;
+
+// Condition codes.
+enum Condition {
+  eq = 0,
+  ne = 1,
+  hs = 2, cs = hs,
+  lo = 3, cc = lo,
+  mi = 4,
+  pl = 5,
+  vs = 6,
+  vc = 7,
+  hi = 8,
+  ls = 9,
+  ge = 10,
+  lt = 11,
+  gt = 12,
+  le = 13,
+  al = 14,
+  nv = 15  // Behaves as always/al.
+};
+
+inline Condition NegateCondition(Condition cond) {
+  // Conditions al and nv behave identically, as "always true". They can't be
+  // inverted, because there is no never condition.
+  DCHECK((cond != al) && (cond != nv));
+  return static_cast<Condition>(cond ^ 1);
+}
+
+// Commute a condition such that {a cond b == b cond' a}.
+inline Condition CommuteCondition(Condition cond) {
+  switch (cond) {
+    case lo:
+      return hi;
+    case hi:
+      return lo;
+    case hs:
+      return ls;
+    case ls:
+      return hs;
+    case lt:
+      return gt;
+    case gt:
+      return lt;
+    case ge:
+      return le;
+    case le:
+      return ge;
+    case eq:
+      return eq;
+    default:
+      // In practice this function is only used with a condition coming from
+      // TokenToCondition in lithium-codegen-arm64.cc. Any other condition is
+      // invalid as it doesn't necessary make sense to reverse it (consider
+      // 'mi' for instance).
+      UNREACHABLE();
+      return nv;
+  }
+}
+
+enum FlagsUpdate {
+  SetFlags   = 1,
+  LeaveFlags = 0
+};
+
+enum StatusFlags {
+  NoFlag    = 0,
+
+  // Derive the flag combinations from the system register bit descriptions.
+  NFlag     = N_mask,
+  ZFlag     = Z_mask,
+  CFlag     = C_mask,
+  VFlag     = V_mask,
+  NZFlag    = NFlag | ZFlag,
+  NCFlag    = NFlag | CFlag,
+  NVFlag    = NFlag | VFlag,
+  ZCFlag    = ZFlag | CFlag,
+  ZVFlag    = ZFlag | VFlag,
+  CVFlag    = CFlag | VFlag,
+  NZCFlag   = NFlag | ZFlag | CFlag,
+  NZVFlag   = NFlag | ZFlag | VFlag,
+  NCVFlag   = NFlag | CFlag | VFlag,
+  ZCVFlag   = ZFlag | CFlag | VFlag,
+  NZCVFlag  = NFlag | ZFlag | CFlag | VFlag,
+
+  // Floating-point comparison results.
+  FPEqualFlag       = ZCFlag,
+  FPLessThanFlag    = NFlag,
+  FPGreaterThanFlag = CFlag,
+  FPUnorderedFlag   = CVFlag
+};
+
+enum Shift {
+  NO_SHIFT = -1,
+  LSL = 0x0,
+  LSR = 0x1,
+  ASR = 0x2,
+  ROR = 0x3
+};
+
+enum Extend {
+  NO_EXTEND = -1,
+  UXTB      = 0,
+  UXTH      = 1,
+  UXTW      = 2,
+  UXTX      = 3,
+  SXTB      = 4,
+  SXTH      = 5,
+  SXTW      = 6,
+  SXTX      = 7
+};
+
+enum SystemHint {
+  NOP   = 0,
+  YIELD = 1,
+  WFE   = 2,
+  WFI   = 3,
+  SEV   = 4,
+  SEVL  = 5
+};
+
+enum BarrierDomain {
+  OuterShareable = 0,
+  NonShareable   = 1,
+  InnerShareable = 2,
+  FullSystem     = 3
+};
+
+enum BarrierType {
+  BarrierOther  = 0,
+  BarrierReads  = 1,
+  BarrierWrites = 2,
+  BarrierAll    = 3
+};
+
+// System/special register names.
+// This information is not encoded as one field but as the concatenation of
+// multiple fields (Op0<0>, Op1, Crn, Crm, Op2).
+enum SystemRegister {
+  NZCV = ((0x1 << SysO0_offset) |
+          (0x3 << SysOp1_offset) |
+          (0x4 << CRn_offset) |
+          (0x2 << CRm_offset) |
+          (0x0 << SysOp2_offset)) >> ImmSystemRegister_offset,
+  FPCR = ((0x1 << SysO0_offset) |
+          (0x3 << SysOp1_offset) |
+          (0x4 << CRn_offset) |
+          (0x4 << CRm_offset) |
+          (0x0 << SysOp2_offset)) >> ImmSystemRegister_offset
+};
+
+// Instruction enumerations.
+//
+// These are the masks that define a class of instructions, and the list of
+// instructions within each class. Each enumeration has a Fixed, FMask and
+// Mask value.
+//
+// Fixed: The fixed bits in this instruction class.
+// FMask: The mask used to extract the fixed bits in the class.
+// Mask:  The mask used to identify the instructions within a class.
+//
+// The enumerations can be used like this:
+//
+// DCHECK(instr->Mask(PCRelAddressingFMask) == PCRelAddressingFixed);
+// switch(instr->Mask(PCRelAddressingMask)) {
+//   case ADR:  Format("adr 'Xd, 'AddrPCRelByte"); break;
+//   case ADRP: Format("adrp 'Xd, 'AddrPCRelPage"); break;
+//   default:   printf("Unknown instruction\n");
+// }
+
+
+// Generic fields.
+enum GenericInstrField {
+  SixtyFourBits        = 0x80000000,
+  ThirtyTwoBits        = 0x00000000,
+  FP32                 = 0x00000000,
+  FP64                 = 0x00400000
+};
+
+// PC relative addressing.
+enum PCRelAddressingOp {
+  PCRelAddressingFixed = 0x10000000,
+  PCRelAddressingFMask = 0x1F000000,
+  PCRelAddressingMask  = 0x9F000000,
+  ADR                  = PCRelAddressingFixed | 0x00000000,
+  ADRP                 = PCRelAddressingFixed | 0x80000000
+};
+
+// Add/sub (immediate, shifted and extended.)
+const int kSFOffset = 31;
+enum AddSubOp {
+  AddSubOpMask      = 0x60000000,
+  AddSubSetFlagsBit = 0x20000000,
+  ADD               = 0x00000000,
+  ADDS              = ADD | AddSubSetFlagsBit,
+  SUB               = 0x40000000,
+  SUBS              = SUB | AddSubSetFlagsBit
+};
+
+#define ADD_SUB_OP_LIST(V)  \
+  V(ADD),                   \
+  V(ADDS),                  \
+  V(SUB),                   \
+  V(SUBS)
+
+enum AddSubImmediateOp {
+  AddSubImmediateFixed = 0x11000000,
+  AddSubImmediateFMask = 0x1F000000,
+  AddSubImmediateMask  = 0xFF000000,
+  #define ADD_SUB_IMMEDIATE(A)           \
+  A##_w_imm = AddSubImmediateFixed | A,  \
+  A##_x_imm = AddSubImmediateFixed | A | SixtyFourBits
+  ADD_SUB_OP_LIST(ADD_SUB_IMMEDIATE)
+  #undef ADD_SUB_IMMEDIATE
+};
+
+enum AddSubShiftedOp {
+  AddSubShiftedFixed   = 0x0B000000,
+  AddSubShiftedFMask   = 0x1F200000,
+  AddSubShiftedMask    = 0xFF200000,
+  #define ADD_SUB_SHIFTED(A)             \
+  A##_w_shift = AddSubShiftedFixed | A,  \
+  A##_x_shift = AddSubShiftedFixed | A | SixtyFourBits
+  ADD_SUB_OP_LIST(ADD_SUB_SHIFTED)
+  #undef ADD_SUB_SHIFTED
+};
+
+enum AddSubExtendedOp {
+  AddSubExtendedFixed  = 0x0B200000,
+  AddSubExtendedFMask  = 0x1F200000,
+  AddSubExtendedMask   = 0xFFE00000,
+  #define ADD_SUB_EXTENDED(A)           \
+  A##_w_ext = AddSubExtendedFixed | A,  \
+  A##_x_ext = AddSubExtendedFixed | A | SixtyFourBits
+  ADD_SUB_OP_LIST(ADD_SUB_EXTENDED)
+  #undef ADD_SUB_EXTENDED
+};
+
+// Add/sub with carry.
+enum AddSubWithCarryOp {
+  AddSubWithCarryFixed = 0x1A000000,
+  AddSubWithCarryFMask = 0x1FE00000,
+  AddSubWithCarryMask  = 0xFFE0FC00,
+  ADC_w                = AddSubWithCarryFixed | ADD,
+  ADC_x                = AddSubWithCarryFixed | ADD | SixtyFourBits,
+  ADC                  = ADC_w,
+  ADCS_w               = AddSubWithCarryFixed | ADDS,
+  ADCS_x               = AddSubWithCarryFixed | ADDS | SixtyFourBits,
+  SBC_w                = AddSubWithCarryFixed | SUB,
+  SBC_x                = AddSubWithCarryFixed | SUB | SixtyFourBits,
+  SBC                  = SBC_w,
+  SBCS_w               = AddSubWithCarryFixed | SUBS,
+  SBCS_x               = AddSubWithCarryFixed | SUBS | SixtyFourBits
+};
+
+
+// Logical (immediate and shifted register).
+enum LogicalOp {
+  LogicalOpMask = 0x60200000,
+  NOT   = 0x00200000,
+  AND   = 0x00000000,
+  BIC   = AND | NOT,
+  ORR   = 0x20000000,
+  ORN   = ORR | NOT,
+  EOR   = 0x40000000,
+  EON   = EOR | NOT,
+  ANDS  = 0x60000000,
+  BICS  = ANDS | NOT
+};
+
+// Logical immediate.
+enum LogicalImmediateOp {
+  LogicalImmediateFixed = 0x12000000,
+  LogicalImmediateFMask = 0x1F800000,
+  LogicalImmediateMask  = 0xFF800000,
+  AND_w_imm   = LogicalImmediateFixed | AND,
+  AND_x_imm   = LogicalImmediateFixed | AND | SixtyFourBits,
+  ORR_w_imm   = LogicalImmediateFixed | ORR,
+  ORR_x_imm   = LogicalImmediateFixed | ORR | SixtyFourBits,
+  EOR_w_imm   = LogicalImmediateFixed | EOR,
+  EOR_x_imm   = LogicalImmediateFixed | EOR | SixtyFourBits,
+  ANDS_w_imm  = LogicalImmediateFixed | ANDS,
+  ANDS_x_imm  = LogicalImmediateFixed | ANDS | SixtyFourBits
+};
+
+// Logical shifted register.
+enum LogicalShiftedOp {
+  LogicalShiftedFixed = 0x0A000000,
+  LogicalShiftedFMask = 0x1F000000,
+  LogicalShiftedMask  = 0xFF200000,
+  AND_w               = LogicalShiftedFixed | AND,
+  AND_x               = LogicalShiftedFixed | AND | SixtyFourBits,
+  AND_shift           = AND_w,
+  BIC_w               = LogicalShiftedFixed | BIC,
+  BIC_x               = LogicalShiftedFixed | BIC | SixtyFourBits,
+  BIC_shift           = BIC_w,
+  ORR_w               = LogicalShiftedFixed | ORR,
+  ORR_x               = LogicalShiftedFixed | ORR | SixtyFourBits,
+  ORR_shift           = ORR_w,
+  ORN_w               = LogicalShiftedFixed | ORN,
+  ORN_x               = LogicalShiftedFixed | ORN | SixtyFourBits,
+  ORN_shift           = ORN_w,
+  EOR_w               = LogicalShiftedFixed | EOR,
+  EOR_x               = LogicalShiftedFixed | EOR | SixtyFourBits,
+  EOR_shift           = EOR_w,
+  EON_w               = LogicalShiftedFixed | EON,
+  EON_x               = LogicalShiftedFixed | EON | SixtyFourBits,
+  EON_shift           = EON_w,
+  ANDS_w              = LogicalShiftedFixed | ANDS,
+  ANDS_x              = LogicalShiftedFixed | ANDS | SixtyFourBits,
+  ANDS_shift          = ANDS_w,
+  BICS_w              = LogicalShiftedFixed | BICS,
+  BICS_x              = LogicalShiftedFixed | BICS | SixtyFourBits,
+  BICS_shift          = BICS_w
+};
+
+// Move wide immediate.
+enum MoveWideImmediateOp {
+  MoveWideImmediateFixed = 0x12800000,
+  MoveWideImmediateFMask = 0x1F800000,
+  MoveWideImmediateMask  = 0xFF800000,
+  MOVN                   = 0x00000000,
+  MOVZ                   = 0x40000000,
+  MOVK                   = 0x60000000,
+  MOVN_w                 = MoveWideImmediateFixed | MOVN,
+  MOVN_x                 = MoveWideImmediateFixed | MOVN | SixtyFourBits,
+  MOVZ_w                 = MoveWideImmediateFixed | MOVZ,
+  MOVZ_x                 = MoveWideImmediateFixed | MOVZ | SixtyFourBits,
+  MOVK_w                 = MoveWideImmediateFixed | MOVK,
+  MOVK_x                 = MoveWideImmediateFixed | MOVK | SixtyFourBits
+};
+
+// Bitfield.
+const int kBitfieldNOffset = 22;
+enum BitfieldOp {
+  BitfieldFixed = 0x13000000,
+  BitfieldFMask = 0x1F800000,
+  BitfieldMask  = 0xFF800000,
+  SBFM_w        = BitfieldFixed | 0x00000000,
+  SBFM_x        = BitfieldFixed | 0x80000000,
+  SBFM          = SBFM_w,
+  BFM_w         = BitfieldFixed | 0x20000000,
+  BFM_x         = BitfieldFixed | 0xA0000000,
+  BFM           = BFM_w,
+  UBFM_w        = BitfieldFixed | 0x40000000,
+  UBFM_x        = BitfieldFixed | 0xC0000000,
+  UBFM          = UBFM_w
+  // Bitfield N field.
+};
+
+// Extract.
+enum ExtractOp {
+  ExtractFixed = 0x13800000,
+  ExtractFMask = 0x1F800000,
+  ExtractMask  = 0xFFA00000,
+  EXTR_w       = ExtractFixed | 0x00000000,
+  EXTR_x       = ExtractFixed | 0x80000000,
+  EXTR         = EXTR_w
+};
+
+// Unconditional branch.
+enum UnconditionalBranchOp {
+  UnconditionalBranchFixed = 0x14000000,
+  UnconditionalBranchFMask = 0x7C000000,
+  UnconditionalBranchMask  = 0xFC000000,
+  B                        = UnconditionalBranchFixed | 0x00000000,
+  BL                       = UnconditionalBranchFixed | 0x80000000
+};
+
+// Unconditional branch to register.
+enum UnconditionalBranchToRegisterOp {
+  UnconditionalBranchToRegisterFixed = 0xD6000000,
+  UnconditionalBranchToRegisterFMask = 0xFE000000,
+  UnconditionalBranchToRegisterMask  = 0xFFFFFC1F,
+  BR      = UnconditionalBranchToRegisterFixed | 0x001F0000,
+  BLR     = UnconditionalBranchToRegisterFixed | 0x003F0000,
+  RET     = UnconditionalBranchToRegisterFixed | 0x005F0000
+};
+
+// Compare and branch.
+enum CompareBranchOp {
+  CompareBranchFixed = 0x34000000,
+  CompareBranchFMask = 0x7E000000,
+  CompareBranchMask  = 0xFF000000,
+  CBZ_w              = CompareBranchFixed | 0x00000000,
+  CBZ_x              = CompareBranchFixed | 0x80000000,
+  CBZ                = CBZ_w,
+  CBNZ_w             = CompareBranchFixed | 0x01000000,
+  CBNZ_x             = CompareBranchFixed | 0x81000000,
+  CBNZ               = CBNZ_w
+};
+
+// Test and branch.
+enum TestBranchOp {
+  TestBranchFixed = 0x36000000,
+  TestBranchFMask = 0x7E000000,
+  TestBranchMask  = 0x7F000000,
+  TBZ             = TestBranchFixed | 0x00000000,
+  TBNZ            = TestBranchFixed | 0x01000000
+};
+
+// Conditional branch.
+enum ConditionalBranchOp {
+  ConditionalBranchFixed = 0x54000000,
+  ConditionalBranchFMask = 0xFE000000,
+  ConditionalBranchMask  = 0xFF000010,
+  B_cond                 = ConditionalBranchFixed | 0x00000000
+};
+
+// System.
+// System instruction encoding is complicated because some instructions use op
+// and CR fields to encode parameters. To handle this cleanly, the system
+// instructions are split into more than one enum.
+
+enum SystemOp {
+  SystemFixed = 0xD5000000,
+  SystemFMask = 0xFFC00000
+};
+
+enum SystemSysRegOp {
+  SystemSysRegFixed = 0xD5100000,
+  SystemSysRegFMask = 0xFFD00000,
+  SystemSysRegMask  = 0xFFF00000,
+  MRS               = SystemSysRegFixed | 0x00200000,
+  MSR               = SystemSysRegFixed | 0x00000000
+};
+
+enum SystemHintOp {
+  SystemHintFixed = 0xD503201F,
+  SystemHintFMask = 0xFFFFF01F,
+  SystemHintMask  = 0xFFFFF01F,
+  HINT            = SystemHintFixed | 0x00000000
+};
+
+// Exception.
+enum ExceptionOp {
+  ExceptionFixed = 0xD4000000,
+  ExceptionFMask = 0xFF000000,
+  ExceptionMask  = 0xFFE0001F,
+  HLT            = ExceptionFixed | 0x00400000,
+  BRK            = ExceptionFixed | 0x00200000,
+  SVC            = ExceptionFixed | 0x00000001,
+  HVC            = ExceptionFixed | 0x00000002,
+  SMC            = ExceptionFixed | 0x00000003,
+  DCPS1          = ExceptionFixed | 0x00A00001,
+  DCPS2          = ExceptionFixed | 0x00A00002,
+  DCPS3          = ExceptionFixed | 0x00A00003
+};
+// Code used to spot hlt instructions that should not be hit.
+const int kHltBadCode = 0xbad;
+
+enum MemBarrierOp {
+  MemBarrierFixed = 0xD503309F,
+  MemBarrierFMask = 0xFFFFF09F,
+  MemBarrierMask  = 0xFFFFF0FF,
+  DSB             = MemBarrierFixed | 0x00000000,
+  DMB             = MemBarrierFixed | 0x00000020,
+  ISB             = MemBarrierFixed | 0x00000040
+};
+
+// Any load or store (including pair).
+enum LoadStoreAnyOp {
+  LoadStoreAnyFMask = 0x0a000000,
+  LoadStoreAnyFixed = 0x08000000
+};
+
+// Any load pair or store pair.
+enum LoadStorePairAnyOp {
+  LoadStorePairAnyFMask = 0x3a000000,
+  LoadStorePairAnyFixed = 0x28000000
+};
+
+#define LOAD_STORE_PAIR_OP_LIST(V)  \
+  V(STP, w,   0x00000000),          \
+  V(LDP, w,   0x00400000),          \
+  V(LDPSW, x, 0x40400000),          \
+  V(STP, x,   0x80000000),          \
+  V(LDP, x,   0x80400000),          \
+  V(STP, s,   0x04000000),          \
+  V(LDP, s,   0x04400000),          \
+  V(STP, d,   0x44000000),          \
+  V(LDP, d,   0x44400000)
+
+// Load/store pair (post, pre and offset.)
+enum LoadStorePairOp {
+  LoadStorePairMask = 0xC4400000,
+  LoadStorePairLBit = 1 << 22,
+  #define LOAD_STORE_PAIR(A, B, C) \
+  A##_##B = C
+  LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR)
+  #undef LOAD_STORE_PAIR
+};
+
+enum LoadStorePairPostIndexOp {
+  LoadStorePairPostIndexFixed = 0x28800000,
+  LoadStorePairPostIndexFMask = 0x3B800000,
+  LoadStorePairPostIndexMask  = 0xFFC00000,
+  #define LOAD_STORE_PAIR_POST_INDEX(A, B, C)  \
+  A##_##B##_post = LoadStorePairPostIndexFixed | A##_##B
+  LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_POST_INDEX)
+  #undef LOAD_STORE_PAIR_POST_INDEX
+};
+
+enum LoadStorePairPreIndexOp {
+  LoadStorePairPreIndexFixed = 0x29800000,
+  LoadStorePairPreIndexFMask = 0x3B800000,
+  LoadStorePairPreIndexMask  = 0xFFC00000,
+  #define LOAD_STORE_PAIR_PRE_INDEX(A, B, C)  \
+  A##_##B##_pre = LoadStorePairPreIndexFixed | A##_##B
+  LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_PRE_INDEX)
+  #undef LOAD_STORE_PAIR_PRE_INDEX
+};
+
+enum LoadStorePairOffsetOp {
+  LoadStorePairOffsetFixed = 0x29000000,
+  LoadStorePairOffsetFMask = 0x3B800000,
+  LoadStorePairOffsetMask  = 0xFFC00000,
+  #define LOAD_STORE_PAIR_OFFSET(A, B, C)  \
+  A##_##B##_off = LoadStorePairOffsetFixed | A##_##B
+  LOAD_STORE_PAIR_OP_LIST(LOAD_STORE_PAIR_OFFSET)
+  #undef LOAD_STORE_PAIR_OFFSET
+};
+
+enum LoadStorePairNonTemporalOp {
+  LoadStorePairNonTemporalFixed = 0x28000000,
+  LoadStorePairNonTemporalFMask = 0x3B800000,
+  LoadStorePairNonTemporalMask  = 0xFFC00000,
+  STNP_w = LoadStorePairNonTemporalFixed | STP_w,
+  LDNP_w = LoadStorePairNonTemporalFixed | LDP_w,
+  STNP_x = LoadStorePairNonTemporalFixed | STP_x,
+  LDNP_x = LoadStorePairNonTemporalFixed | LDP_x,
+  STNP_s = LoadStorePairNonTemporalFixed | STP_s,
+  LDNP_s = LoadStorePairNonTemporalFixed | LDP_s,
+  STNP_d = LoadStorePairNonTemporalFixed | STP_d,
+  LDNP_d = LoadStorePairNonTemporalFixed | LDP_d
+};
+
+// Load literal.
+enum LoadLiteralOp {
+  LoadLiteralFixed = 0x18000000,
+  LoadLiteralFMask = 0x3B000000,
+  LoadLiteralMask  = 0xFF000000,
+  LDR_w_lit        = LoadLiteralFixed | 0x00000000,
+  LDR_x_lit        = LoadLiteralFixed | 0x40000000,
+  LDRSW_x_lit      = LoadLiteralFixed | 0x80000000,
+  PRFM_lit         = LoadLiteralFixed | 0xC0000000,
+  LDR_s_lit        = LoadLiteralFixed | 0x04000000,
+  LDR_d_lit        = LoadLiteralFixed | 0x44000000
+};
+
+#define LOAD_STORE_OP_LIST(V)     \
+  V(ST, RB, w,  0x00000000),  \
+  V(ST, RH, w,  0x40000000),  \
+  V(ST, R, w,   0x80000000),  \
+  V(ST, R, x,   0xC0000000),  \
+  V(LD, RB, w,  0x00400000),  \
+  V(LD, RH, w,  0x40400000),  \
+  V(LD, R, w,   0x80400000),  \
+  V(LD, R, x,   0xC0400000),  \
+  V(LD, RSB, x, 0x00800000),  \
+  V(LD, RSH, x, 0x40800000),  \
+  V(LD, RSW, x, 0x80800000),  \
+  V(LD, RSB, w, 0x00C00000),  \
+  V(LD, RSH, w, 0x40C00000),  \
+  V(ST, R, s,   0x84000000),  \
+  V(ST, R, d,   0xC4000000),  \
+  V(LD, R, s,   0x84400000),  \
+  V(LD, R, d,   0xC4400000)
+
+
+// Load/store unscaled offset.
+enum LoadStoreUnscaledOffsetOp {
+  LoadStoreUnscaledOffsetFixed = 0x38000000,
+  LoadStoreUnscaledOffsetFMask = 0x3B200C00,
+  LoadStoreUnscaledOffsetMask  = 0xFFE00C00,
+  #define LOAD_STORE_UNSCALED(A, B, C, D)  \
+  A##U##B##_##C = LoadStoreUnscaledOffsetFixed | D
+  LOAD_STORE_OP_LIST(LOAD_STORE_UNSCALED)
+  #undef LOAD_STORE_UNSCALED
+};
+
+// Load/store (post, pre, offset and unsigned.)
+enum LoadStoreOp {
+  LoadStoreOpMask   = 0xC4C00000,
+  #define LOAD_STORE(A, B, C, D)  \
+  A##B##_##C = D
+  LOAD_STORE_OP_LIST(LOAD_STORE),
+  #undef LOAD_STORE
+  PRFM = 0xC0800000
+};
+
+// Load/store post index.
+enum LoadStorePostIndex {
+  LoadStorePostIndexFixed = 0x38000400,
+  LoadStorePostIndexFMask = 0x3B200C00,
+  LoadStorePostIndexMask  = 0xFFE00C00,
+  #define LOAD_STORE_POST_INDEX(A, B, C, D)  \
+  A##B##_##C##_post = LoadStorePostIndexFixed | D
+  LOAD_STORE_OP_LIST(LOAD_STORE_POST_INDEX)
+  #undef LOAD_STORE_POST_INDEX
+};
+
+// Load/store pre index.
+enum LoadStorePreIndex {
+  LoadStorePreIndexFixed = 0x38000C00,
+  LoadStorePreIndexFMask = 0x3B200C00,
+  LoadStorePreIndexMask  = 0xFFE00C00,
+  #define LOAD_STORE_PRE_INDEX(A, B, C, D)  \
+  A##B##_##C##_pre = LoadStorePreIndexFixed | D
+  LOAD_STORE_OP_LIST(LOAD_STORE_PRE_INDEX)
+  #undef LOAD_STORE_PRE_INDEX
+};
+
+// Load/store unsigned offset.
+enum LoadStoreUnsignedOffset {
+  LoadStoreUnsignedOffsetFixed = 0x39000000,
+  LoadStoreUnsignedOffsetFMask = 0x3B000000,
+  LoadStoreUnsignedOffsetMask  = 0xFFC00000,
+  PRFM_unsigned                = LoadStoreUnsignedOffsetFixed | PRFM,
+  #define LOAD_STORE_UNSIGNED_OFFSET(A, B, C, D) \
+  A##B##_##C##_unsigned = LoadStoreUnsignedOffsetFixed | D
+  LOAD_STORE_OP_LIST(LOAD_STORE_UNSIGNED_OFFSET)
+  #undef LOAD_STORE_UNSIGNED_OFFSET
+};
+
+// Load/store register offset.
+enum LoadStoreRegisterOffset {
+  LoadStoreRegisterOffsetFixed = 0x38200800,
+  LoadStoreRegisterOffsetFMask = 0x3B200C00,
+  LoadStoreRegisterOffsetMask  = 0xFFE00C00,
+  PRFM_reg                     = LoadStoreRegisterOffsetFixed | PRFM,
+  #define LOAD_STORE_REGISTER_OFFSET(A, B, C, D) \
+  A##B##_##C##_reg = LoadStoreRegisterOffsetFixed | D
+  LOAD_STORE_OP_LIST(LOAD_STORE_REGISTER_OFFSET)
+  #undef LOAD_STORE_REGISTER_OFFSET
+};
+
+// Conditional compare.
+enum ConditionalCompareOp {
+  ConditionalCompareMask = 0x60000000,
+  CCMN                   = 0x20000000,
+  CCMP                   = 0x60000000
+};
+
+// Conditional compare register.
+enum ConditionalCompareRegisterOp {
+  ConditionalCompareRegisterFixed = 0x1A400000,
+  ConditionalCompareRegisterFMask = 0x1FE00800,
+  ConditionalCompareRegisterMask  = 0xFFE00C10,
+  CCMN_w = ConditionalCompareRegisterFixed | CCMN,
+  CCMN_x = ConditionalCompareRegisterFixed | SixtyFourBits | CCMN,
+  CCMP_w = ConditionalCompareRegisterFixed | CCMP,
+  CCMP_x = ConditionalCompareRegisterFixed | SixtyFourBits | CCMP
+};
+
+// Conditional compare immediate.
+enum ConditionalCompareImmediateOp {
+  ConditionalCompareImmediateFixed = 0x1A400800,
+  ConditionalCompareImmediateFMask = 0x1FE00800,
+  ConditionalCompareImmediateMask  = 0xFFE00C10,
+  CCMN_w_imm = ConditionalCompareImmediateFixed | CCMN,
+  CCMN_x_imm = ConditionalCompareImmediateFixed | SixtyFourBits | CCMN,
+  CCMP_w_imm = ConditionalCompareImmediateFixed | CCMP,
+  CCMP_x_imm = ConditionalCompareImmediateFixed | SixtyFourBits | CCMP
+};
+
+// Conditional select.
+enum ConditionalSelectOp {
+  ConditionalSelectFixed = 0x1A800000,
+  ConditionalSelectFMask = 0x1FE00000,
+  ConditionalSelectMask  = 0xFFE00C00,
+  CSEL_w                 = ConditionalSelectFixed | 0x00000000,
+  CSEL_x                 = ConditionalSelectFixed | 0x80000000,
+  CSEL                   = CSEL_w,
+  CSINC_w                = ConditionalSelectFixed | 0x00000400,
+  CSINC_x                = ConditionalSelectFixed | 0x80000400,
+  CSINC                  = CSINC_w,
+  CSINV_w                = ConditionalSelectFixed | 0x40000000,
+  CSINV_x                = ConditionalSelectFixed | 0xC0000000,
+  CSINV                  = CSINV_w,
+  CSNEG_w                = ConditionalSelectFixed | 0x40000400,
+  CSNEG_x                = ConditionalSelectFixed | 0xC0000400,
+  CSNEG                  = CSNEG_w
+};
+
+// Data processing 1 source.
+enum DataProcessing1SourceOp {
+  DataProcessing1SourceFixed = 0x5AC00000,
+  DataProcessing1SourceFMask = 0x5FE00000,
+  DataProcessing1SourceMask  = 0xFFFFFC00,
+  RBIT    = DataProcessing1SourceFixed | 0x00000000,
+  RBIT_w  = RBIT,
+  RBIT_x  = RBIT | SixtyFourBits,
+  REV16   = DataProcessing1SourceFixed | 0x00000400,
+  REV16_w = REV16,
+  REV16_x = REV16 | SixtyFourBits,
+  REV     = DataProcessing1SourceFixed | 0x00000800,
+  REV_w   = REV,
+  REV32_x = REV | SixtyFourBits,
+  REV_x   = DataProcessing1SourceFixed | SixtyFourBits | 0x00000C00,
+  CLZ     = DataProcessing1SourceFixed | 0x00001000,
+  CLZ_w   = CLZ,
+  CLZ_x   = CLZ | SixtyFourBits,
+  CLS     = DataProcessing1SourceFixed | 0x00001400,
+  CLS_w   = CLS,
+  CLS_x   = CLS | SixtyFourBits
+};
+
+// Data processing 2 source.
+enum DataProcessing2SourceOp {
+  DataProcessing2SourceFixed = 0x1AC00000,
+  DataProcessing2SourceFMask = 0x5FE00000,
+  DataProcessing2SourceMask  = 0xFFE0FC00,
+  UDIV_w  = DataProcessing2SourceFixed | 0x00000800,
+  UDIV_x  = DataProcessing2SourceFixed | 0x80000800,
+  UDIV    = UDIV_w,
+  SDIV_w  = DataProcessing2SourceFixed | 0x00000C00,
+  SDIV_x  = DataProcessing2SourceFixed | 0x80000C00,
+  SDIV    = SDIV_w,
+  LSLV_w  = DataProcessing2SourceFixed | 0x00002000,
+  LSLV_x  = DataProcessing2SourceFixed | 0x80002000,
+  LSLV    = LSLV_w,
+  LSRV_w  = DataProcessing2SourceFixed | 0x00002400,
+  LSRV_x  = DataProcessing2SourceFixed | 0x80002400,
+  LSRV    = LSRV_w,
+  ASRV_w  = DataProcessing2SourceFixed | 0x00002800,
+  ASRV_x  = DataProcessing2SourceFixed | 0x80002800,
+  ASRV    = ASRV_w,
+  RORV_w  = DataProcessing2SourceFixed | 0x00002C00,
+  RORV_x  = DataProcessing2SourceFixed | 0x80002C00,
+  RORV    = RORV_w,
+  CRC32B  = DataProcessing2SourceFixed | 0x00004000,
+  CRC32H  = DataProcessing2SourceFixed | 0x00004400,
+  CRC32W  = DataProcessing2SourceFixed | 0x00004800,
+  CRC32X  = DataProcessing2SourceFixed | SixtyFourBits | 0x00004C00,
+  CRC32CB = DataProcessing2SourceFixed | 0x00005000,
+  CRC32CH = DataProcessing2SourceFixed | 0x00005400,
+  CRC32CW = DataProcessing2SourceFixed | 0x00005800,
+  CRC32CX = DataProcessing2SourceFixed | SixtyFourBits | 0x00005C00
+};
+
+// Data processing 3 source.
+enum DataProcessing3SourceOp {
+  DataProcessing3SourceFixed = 0x1B000000,
+  DataProcessing3SourceFMask = 0x1F000000,
+  DataProcessing3SourceMask  = 0xFFE08000,
+  MADD_w                     = DataProcessing3SourceFixed | 0x00000000,
+  MADD_x                     = DataProcessing3SourceFixed | 0x80000000,
+  MADD                       = MADD_w,
+  MSUB_w                     = DataProcessing3SourceFixed | 0x00008000,
+  MSUB_x                     = DataProcessing3SourceFixed | 0x80008000,
+  MSUB                       = MSUB_w,
+  SMADDL_x                   = DataProcessing3SourceFixed | 0x80200000,
+  SMSUBL_x                   = DataProcessing3SourceFixed | 0x80208000,
+  SMULH_x                    = DataProcessing3SourceFixed | 0x80400000,
+  UMADDL_x                   = DataProcessing3SourceFixed | 0x80A00000,
+  UMSUBL_x                   = DataProcessing3SourceFixed | 0x80A08000,
+  UMULH_x                    = DataProcessing3SourceFixed | 0x80C00000
+};
+
+// Floating point compare.
+enum FPCompareOp {
+  FPCompareFixed = 0x1E202000,
+  FPCompareFMask = 0x5F203C00,
+  FPCompareMask  = 0xFFE0FC1F,
+  FCMP_s         = FPCompareFixed | 0x00000000,
+  FCMP_d         = FPCompareFixed | FP64 | 0x00000000,
+  FCMP           = FCMP_s,
+  FCMP_s_zero    = FPCompareFixed | 0x00000008,
+  FCMP_d_zero    = FPCompareFixed | FP64 | 0x00000008,
+  FCMP_zero      = FCMP_s_zero,
+  FCMPE_s        = FPCompareFixed | 0x00000010,
+  FCMPE_d        = FPCompareFixed | FP64 | 0x00000010,
+  FCMPE_s_zero   = FPCompareFixed | 0x00000018,
+  FCMPE_d_zero   = FPCompareFixed | FP64 | 0x00000018
+};
+
+// Floating point conditional compare.
+enum FPConditionalCompareOp {
+  FPConditionalCompareFixed = 0x1E200400,
+  FPConditionalCompareFMask = 0x5F200C00,
+  FPConditionalCompareMask  = 0xFFE00C10,
+  FCCMP_s                   = FPConditionalCompareFixed | 0x00000000,
+  FCCMP_d                   = FPConditionalCompareFixed | FP64 | 0x00000000,
+  FCCMP                     = FCCMP_s,
+  FCCMPE_s                  = FPConditionalCompareFixed | 0x00000010,
+  FCCMPE_d                  = FPConditionalCompareFixed | FP64 | 0x00000010,
+  FCCMPE                    = FCCMPE_s
+};
+
+// Floating point conditional select.
+enum FPConditionalSelectOp {
+  FPConditionalSelectFixed = 0x1E200C00,
+  FPConditionalSelectFMask = 0x5F200C00,
+  FPConditionalSelectMask  = 0xFFE00C00,
+  FCSEL_s                  = FPConditionalSelectFixed | 0x00000000,
+  FCSEL_d                  = FPConditionalSelectFixed | FP64 | 0x00000000,
+  FCSEL                    = FCSEL_s
+};
+
+// Floating point immediate.
+enum FPImmediateOp {
+  FPImmediateFixed = 0x1E201000,
+  FPImmediateFMask = 0x5F201C00,
+  FPImmediateMask  = 0xFFE01C00,
+  FMOV_s_imm       = FPImmediateFixed | 0x00000000,
+  FMOV_d_imm       = FPImmediateFixed | FP64 | 0x00000000
+};
+
+// Floating point data processing 1 source.
+enum FPDataProcessing1SourceOp {
+  FPDataProcessing1SourceFixed = 0x1E204000,
+  FPDataProcessing1SourceFMask = 0x5F207C00,
+  FPDataProcessing1SourceMask  = 0xFFFFFC00,
+  FMOV_s   = FPDataProcessing1SourceFixed | 0x00000000,
+  FMOV_d   = FPDataProcessing1SourceFixed | FP64 | 0x00000000,
+  FMOV     = FMOV_s,
+  FABS_s   = FPDataProcessing1SourceFixed | 0x00008000,
+  FABS_d   = FPDataProcessing1SourceFixed | FP64 | 0x00008000,
+  FABS     = FABS_s,
+  FNEG_s   = FPDataProcessing1SourceFixed | 0x00010000,
+  FNEG_d   = FPDataProcessing1SourceFixed | FP64 | 0x00010000,
+  FNEG     = FNEG_s,
+  FSQRT_s  = FPDataProcessing1SourceFixed | 0x00018000,
+  FSQRT_d  = FPDataProcessing1SourceFixed | FP64 | 0x00018000,
+  FSQRT    = FSQRT_s,
+  FCVT_ds  = FPDataProcessing1SourceFixed | 0x00028000,
+  FCVT_sd  = FPDataProcessing1SourceFixed | FP64 | 0x00020000,
+  FRINTN_s = FPDataProcessing1SourceFixed | 0x00040000,
+  FRINTN_d = FPDataProcessing1SourceFixed | FP64 | 0x00040000,
+  FRINTN   = FRINTN_s,
+  FRINTP_s = FPDataProcessing1SourceFixed | 0x00048000,
+  FRINTP_d = FPDataProcessing1SourceFixed | FP64 | 0x00048000,
+  FRINTP   = FRINTP_s,
+  FRINTM_s = FPDataProcessing1SourceFixed | 0x00050000,
+  FRINTM_d = FPDataProcessing1SourceFixed | FP64 | 0x00050000,
+  FRINTM   = FRINTM_s,
+  FRINTZ_s = FPDataProcessing1SourceFixed | 0x00058000,
+  FRINTZ_d = FPDataProcessing1SourceFixed | FP64 | 0x00058000,
+  FRINTZ   = FRINTZ_s,
+  FRINTA_s = FPDataProcessing1SourceFixed | 0x00060000,
+  FRINTA_d = FPDataProcessing1SourceFixed | FP64 | 0x00060000,
+  FRINTA   = FRINTA_s,
+  FRINTX_s = FPDataProcessing1SourceFixed | 0x00070000,
+  FRINTX_d = FPDataProcessing1SourceFixed | FP64 | 0x00070000,
+  FRINTX   = FRINTX_s,
+  FRINTI_s = FPDataProcessing1SourceFixed | 0x00078000,
+  FRINTI_d = FPDataProcessing1SourceFixed | FP64 | 0x00078000,
+  FRINTI   = FRINTI_s
+};
+
+// Floating point data processing 2 source.
+enum FPDataProcessing2SourceOp {
+  FPDataProcessing2SourceFixed = 0x1E200800,
+  FPDataProcessing2SourceFMask = 0x5F200C00,
+  FPDataProcessing2SourceMask  = 0xFFE0FC00,
+  FMUL     = FPDataProcessing2SourceFixed | 0x00000000,
+  FMUL_s   = FMUL,
+  FMUL_d   = FMUL | FP64,
+  FDIV     = FPDataProcessing2SourceFixed | 0x00001000,
+  FDIV_s   = FDIV,
+  FDIV_d   = FDIV | FP64,
+  FADD     = FPDataProcessing2SourceFixed | 0x00002000,
+  FADD_s   = FADD,
+  FADD_d   = FADD | FP64,
+  FSUB     = FPDataProcessing2SourceFixed | 0x00003000,
+  FSUB_s   = FSUB,
+  FSUB_d   = FSUB | FP64,
+  FMAX     = FPDataProcessing2SourceFixed | 0x00004000,
+  FMAX_s   = FMAX,
+  FMAX_d   = FMAX | FP64,
+  FMIN     = FPDataProcessing2SourceFixed | 0x00005000,
+  FMIN_s   = FMIN,
+  FMIN_d   = FMIN | FP64,
+  FMAXNM   = FPDataProcessing2SourceFixed | 0x00006000,
+  FMAXNM_s = FMAXNM,
+  FMAXNM_d = FMAXNM | FP64,
+  FMINNM   = FPDataProcessing2SourceFixed | 0x00007000,
+  FMINNM_s = FMINNM,
+  FMINNM_d = FMINNM | FP64,
+  FNMUL    = FPDataProcessing2SourceFixed | 0x00008000,
+  FNMUL_s  = FNMUL,
+  FNMUL_d  = FNMUL | FP64
+};
+
+// Floating point data processing 3 source.
+enum FPDataProcessing3SourceOp {
+  FPDataProcessing3SourceFixed = 0x1F000000,
+  FPDataProcessing3SourceFMask = 0x5F000000,
+  FPDataProcessing3SourceMask  = 0xFFE08000,
+  FMADD_s                      = FPDataProcessing3SourceFixed | 0x00000000,
+  FMSUB_s                      = FPDataProcessing3SourceFixed | 0x00008000,
+  FNMADD_s                     = FPDataProcessing3SourceFixed | 0x00200000,
+  FNMSUB_s                     = FPDataProcessing3SourceFixed | 0x00208000,
+  FMADD_d                      = FPDataProcessing3SourceFixed | 0x00400000,
+  FMSUB_d                      = FPDataProcessing3SourceFixed | 0x00408000,
+  FNMADD_d                     = FPDataProcessing3SourceFixed | 0x00600000,
+  FNMSUB_d                     = FPDataProcessing3SourceFixed | 0x00608000
+};
+
+// Conversion between floating point and integer.
+enum FPIntegerConvertOp {
+  FPIntegerConvertFixed = 0x1E200000,
+  FPIntegerConvertFMask = 0x5F20FC00,
+  FPIntegerConvertMask  = 0xFFFFFC00,
+  FCVTNS    = FPIntegerConvertFixed | 0x00000000,
+  FCVTNS_ws = FCVTNS,
+  FCVTNS_xs = FCVTNS | SixtyFourBits,
+  FCVTNS_wd = FCVTNS | FP64,
+  FCVTNS_xd = FCVTNS | SixtyFourBits | FP64,
+  FCVTNU    = FPIntegerConvertFixed | 0x00010000,
+  FCVTNU_ws = FCVTNU,
+  FCVTNU_xs = FCVTNU | SixtyFourBits,
+  FCVTNU_wd = FCVTNU | FP64,
+  FCVTNU_xd = FCVTNU | SixtyFourBits | FP64,
+  FCVTPS    = FPIntegerConvertFixed | 0x00080000,
+  FCVTPS_ws = FCVTPS,
+  FCVTPS_xs = FCVTPS | SixtyFourBits,
+  FCVTPS_wd = FCVTPS | FP64,
+  FCVTPS_xd = FCVTPS | SixtyFourBits | FP64,
+  FCVTPU    = FPIntegerConvertFixed | 0x00090000,
+  FCVTPU_ws = FCVTPU,
+  FCVTPU_xs = FCVTPU | SixtyFourBits,
+  FCVTPU_wd = FCVTPU | FP64,
+  FCVTPU_xd = FCVTPU | SixtyFourBits | FP64,
+  FCVTMS    = FPIntegerConvertFixed | 0x00100000,
+  FCVTMS_ws = FCVTMS,
+  FCVTMS_xs = FCVTMS | SixtyFourBits,
+  FCVTMS_wd = FCVTMS | FP64,
+  FCVTMS_xd = FCVTMS | SixtyFourBits | FP64,
+  FCVTMU    = FPIntegerConvertFixed | 0x00110000,
+  FCVTMU_ws = FCVTMU,
+  FCVTMU_xs = FCVTMU | SixtyFourBits,
+  FCVTMU_wd = FCVTMU | FP64,
+  FCVTMU_xd = FCVTMU | SixtyFourBits | FP64,
+  FCVTZS    = FPIntegerConvertFixed | 0x00180000,
+  FCVTZS_ws = FCVTZS,
+  FCVTZS_xs = FCVTZS | SixtyFourBits,
+  FCVTZS_wd = FCVTZS | FP64,
+  FCVTZS_xd = FCVTZS | SixtyFourBits | FP64,
+  FCVTZU    = FPIntegerConvertFixed | 0x00190000,
+  FCVTZU_ws = FCVTZU,
+  FCVTZU_xs = FCVTZU | SixtyFourBits,
+  FCVTZU_wd = FCVTZU | FP64,
+  FCVTZU_xd = FCVTZU | SixtyFourBits | FP64,
+  SCVTF     = FPIntegerConvertFixed | 0x00020000,
+  SCVTF_sw  = SCVTF,
+  SCVTF_sx  = SCVTF | SixtyFourBits,
+  SCVTF_dw  = SCVTF | FP64,
+  SCVTF_dx  = SCVTF | SixtyFourBits | FP64,
+  UCVTF     = FPIntegerConvertFixed | 0x00030000,
+  UCVTF_sw  = UCVTF,
+  UCVTF_sx  = UCVTF | SixtyFourBits,
+  UCVTF_dw  = UCVTF | FP64,
+  UCVTF_dx  = UCVTF | SixtyFourBits | FP64,
+  FCVTAS    = FPIntegerConvertFixed | 0x00040000,
+  FCVTAS_ws = FCVTAS,
+  FCVTAS_xs = FCVTAS | SixtyFourBits,
+  FCVTAS_wd = FCVTAS | FP64,
+  FCVTAS_xd = FCVTAS | SixtyFourBits | FP64,
+  FCVTAU    = FPIntegerConvertFixed | 0x00050000,
+  FCVTAU_ws = FCVTAU,
+  FCVTAU_xs = FCVTAU | SixtyFourBits,
+  FCVTAU_wd = FCVTAU | FP64,
+  FCVTAU_xd = FCVTAU | SixtyFourBits | FP64,
+  FMOV_ws   = FPIntegerConvertFixed | 0x00060000,
+  FMOV_sw   = FPIntegerConvertFixed | 0x00070000,
+  FMOV_xd   = FMOV_ws | SixtyFourBits | FP64,
+  FMOV_dx   = FMOV_sw | SixtyFourBits | FP64
+};
+
+// Conversion between fixed point and floating point.
+enum FPFixedPointConvertOp {
+  FPFixedPointConvertFixed = 0x1E000000,
+  FPFixedPointConvertFMask = 0x5F200000,
+  FPFixedPointConvertMask  = 0xFFFF0000,
+  FCVTZS_fixed    = FPFixedPointConvertFixed | 0x00180000,
+  FCVTZS_ws_fixed = FCVTZS_fixed,
+  FCVTZS_xs_fixed = FCVTZS_fixed | SixtyFourBits,
+  FCVTZS_wd_fixed = FCVTZS_fixed | FP64,
+  FCVTZS_xd_fixed = FCVTZS_fixed | SixtyFourBits | FP64,
+  FCVTZU_fixed    = FPFixedPointConvertFixed | 0x00190000,
+  FCVTZU_ws_fixed = FCVTZU_fixed,
+  FCVTZU_xs_fixed = FCVTZU_fixed | SixtyFourBits,
+  FCVTZU_wd_fixed = FCVTZU_fixed | FP64,
+  FCVTZU_xd_fixed = FCVTZU_fixed | SixtyFourBits | FP64,
+  SCVTF_fixed     = FPFixedPointConvertFixed | 0x00020000,
+  SCVTF_sw_fixed  = SCVTF_fixed,
+  SCVTF_sx_fixed  = SCVTF_fixed | SixtyFourBits,
+  SCVTF_dw_fixed  = SCVTF_fixed | FP64,
+  SCVTF_dx_fixed  = SCVTF_fixed | SixtyFourBits | FP64,
+  UCVTF_fixed     = FPFixedPointConvertFixed | 0x00030000,
+  UCVTF_sw_fixed  = UCVTF_fixed,
+  UCVTF_sx_fixed  = UCVTF_fixed | SixtyFourBits,
+  UCVTF_dw_fixed  = UCVTF_fixed | FP64,
+  UCVTF_dx_fixed  = UCVTF_fixed | SixtyFourBits | FP64
+};
+
+// Unimplemented and unallocated instructions. These are defined to make fixed
+// bit assertion easier.
+enum UnimplementedOp {
+  UnimplementedFixed = 0x00000000,
+  UnimplementedFMask = 0x00000000
+};
+
+enum UnallocatedOp {
+  UnallocatedFixed = 0x00000000,
+  UnallocatedFMask = 0x00000000
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_CONSTANTS_ARM64_H_
diff --git a/src/arm64/cpu-arm64.cc b/src/arm64/cpu-arm64.cc
new file mode 100644
index 0000000..39beb6d
--- /dev/null
+++ b/src/arm64/cpu-arm64.cc
@@ -0,0 +1,123 @@
+// Copyright 2013 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.
+
+// CPU specific code for arm independent of OS goes here.
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/utils-arm64.h"
+#include "src/assembler.h"
+
+namespace v8 {
+namespace internal {
+
+class CacheLineSizes {
+ public:
+  CacheLineSizes() {
+#ifdef USE_SIMULATOR
+    cache_type_register_ = 0;
+#else
+    // Copy the content of the cache type register to a core register.
+    __asm__ __volatile__ ("mrs %[ctr], ctr_el0"  // NOLINT
+                          : [ctr] "=r" (cache_type_register_));
+#endif
+  }
+
+  uint32_t icache_line_size() const { return ExtractCacheLineSize(0); }
+  uint32_t dcache_line_size() const { return ExtractCacheLineSize(16); }
+
+ private:
+  uint32_t ExtractCacheLineSize(int cache_line_size_shift) const {
+    // The cache type register holds the size of cache lines in words as a
+    // power of two.
+    return 4 << ((cache_type_register_ >> cache_line_size_shift) & 0xf);
+  }
+
+  uint32_t cache_type_register_;
+};
+
+
+void CpuFeatures::FlushICache(void* address, size_t length) {
+  if (length == 0) return;
+
+#ifdef USE_SIMULATOR
+  // TODO(all): consider doing some cache simulation to ensure every address
+  // run has been synced.
+  USE(address);
+  USE(length);
+#else
+  // The code below assumes user space cache operations are allowed. The goal
+  // of this routine is to make sure the code generated is visible to the I
+  // side of the CPU.
+
+  uintptr_t start = reinterpret_cast<uintptr_t>(address);
+  // Sizes will be used to generate a mask big enough to cover a pointer.
+  CacheLineSizes sizes;
+  uintptr_t dsize = sizes.dcache_line_size();
+  uintptr_t isize = sizes.icache_line_size();
+  // Cache line sizes are always a power of 2.
+  DCHECK(CountSetBits(dsize, 64) == 1);
+  DCHECK(CountSetBits(isize, 64) == 1);
+  uintptr_t dstart = start & ~(dsize - 1);
+  uintptr_t istart = start & ~(isize - 1);
+  uintptr_t end = start + length;
+
+  __asm__ __volatile__ (  // NOLINT
+    // Clean every line of the D cache containing the target data.
+    "0:                                \n\t"
+    // dc      : Data Cache maintenance
+    //    c    : Clean
+    //     va  : by (Virtual) Address
+    //       u : to the point of Unification
+    // The point of unification for a processor is the point by which the
+    // instruction and data caches are guaranteed to see the same copy of a
+    // memory location. See ARM DDI 0406B page B2-12 for more information.
+    "dc   cvau, %[dline]                \n\t"
+    "add  %[dline], %[dline], %[dsize]  \n\t"
+    "cmp  %[dline], %[end]              \n\t"
+    "b.lt 0b                            \n\t"
+    // Barrier to make sure the effect of the code above is visible to the rest
+    // of the world.
+    // dsb    : Data Synchronisation Barrier
+    //    ish : Inner SHareable domain
+    // The point of unification for an Inner Shareable shareability domain is
+    // the point by which the instruction and data caches of all the processors
+    // in that Inner Shareable shareability domain are guaranteed to see the
+    // same copy of a memory location.  See ARM DDI 0406B page B2-12 for more
+    // information.
+    "dsb  ish                           \n\t"
+    // Invalidate every line of the I cache containing the target data.
+    "1:                                 \n\t"
+    // ic      : instruction cache maintenance
+    //    i    : invalidate
+    //     va  : by address
+    //       u : to the point of unification
+    "ic   ivau, %[iline]                \n\t"
+    "add  %[iline], %[iline], %[isize]  \n\t"
+    "cmp  %[iline], %[end]              \n\t"
+    "b.lt 1b                            \n\t"
+    // Barrier to make sure the effect of the code above is visible to the rest
+    // of the world.
+    "dsb  ish                           \n\t"
+    // Barrier to ensure any prefetching which happened before this code is
+    // discarded.
+    // isb : Instruction Synchronisation Barrier
+    "isb                                \n\t"
+    : [dline] "+r" (dstart),
+      [iline] "+r" (istart)
+    : [dsize] "r"  (dsize),
+      [isize] "r"  (isize),
+      [end]   "r"  (end)
+    // This code does not write to memory but without the dependency gcc might
+    // move this code before the code is generated.
+    : "cc", "memory"
+  );  // NOLINT
+#endif
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/debug-arm64.cc b/src/arm64/debug-arm64.cc
new file mode 100644
index 0000000..f57d5b5
--- /dev/null
+++ b/src/arm64/debug-arm64.cc
@@ -0,0 +1,378 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/codegen.h"
+#include "src/debug.h"
+
+namespace v8 {
+namespace internal {
+
+
+#define __ ACCESS_MASM(masm)
+
+bool BreakLocationIterator::IsDebugBreakAtReturn() {
+  return Debug::IsDebugBreakAtReturn(rinfo());
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtReturn() {
+  // Patch the code emitted by FullCodeGenerator::EmitReturnSequence, changing
+  // the return from JS function sequence from
+  //   mov sp, fp
+  //   ldp fp, lr, [sp] #16
+  //   lrd ip0, [pc, #(3 * kInstructionSize)]
+  //   add sp, sp, ip0
+  //   ret
+  //   <number of paramters ...
+  //    ... plus one (64 bits)>
+  // to a call to the debug break return code.
+  //   ldr ip0, [pc, #(3 * kInstructionSize)]
+  //   blr ip0
+  //   hlt kHltBadCode    @ code should not return, catch if it does.
+  //   <debug break return code ...
+  //    ... entry point address (64 bits)>
+
+  // The patching code must not overflow the space occupied by the return
+  // sequence.
+  STATIC_ASSERT(Assembler::kJSRetSequenceInstructions >= 5);
+  PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 5);
+  byte* entry =
+      debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry();
+
+  // The first instruction of a patched return sequence must be a load literal
+  // loading the address of the debug break return code.
+  patcher.ldr_pcrel(ip0, (3 * kInstructionSize) >> kLoadLiteralScaleLog2);
+  // TODO(all): check the following is correct.
+  // The debug break return code will push a frame and call statically compiled
+  // code. By using blr, even though control will not return after the branch,
+  // this call site will be registered in the frame (lr being saved as the pc
+  // of the next instruction to execute for this frame). The debugger can now
+  // iterate on the frames to find call to debug break return code.
+  patcher.blr(ip0);
+  patcher.hlt(kHltBadCode);
+  patcher.dc64(reinterpret_cast<int64_t>(entry));
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtReturn() {
+  // Reset the code emitted by EmitReturnSequence to its original state.
+  rinfo()->PatchCode(original_rinfo()->pc(),
+                     Assembler::kJSRetSequenceInstructions);
+}
+
+
+bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
+  DCHECK(RelocInfo::IsJSReturn(rinfo->rmode()));
+  return rinfo->IsPatchedReturnSequence();
+}
+
+
+bool BreakLocationIterator::IsDebugBreakAtSlot() {
+  DCHECK(IsDebugBreakSlot());
+  // Check whether the debug break slot instructions have been patched.
+  return rinfo()->IsPatchedDebugBreakSlotSequence();
+}
+
+
+void BreakLocationIterator::SetDebugBreakAtSlot() {
+  // Patch the code emitted by DebugCodegen::GenerateSlots, changing the debug
+  // break slot code from
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  //   mov x0, x0    @ nop DEBUG_BREAK_NOP
+  // to a call to the debug slot code.
+  //   ldr ip0, [pc, #(2 * kInstructionSize)]
+  //   blr ip0
+  //   <debug break slot code ...
+  //    ... entry point address (64 bits)>
+
+  // TODO(all): consider adding a hlt instruction after the blr as we don't
+  // expect control to return here. This implies increasing
+  // kDebugBreakSlotInstructions to 5 instructions.
+
+  // The patching code must not overflow the space occupied by the return
+  // sequence.
+  STATIC_ASSERT(Assembler::kDebugBreakSlotInstructions >= 4);
+  PatchingAssembler patcher(reinterpret_cast<Instruction*>(rinfo()->pc()), 4);
+  byte* entry =
+      debug_info_->GetIsolate()->builtins()->Slot_DebugBreak()->entry();
+
+  // The first instruction of a patched debug break slot must be a load literal
+  // loading the address of the debug break slot code.
+  patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2);
+  // TODO(all): check the following is correct.
+  // The debug break slot code will push a frame and call statically compiled
+  // code. By using blr, event hough control will not return after the branch,
+  // this call site will be registered in the frame (lr being saved as the pc
+  // of the next instruction to execute for this frame). The debugger can now
+  // iterate on the frames to find call to debug break slot code.
+  patcher.blr(ip0);
+  patcher.dc64(reinterpret_cast<int64_t>(entry));
+}
+
+
+void BreakLocationIterator::ClearDebugBreakAtSlot() {
+  DCHECK(IsDebugBreakSlot());
+  rinfo()->PatchCode(original_rinfo()->pc(),
+                     Assembler::kDebugBreakSlotInstructions);
+}
+
+
+static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
+                                          RegList object_regs,
+                                          RegList non_object_regs,
+                                          Register scratch) {
+  {
+    FrameScope scope(masm, StackFrame::INTERNAL);
+
+    // Load padding words on stack.
+    __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingValue));
+    __ PushMultipleTimes(scratch, LiveEdit::kFramePaddingInitialSize);
+    __ Mov(scratch, Smi::FromInt(LiveEdit::kFramePaddingInitialSize));
+    __ Push(scratch);
+
+    // Any live values (object_regs and non_object_regs) in caller-saved
+    // registers (or lr) need to be stored on the stack so that their values are
+    // safely preserved for a call into C code.
+    //
+    // Also:
+    //  * object_regs may be modified during the C code by the garbage
+    //    collector. Every object register must be a valid tagged pointer or
+    //    SMI.
+    //
+    //  * non_object_regs will be converted to SMIs so that the garbage
+    //    collector doesn't try to interpret them as pointers.
+    //
+    // TODO(jbramley): Why can't this handle callee-saved registers?
+    DCHECK((~kCallerSaved.list() & object_regs) == 0);
+    DCHECK((~kCallerSaved.list() & non_object_regs) == 0);
+    DCHECK((object_regs & non_object_regs) == 0);
+    DCHECK((scratch.Bit() & object_regs) == 0);
+    DCHECK((scratch.Bit() & non_object_regs) == 0);
+    DCHECK((masm->TmpList()->list() & (object_regs | non_object_regs)) == 0);
+    STATIC_ASSERT(kSmiValueSize == 32);
+
+    CPURegList non_object_list =
+        CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs);
+    while (!non_object_list.IsEmpty()) {
+      // Store each non-object register as two SMIs.
+      Register reg = Register(non_object_list.PopLowestIndex());
+      __ Lsr(scratch, reg, 32);
+      __ SmiTagAndPush(scratch, reg);
+
+      // Stack:
+      //  jssp[12]: reg[63:32]
+      //  jssp[8]: 0x00000000 (SMI tag & padding)
+      //  jssp[4]: reg[31:0]
+      //  jssp[0]: 0x00000000 (SMI tag & padding)
+      STATIC_ASSERT(kSmiTag == 0);
+      STATIC_ASSERT(static_cast<unsigned>(kSmiShift) == kWRegSizeInBits);
+    }
+
+    if (object_regs != 0) {
+      __ PushXRegList(object_regs);
+    }
+
+#ifdef DEBUG
+    __ RecordComment("// Calling from debug break to runtime - come in - over");
+#endif
+    __ Mov(x0, 0);  // No arguments.
+    __ Mov(x1, ExternalReference::debug_break(masm->isolate()));
+
+    CEntryStub stub(masm->isolate(), 1);
+    __ CallStub(&stub);
+
+    // Restore the register values from the expression stack.
+    if (object_regs != 0) {
+      __ PopXRegList(object_regs);
+    }
+
+    non_object_list =
+        CPURegList(CPURegister::kRegister, kXRegSizeInBits, non_object_regs);
+    while (!non_object_list.IsEmpty()) {
+      // Load each non-object register from two SMIs.
+      // Stack:
+      //  jssp[12]: reg[63:32]
+      //  jssp[8]: 0x00000000 (SMI tag & padding)
+      //  jssp[4]: reg[31:0]
+      //  jssp[0]: 0x00000000 (SMI tag & padding)
+      Register reg = Register(non_object_list.PopHighestIndex());
+      __ Pop(scratch, reg);
+      __ Bfxil(reg, scratch, 32, 32);
+    }
+
+    // Don't bother removing padding bytes pushed on the stack
+    // as the frame is going to be restored right away.
+
+    // Leave the internal frame.
+  }
+
+  // Now that the break point has been handled, resume normal execution by
+  // jumping to the target address intended by the caller and that was
+  // overwritten by the address of DebugBreakXXX.
+  ExternalReference after_break_target =
+      ExternalReference::debug_after_break_target_address(masm->isolate());
+  __ Mov(scratch, after_break_target);
+  __ Ldr(scratch, MemOperand(scratch));
+  __ Br(scratch);
+}
+
+
+void DebugCodegen::GenerateCallICStubDebugBreak(MacroAssembler* masm) {
+  // Register state for CallICStub
+  // ----------- S t a t e -------------
+  //  -- x1 : function
+  //  -- x3 : slot in feedback array
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, x1.Bit() | x3.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateLoadICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC load (from ic-arm.cc).
+  Register receiver = LoadDescriptor::ReceiverRegister();
+  Register name = LoadDescriptor::NameRegister();
+  Generate_DebugBreakCallHelper(masm, receiver.Bit() | name.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateStoreICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC store (from ic-arm64.cc).
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  Generate_DebugBreakCallHelper(
+      masm, receiver.Bit() | name.Bit() | value.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for keyed IC load (from ic-arm.cc).
+  GenerateLoadICDebugBreak(masm);
+}
+
+
+void DebugCodegen::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
+  // Calling convention for IC keyed store call (from ic-arm64.cc).
+  Register receiver = StoreDescriptor::ReceiverRegister();
+  Register name = StoreDescriptor::NameRegister();
+  Register value = StoreDescriptor::ValueRegister();
+  Generate_DebugBreakCallHelper(
+      masm, receiver.Bit() | name.Bit() | value.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
+  // Register state for CompareNil IC
+  // ----------- S t a t e -------------
+  //  -- r0    : value
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, x0.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
+  // In places other than IC call sites it is expected that r0 is TOS which
+  // is an object - this is not generally the case so this should be used with
+  // care.
+  Generate_DebugBreakCallHelper(masm, x0.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
+  // Register state for CallFunctionStub (from code-stubs-arm64.cc).
+  // ----------- S t a t e -------------
+  //  -- x1 : function
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, x1.Bit(), 0, x10);
+}
+
+
+void DebugCodegen::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
+  // Calling convention for CallConstructStub (from code-stubs-arm64.cc).
+  // ----------- S t a t e -------------
+  //  -- x0 : number of arguments (not smi)
+  //  -- x1 : constructor function
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(masm, x1.Bit(), x0.Bit(), x10);
+}
+
+
+void DebugCodegen::GenerateCallConstructStubRecordDebugBreak(
+    MacroAssembler* masm) {
+  // Calling convention for CallConstructStub (from code-stubs-arm64.cc).
+  // ----------- S t a t e -------------
+  //  -- x0 : number of arguments (not smi)
+  //  -- x1 : constructor function
+  //  -- x2     : feedback array
+  //  -- x3     : feedback slot (smi)
+  // -----------------------------------
+  Generate_DebugBreakCallHelper(
+      masm, x1.Bit() | x2.Bit() | x3.Bit(), x0.Bit(), x10);
+}
+
+
+void DebugCodegen::GenerateSlot(MacroAssembler* masm) {
+  // Generate enough nop's to make space for a call instruction. Avoid emitting
+  // the constant pool in the debug break slot code.
+  InstructionAccurateScope scope(masm, Assembler::kDebugBreakSlotInstructions);
+
+  __ RecordDebugBreakSlot();
+  for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
+    __ nop(Assembler::DEBUG_BREAK_NOP);
+  }
+}
+
+
+void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
+  // In the places where a debug break slot is inserted no registers can contain
+  // object pointers.
+  Generate_DebugBreakCallHelper(masm, 0, 0, x10);
+}
+
+
+void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
+  __ Ret();
+}
+
+
+void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
+  ExternalReference restarter_frame_function_slot =
+      ExternalReference::debug_restarter_frame_function_pointer_address(
+          masm->isolate());
+  UseScratchRegisterScope temps(masm);
+  Register scratch = temps.AcquireX();
+
+  __ Mov(scratch, restarter_frame_function_slot);
+  __ Str(xzr, MemOperand(scratch));
+
+  // We do not know our frame height, but set sp based on fp.
+  __ Sub(masm->StackPointer(), fp, kPointerSize);
+  __ AssertStackConsistency();
+
+  __ Pop(x1, fp, lr);  // Function, Frame, Return address.
+
+  // Load context from the function.
+  __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
+
+  // Get function code.
+  __ Ldr(scratch, FieldMemOperand(x1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(scratch, FieldMemOperand(scratch, SharedFunctionInfo::kCodeOffset));
+  __ Add(scratch, scratch, Code::kHeaderSize - kHeapObjectTag);
+
+  // Re-run JSFunction, x1 is function, cp is context.
+  __ Br(scratch);
+}
+
+
+const bool LiveEdit::kFrameDropperSupported = true;
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/decoder-arm64-inl.h b/src/arm64/decoder-arm64-inl.h
new file mode 100644
index 0000000..5dd2fd9
--- /dev/null
+++ b/src/arm64/decoder-arm64-inl.h
@@ -0,0 +1,648 @@
+// 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.
+
+#ifndef V8_ARM64_DECODER_ARM64_INL_H_
+#define V8_ARM64_DECODER_ARM64_INL_H_
+
+#include "src/arm64/decoder-arm64.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+// Top-level instruction decode function.
+template<typename V>
+void Decoder<V>::Decode(Instruction *instr) {
+  if (instr->Bits(28, 27) == 0) {
+    V::VisitUnallocated(instr);
+  } else {
+    switch (instr->Bits(27, 24)) {
+      // 0:   PC relative addressing.
+      case 0x0: DecodePCRelAddressing(instr); break;
+
+      // 1:   Add/sub immediate.
+      case 0x1: DecodeAddSubImmediate(instr); break;
+
+      // A:   Logical shifted register.
+      //      Add/sub with carry.
+      //      Conditional compare register.
+      //      Conditional compare immediate.
+      //      Conditional select.
+      //      Data processing 1 source.
+      //      Data processing 2 source.
+      // B:   Add/sub shifted register.
+      //      Add/sub extended register.
+      //      Data processing 3 source.
+      case 0xA:
+      case 0xB: DecodeDataProcessing(instr); break;
+
+      // 2:   Logical immediate.
+      //      Move wide immediate.
+      case 0x2: DecodeLogical(instr); break;
+
+      // 3:   Bitfield.
+      //      Extract.
+      case 0x3: DecodeBitfieldExtract(instr); break;
+
+      // 4:   Unconditional branch immediate.
+      //      Exception generation.
+      //      Compare and branch immediate.
+      // 5:   Compare and branch immediate.
+      //      Conditional branch.
+      //      System.
+      // 6,7: Unconditional branch.
+      //      Test and branch immediate.
+      case 0x4:
+      case 0x5:
+      case 0x6:
+      case 0x7: DecodeBranchSystemException(instr); break;
+
+      // 8,9: Load/store register pair post-index.
+      //      Load register literal.
+      //      Load/store register unscaled immediate.
+      //      Load/store register immediate post-index.
+      //      Load/store register immediate pre-index.
+      //      Load/store register offset.
+      // C,D: Load/store register pair offset.
+      //      Load/store register pair pre-index.
+      //      Load/store register unsigned immediate.
+      //      Advanced SIMD.
+      case 0x8:
+      case 0x9:
+      case 0xC:
+      case 0xD: DecodeLoadStore(instr); break;
+
+      // E:   FP fixed point conversion.
+      //      FP integer conversion.
+      //      FP data processing 1 source.
+      //      FP compare.
+      //      FP immediate.
+      //      FP data processing 2 source.
+      //      FP conditional compare.
+      //      FP conditional select.
+      //      Advanced SIMD.
+      // F:   FP data processing 3 source.
+      //      Advanced SIMD.
+      case 0xE:
+      case 0xF: DecodeFP(instr); break;
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodePCRelAddressing(Instruction* instr) {
+  DCHECK(instr->Bits(27, 24) == 0x0);
+  // We know bit 28 is set, as <b28:b27> = 0 is filtered out at the top level
+  // decode.
+  DCHECK(instr->Bit(28) == 0x1);
+  V::VisitPCRelAddressing(instr);
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeBranchSystemException(Instruction* instr) {
+  DCHECK((instr->Bits(27, 24) == 0x4) ||
+         (instr->Bits(27, 24) == 0x5) ||
+         (instr->Bits(27, 24) == 0x6) ||
+         (instr->Bits(27, 24) == 0x7) );
+
+  switch (instr->Bits(31, 29)) {
+    case 0:
+    case 4: {
+      V::VisitUnconditionalBranch(instr);
+      break;
+    }
+    case 1:
+    case 5: {
+      if (instr->Bit(25) == 0) {
+        V::VisitCompareBranch(instr);
+      } else {
+        V::VisitTestBranch(instr);
+      }
+      break;
+    }
+    case 2: {
+      if (instr->Bit(25) == 0) {
+        if ((instr->Bit(24) == 0x1) ||
+            (instr->Mask(0x01000010) == 0x00000010)) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitConditionalBranch(instr);
+        }
+      } else {
+        V::VisitUnallocated(instr);
+      }
+      break;
+    }
+    case 6: {
+      if (instr->Bit(25) == 0) {
+        if (instr->Bit(24) == 0) {
+          if ((instr->Bits(4, 2) != 0) ||
+              (instr->Mask(0x00E0001D) == 0x00200001) ||
+              (instr->Mask(0x00E0001D) == 0x00400001) ||
+              (instr->Mask(0x00E0001E) == 0x00200002) ||
+              (instr->Mask(0x00E0001E) == 0x00400002) ||
+              (instr->Mask(0x00E0001C) == 0x00600000) ||
+              (instr->Mask(0x00E0001C) == 0x00800000) ||
+              (instr->Mask(0x00E0001F) == 0x00A00000) ||
+              (instr->Mask(0x00C0001C) == 0x00C00000)) {
+            V::VisitUnallocated(instr);
+          } else {
+            V::VisitException(instr);
+          }
+        } else {
+          if (instr->Bits(23, 22) == 0) {
+            const Instr masked_003FF0E0 = instr->Mask(0x003FF0E0);
+            if ((instr->Bits(21, 19) == 0x4) ||
+                (masked_003FF0E0 == 0x00033000) ||
+                (masked_003FF0E0 == 0x003FF020) ||
+                (masked_003FF0E0 == 0x003FF060) ||
+                (masked_003FF0E0 == 0x003FF0E0) ||
+                (instr->Mask(0x00388000) == 0x00008000) ||
+                (instr->Mask(0x0038E000) == 0x00000000) ||
+                (instr->Mask(0x0039E000) == 0x00002000) ||
+                (instr->Mask(0x003AE000) == 0x00002000) ||
+                (instr->Mask(0x003CE000) == 0x00042000) ||
+                (instr->Mask(0x003FFFC0) == 0x000320C0) ||
+                (instr->Mask(0x003FF100) == 0x00032100) ||
+                (instr->Mask(0x003FF200) == 0x00032200) ||
+                (instr->Mask(0x003FF400) == 0x00032400) ||
+                (instr->Mask(0x003FF800) == 0x00032800) ||
+                (instr->Mask(0x0038F000) == 0x00005000) ||
+                (instr->Mask(0x0038E000) == 0x00006000)) {
+              V::VisitUnallocated(instr);
+            } else {
+              V::VisitSystem(instr);
+            }
+          } else {
+            V::VisitUnallocated(instr);
+          }
+        }
+      } else {
+        if ((instr->Bit(24) == 0x1) ||
+            (instr->Bits(20, 16) != 0x1F) ||
+            (instr->Bits(15, 10) != 0) ||
+            (instr->Bits(4, 0) != 0) ||
+            (instr->Bits(24, 21) == 0x3) ||
+            (instr->Bits(24, 22) == 0x3)) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitUnconditionalBranchToRegister(instr);
+        }
+      }
+      break;
+    }
+    case 3:
+    case 7: {
+      V::VisitUnallocated(instr);
+      break;
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeLoadStore(Instruction* instr) {
+  DCHECK((instr->Bits(27, 24) == 0x8) ||
+         (instr->Bits(27, 24) == 0x9) ||
+         (instr->Bits(27, 24) == 0xC) ||
+         (instr->Bits(27, 24) == 0xD) );
+
+  if (instr->Bit(24) == 0) {
+    if (instr->Bit(28) == 0) {
+      if (instr->Bit(29) == 0) {
+        if (instr->Bit(26) == 0) {
+          // TODO(all): VisitLoadStoreExclusive.
+          V::VisitUnimplemented(instr);
+        } else {
+          DecodeAdvSIMDLoadStore(instr);
+        }
+      } else {
+        if ((instr->Bits(31, 30) == 0x3) ||
+            (instr->Mask(0xC4400000) == 0x40000000)) {
+          V::VisitUnallocated(instr);
+        } else {
+          if (instr->Bit(23) == 0) {
+            if (instr->Mask(0xC4400000) == 0xC0400000) {
+              V::VisitUnallocated(instr);
+            } else {
+              V::VisitLoadStorePairNonTemporal(instr);
+            }
+          } else {
+            V::VisitLoadStorePairPostIndex(instr);
+          }
+        }
+      }
+    } else {
+      if (instr->Bit(29) == 0) {
+        if (instr->Mask(0xC4000000) == 0xC4000000) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitLoadLiteral(instr);
+        }
+      } else {
+        if ((instr->Mask(0x84C00000) == 0x80C00000) ||
+            (instr->Mask(0x44800000) == 0x44800000) ||
+            (instr->Mask(0x84800000) == 0x84800000)) {
+          V::VisitUnallocated(instr);
+        } else {
+          if (instr->Bit(21) == 0) {
+            switch (instr->Bits(11, 10)) {
+              case 0: {
+                V::VisitLoadStoreUnscaledOffset(instr);
+                break;
+              }
+              case 1: {
+                if (instr->Mask(0xC4C00000) == 0xC0800000) {
+                  V::VisitUnallocated(instr);
+                } else {
+                  V::VisitLoadStorePostIndex(instr);
+                }
+                break;
+              }
+              case 2: {
+                // TODO(all): VisitLoadStoreRegisterOffsetUnpriv.
+                V::VisitUnimplemented(instr);
+                break;
+              }
+              case 3: {
+                if (instr->Mask(0xC4C00000) == 0xC0800000) {
+                  V::VisitUnallocated(instr);
+                } else {
+                  V::VisitLoadStorePreIndex(instr);
+                }
+                break;
+              }
+            }
+          } else {
+            if (instr->Bits(11, 10) == 0x2) {
+              if (instr->Bit(14) == 0) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitLoadStoreRegisterOffset(instr);
+              }
+            } else {
+              V::VisitUnallocated(instr);
+            }
+          }
+        }
+      }
+    }
+  } else {
+    if (instr->Bit(28) == 0) {
+      if (instr->Bit(29) == 0) {
+        V::VisitUnallocated(instr);
+      } else {
+        if ((instr->Bits(31, 30) == 0x3) ||
+            (instr->Mask(0xC4400000) == 0x40000000)) {
+          V::VisitUnallocated(instr);
+        } else {
+          if (instr->Bit(23) == 0) {
+            V::VisitLoadStorePairOffset(instr);
+          } else {
+            V::VisitLoadStorePairPreIndex(instr);
+          }
+        }
+      }
+    } else {
+      if (instr->Bit(29) == 0) {
+        V::VisitUnallocated(instr);
+      } else {
+        if ((instr->Mask(0x84C00000) == 0x80C00000) ||
+            (instr->Mask(0x44800000) == 0x44800000) ||
+            (instr->Mask(0x84800000) == 0x84800000)) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitLoadStoreUnsignedOffset(instr);
+        }
+      }
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeLogical(Instruction* instr) {
+  DCHECK(instr->Bits(27, 24) == 0x2);
+
+  if (instr->Mask(0x80400000) == 0x00400000) {
+    V::VisitUnallocated(instr);
+  } else {
+    if (instr->Bit(23) == 0) {
+      V::VisitLogicalImmediate(instr);
+    } else {
+      if (instr->Bits(30, 29) == 0x1) {
+        V::VisitUnallocated(instr);
+      } else {
+        V::VisitMoveWideImmediate(instr);
+      }
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeBitfieldExtract(Instruction* instr) {
+  DCHECK(instr->Bits(27, 24) == 0x3);
+
+  if ((instr->Mask(0x80400000) == 0x80000000) ||
+      (instr->Mask(0x80400000) == 0x00400000) ||
+      (instr->Mask(0x80008000) == 0x00008000)) {
+    V::VisitUnallocated(instr);
+  } else if (instr->Bit(23) == 0) {
+    if ((instr->Mask(0x80200000) == 0x00200000) ||
+        (instr->Mask(0x60000000) == 0x60000000)) {
+      V::VisitUnallocated(instr);
+    } else {
+      V::VisitBitfield(instr);
+    }
+  } else {
+    if ((instr->Mask(0x60200000) == 0x00200000) ||
+        (instr->Mask(0x60000000) != 0x00000000)) {
+      V::VisitUnallocated(instr);
+    } else {
+      V::VisitExtract(instr);
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeAddSubImmediate(Instruction* instr) {
+  DCHECK(instr->Bits(27, 24) == 0x1);
+  if (instr->Bit(23) == 1) {
+    V::VisitUnallocated(instr);
+  } else {
+    V::VisitAddSubImmediate(instr);
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeDataProcessing(Instruction* instr) {
+  DCHECK((instr->Bits(27, 24) == 0xA) ||
+         (instr->Bits(27, 24) == 0xB) );
+
+  if (instr->Bit(24) == 0) {
+    if (instr->Bit(28) == 0) {
+      if (instr->Mask(0x80008000) == 0x00008000) {
+        V::VisitUnallocated(instr);
+      } else {
+        V::VisitLogicalShifted(instr);
+      }
+    } else {
+      switch (instr->Bits(23, 21)) {
+        case 0: {
+          if (instr->Mask(0x0000FC00) != 0) {
+            V::VisitUnallocated(instr);
+          } else {
+            V::VisitAddSubWithCarry(instr);
+          }
+          break;
+        }
+        case 2: {
+          if ((instr->Bit(29) == 0) ||
+              (instr->Mask(0x00000410) != 0)) {
+            V::VisitUnallocated(instr);
+          } else {
+            if (instr->Bit(11) == 0) {
+              V::VisitConditionalCompareRegister(instr);
+            } else {
+              V::VisitConditionalCompareImmediate(instr);
+            }
+          }
+          break;
+        }
+        case 4: {
+          if (instr->Mask(0x20000800) != 0x00000000) {
+            V::VisitUnallocated(instr);
+          } else {
+            V::VisitConditionalSelect(instr);
+          }
+          break;
+        }
+        case 6: {
+          if (instr->Bit(29) == 0x1) {
+            V::VisitUnallocated(instr);
+          } else {
+            if (instr->Bit(30) == 0) {
+              if ((instr->Bit(15) == 0x1) ||
+                  (instr->Bits(15, 11) == 0) ||
+                  (instr->Bits(15, 12) == 0x1) ||
+                  (instr->Bits(15, 12) == 0x3) ||
+                  (instr->Bits(15, 13) == 0x3) ||
+                  (instr->Mask(0x8000EC00) == 0x00004C00) ||
+                  (instr->Mask(0x8000E800) == 0x80004000) ||
+                  (instr->Mask(0x8000E400) == 0x80004000)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitDataProcessing2Source(instr);
+              }
+            } else {
+              if ((instr->Bit(13) == 1) ||
+                  (instr->Bits(20, 16) != 0) ||
+                  (instr->Bits(15, 14) != 0) ||
+                  (instr->Mask(0xA01FFC00) == 0x00000C00) ||
+                  (instr->Mask(0x201FF800) == 0x00001800)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitDataProcessing1Source(instr);
+              }
+            }
+            break;
+          }
+        }
+        case 1:
+        case 3:
+        case 5:
+        case 7: V::VisitUnallocated(instr); break;
+      }
+    }
+  } else {
+    if (instr->Bit(28) == 0) {
+     if (instr->Bit(21) == 0) {
+        if ((instr->Bits(23, 22) == 0x3) ||
+            (instr->Mask(0x80008000) == 0x00008000)) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitAddSubShifted(instr);
+        }
+      } else {
+        if ((instr->Mask(0x00C00000) != 0x00000000) ||
+            (instr->Mask(0x00001400) == 0x00001400) ||
+            (instr->Mask(0x00001800) == 0x00001800)) {
+          V::VisitUnallocated(instr);
+        } else {
+          V::VisitAddSubExtended(instr);
+        }
+      }
+    } else {
+      if ((instr->Bit(30) == 0x1) ||
+          (instr->Bits(30, 29) == 0x1) ||
+          (instr->Mask(0xE0600000) == 0x00200000) ||
+          (instr->Mask(0xE0608000) == 0x00400000) ||
+          (instr->Mask(0x60608000) == 0x00408000) ||
+          (instr->Mask(0x60E00000) == 0x00E00000) ||
+          (instr->Mask(0x60E00000) == 0x00800000) ||
+          (instr->Mask(0x60E00000) == 0x00600000)) {
+        V::VisitUnallocated(instr);
+      } else {
+        V::VisitDataProcessing3Source(instr);
+      }
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeFP(Instruction* instr) {
+  DCHECK((instr->Bits(27, 24) == 0xE) ||
+         (instr->Bits(27, 24) == 0xF) );
+
+  if (instr->Bit(28) == 0) {
+    DecodeAdvSIMDDataProcessing(instr);
+  } else {
+    if (instr->Bit(29) == 1) {
+      V::VisitUnallocated(instr);
+    } else {
+      if (instr->Bits(31, 30) == 0x3) {
+        V::VisitUnallocated(instr);
+      } else if (instr->Bits(31, 30) == 0x1) {
+        DecodeAdvSIMDDataProcessing(instr);
+      } else {
+        if (instr->Bit(24) == 0) {
+          if (instr->Bit(21) == 0) {
+            if ((instr->Bit(23) == 1) ||
+                (instr->Bit(18) == 1) ||
+                (instr->Mask(0x80008000) == 0x00000000) ||
+                (instr->Mask(0x000E0000) == 0x00000000) ||
+                (instr->Mask(0x000E0000) == 0x000A0000) ||
+                (instr->Mask(0x00160000) == 0x00000000) ||
+                (instr->Mask(0x00160000) == 0x00120000)) {
+              V::VisitUnallocated(instr);
+            } else {
+              V::VisitFPFixedPointConvert(instr);
+            }
+          } else {
+            if (instr->Bits(15, 10) == 32) {
+              V::VisitUnallocated(instr);
+            } else if (instr->Bits(15, 10) == 0) {
+              if ((instr->Bits(23, 22) == 0x3) ||
+                  (instr->Mask(0x000E0000) == 0x000A0000) ||
+                  (instr->Mask(0x000E0000) == 0x000C0000) ||
+                  (instr->Mask(0x00160000) == 0x00120000) ||
+                  (instr->Mask(0x00160000) == 0x00140000) ||
+                  (instr->Mask(0x20C40000) == 0x00800000) ||
+                  (instr->Mask(0x20C60000) == 0x00840000) ||
+                  (instr->Mask(0xA0C60000) == 0x80060000) ||
+                  (instr->Mask(0xA0C60000) == 0x00860000) ||
+                  (instr->Mask(0xA0C60000) == 0x00460000) ||
+                  (instr->Mask(0xA0CE0000) == 0x80860000) ||
+                  (instr->Mask(0xA0CE0000) == 0x804E0000) ||
+                  (instr->Mask(0xA0CE0000) == 0x000E0000) ||
+                  (instr->Mask(0xA0D60000) == 0x00160000) ||
+                  (instr->Mask(0xA0D60000) == 0x80560000) ||
+                  (instr->Mask(0xA0D60000) == 0x80960000)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitFPIntegerConvert(instr);
+              }
+            } else if (instr->Bits(14, 10) == 16) {
+              const Instr masked_A0DF8000 = instr->Mask(0xA0DF8000);
+              if ((instr->Mask(0x80180000) != 0) ||
+                  (masked_A0DF8000 == 0x00020000) ||
+                  (masked_A0DF8000 == 0x00030000) ||
+                  (masked_A0DF8000 == 0x00068000) ||
+                  (masked_A0DF8000 == 0x00428000) ||
+                  (masked_A0DF8000 == 0x00430000) ||
+                  (masked_A0DF8000 == 0x00468000) ||
+                  (instr->Mask(0xA0D80000) == 0x00800000) ||
+                  (instr->Mask(0xA0DE0000) == 0x00C00000) ||
+                  (instr->Mask(0xA0DF0000) == 0x00C30000) ||
+                  (instr->Mask(0xA0DC0000) == 0x00C40000)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitFPDataProcessing1Source(instr);
+              }
+            } else if (instr->Bits(13, 10) == 8) {
+              if ((instr->Bits(15, 14) != 0) ||
+                  (instr->Bits(2, 0) != 0) ||
+                  (instr->Mask(0x80800000) != 0x00000000)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitFPCompare(instr);
+              }
+            } else if (instr->Bits(12, 10) == 4) {
+              if ((instr->Bits(9, 5) != 0) ||
+                  (instr->Mask(0x80800000) != 0x00000000)) {
+                V::VisitUnallocated(instr);
+              } else {
+                V::VisitFPImmediate(instr);
+              }
+            } else {
+              if (instr->Mask(0x80800000) != 0x00000000) {
+                V::VisitUnallocated(instr);
+              } else {
+                switch (instr->Bits(11, 10)) {
+                  case 1: {
+                    V::VisitFPConditionalCompare(instr);
+                    break;
+                  }
+                  case 2: {
+                    if ((instr->Bits(15, 14) == 0x3) ||
+                        (instr->Mask(0x00009000) == 0x00009000) ||
+                        (instr->Mask(0x0000A000) == 0x0000A000)) {
+                      V::VisitUnallocated(instr);
+                    } else {
+                      V::VisitFPDataProcessing2Source(instr);
+                    }
+                    break;
+                  }
+                  case 3: {
+                    V::VisitFPConditionalSelect(instr);
+                    break;
+                  }
+                  default: UNREACHABLE();
+                }
+              }
+            }
+          }
+        } else {
+          // Bit 30 == 1 has been handled earlier.
+          DCHECK(instr->Bit(30) == 0);
+          if (instr->Mask(0xA0800000) != 0) {
+            V::VisitUnallocated(instr);
+          } else {
+            V::VisitFPDataProcessing3Source(instr);
+          }
+        }
+      }
+    }
+  }
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeAdvSIMDLoadStore(Instruction* instr) {
+  // TODO(all): Implement Advanced SIMD load/store instruction decode.
+  DCHECK(instr->Bits(29, 25) == 0x6);
+  V::VisitUnimplemented(instr);
+}
+
+
+template<typename V>
+void Decoder<V>::DecodeAdvSIMDDataProcessing(Instruction* instr) {
+  // TODO(all): Implement Advanced SIMD data processing instruction decode.
+  DCHECK(instr->Bits(27, 25) == 0x7);
+  V::VisitUnimplemented(instr);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_DECODER_ARM64_INL_H_
diff --git a/src/arm64/decoder-arm64.cc b/src/arm64/decoder-arm64.cc
new file mode 100644
index 0000000..5cca85e
--- /dev/null
+++ b/src/arm64/decoder-arm64.cc
@@ -0,0 +1,86 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/decoder-arm64.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+void DispatchingDecoderVisitor::AppendVisitor(DecoderVisitor* new_visitor) {
+  visitors_.remove(new_visitor);
+  visitors_.push_back(new_visitor);
+}
+
+
+void DispatchingDecoderVisitor::PrependVisitor(DecoderVisitor* new_visitor) {
+  visitors_.remove(new_visitor);
+  visitors_.push_front(new_visitor);
+}
+
+
+void DispatchingDecoderVisitor::InsertVisitorBefore(
+    DecoderVisitor* new_visitor, DecoderVisitor* registered_visitor) {
+  visitors_.remove(new_visitor);
+  std::list<DecoderVisitor*>::iterator it;
+  for (it = visitors_.begin(); it != visitors_.end(); it++) {
+    if (*it == registered_visitor) {
+      visitors_.insert(it, new_visitor);
+      return;
+    }
+  }
+  // We reached the end of the list. The last element must be
+  // registered_visitor.
+  DCHECK(*it == registered_visitor);
+  visitors_.insert(it, new_visitor);
+}
+
+
+void DispatchingDecoderVisitor::InsertVisitorAfter(
+    DecoderVisitor* new_visitor, DecoderVisitor* registered_visitor) {
+  visitors_.remove(new_visitor);
+  std::list<DecoderVisitor*>::iterator it;
+  for (it = visitors_.begin(); it != visitors_.end(); it++) {
+    if (*it == registered_visitor) {
+      it++;
+      visitors_.insert(it, new_visitor);
+      return;
+    }
+  }
+  // We reached the end of the list. The last element must be
+  // registered_visitor.
+  DCHECK(*it == registered_visitor);
+  visitors_.push_back(new_visitor);
+}
+
+
+void DispatchingDecoderVisitor::RemoveVisitor(DecoderVisitor* visitor) {
+  visitors_.remove(visitor);
+}
+
+
+#define DEFINE_VISITOR_CALLERS(A)                                \
+  void DispatchingDecoderVisitor::Visit##A(Instruction* instr) { \
+    if (!(instr->Mask(A##FMask) == A##Fixed)) {                  \
+      DCHECK(instr->Mask(A##FMask) == A##Fixed);                 \
+    }                                                            \
+    std::list<DecoderVisitor*>::iterator it;                     \
+    for (it = visitors_.begin(); it != visitors_.end(); it++) {  \
+      (*it)->Visit##A(instr);                                    \
+    }                                                            \
+  }
+VISITOR_LIST(DEFINE_VISITOR_CALLERS)
+#undef DEFINE_VISITOR_CALLERS
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/decoder-arm64.h b/src/arm64/decoder-arm64.h
new file mode 100644
index 0000000..af6bcc6
--- /dev/null
+++ b/src/arm64/decoder-arm64.h
@@ -0,0 +1,187 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_DECODER_ARM64_H_
+#define V8_ARM64_DECODER_ARM64_H_
+
+#include <list>
+
+#include "src/arm64/instructions-arm64.h"
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+
+// List macro containing all visitors needed by the decoder class.
+
+#define VISITOR_LIST(V)             \
+  V(PCRelAddressing)                \
+  V(AddSubImmediate)                \
+  V(LogicalImmediate)               \
+  V(MoveWideImmediate)              \
+  V(Bitfield)                       \
+  V(Extract)                        \
+  V(UnconditionalBranch)            \
+  V(UnconditionalBranchToRegister)  \
+  V(CompareBranch)                  \
+  V(TestBranch)                     \
+  V(ConditionalBranch)              \
+  V(System)                         \
+  V(Exception)                      \
+  V(LoadStorePairPostIndex)         \
+  V(LoadStorePairOffset)            \
+  V(LoadStorePairPreIndex)          \
+  V(LoadStorePairNonTemporal)       \
+  V(LoadLiteral)                    \
+  V(LoadStoreUnscaledOffset)        \
+  V(LoadStorePostIndex)             \
+  V(LoadStorePreIndex)              \
+  V(LoadStoreRegisterOffset)        \
+  V(LoadStoreUnsignedOffset)        \
+  V(LogicalShifted)                 \
+  V(AddSubShifted)                  \
+  V(AddSubExtended)                 \
+  V(AddSubWithCarry)                \
+  V(ConditionalCompareRegister)     \
+  V(ConditionalCompareImmediate)    \
+  V(ConditionalSelect)              \
+  V(DataProcessing1Source)          \
+  V(DataProcessing2Source)          \
+  V(DataProcessing3Source)          \
+  V(FPCompare)                      \
+  V(FPConditionalCompare)           \
+  V(FPConditionalSelect)            \
+  V(FPImmediate)                    \
+  V(FPDataProcessing1Source)        \
+  V(FPDataProcessing2Source)        \
+  V(FPDataProcessing3Source)        \
+  V(FPIntegerConvert)               \
+  V(FPFixedPointConvert)            \
+  V(Unallocated)                    \
+  V(Unimplemented)
+
+// The Visitor interface. Disassembler and simulator (and other tools)
+// must provide implementations for all of these functions.
+class DecoderVisitor {
+ public:
+  virtual ~DecoderVisitor() {}
+
+  #define DECLARE(A) virtual void Visit##A(Instruction* instr) = 0;
+  VISITOR_LIST(DECLARE)
+  #undef DECLARE
+};
+
+
+// A visitor that dispatches to a list of visitors.
+class DispatchingDecoderVisitor : public DecoderVisitor {
+ public:
+  DispatchingDecoderVisitor() {}
+  virtual ~DispatchingDecoderVisitor() {}
+
+  // Register a new visitor class with the decoder.
+  // Decode() will call the corresponding visitor method from all registered
+  // visitor classes when decoding reaches the leaf node of the instruction
+  // decode tree.
+  // Visitors are called in the order.
+  // A visitor can only be registered once.
+  // Registering an already registered visitor will update its position.
+  //
+  //   d.AppendVisitor(V1);
+  //   d.AppendVisitor(V2);
+  //   d.PrependVisitor(V2);            // Move V2 at the start of the list.
+  //   d.InsertVisitorBefore(V3, V2);
+  //   d.AppendVisitor(V4);
+  //   d.AppendVisitor(V4);             // No effect.
+  //
+  //   d.Decode(i);
+  //
+  // will call in order visitor methods in V3, V2, V1, V4.
+  void AppendVisitor(DecoderVisitor* visitor);
+  void PrependVisitor(DecoderVisitor* visitor);
+  void InsertVisitorBefore(DecoderVisitor* new_visitor,
+                           DecoderVisitor* registered_visitor);
+  void InsertVisitorAfter(DecoderVisitor* new_visitor,
+                          DecoderVisitor* registered_visitor);
+
+  // Remove a previously registered visitor class from the list of visitors
+  // stored by the decoder.
+  void RemoveVisitor(DecoderVisitor* visitor);
+
+  #define DECLARE(A) void Visit##A(Instruction* instr);
+  VISITOR_LIST(DECLARE)
+  #undef DECLARE
+
+ private:
+  // Visitors are registered in a list.
+  std::list<DecoderVisitor*> visitors_;
+};
+
+
+template<typename V>
+class Decoder : public V {
+ public:
+  Decoder() {}
+  virtual ~Decoder() {}
+
+  // Top-level instruction decoder function. Decodes an instruction and calls
+  // the visitor functions registered with the Decoder class.
+  virtual void Decode(Instruction *instr);
+
+ private:
+  // Decode the PC relative addressing instruction, and call the corresponding
+  // visitors.
+  // On entry, instruction bits 27:24 = 0x0.
+  void DecodePCRelAddressing(Instruction* instr);
+
+  // Decode the add/subtract immediate instruction, and call the corresponding
+  // visitors.
+  // On entry, instruction bits 27:24 = 0x1.
+  void DecodeAddSubImmediate(Instruction* instr);
+
+  // Decode the branch, system command, and exception generation parts of
+  // the instruction tree, and call the corresponding visitors.
+  // On entry, instruction bits 27:24 = {0x4, 0x5, 0x6, 0x7}.
+  void DecodeBranchSystemException(Instruction* instr);
+
+  // Decode the load and store parts of the instruction tree, and call
+  // the corresponding visitors.
+  // On entry, instruction bits 27:24 = {0x8, 0x9, 0xC, 0xD}.
+  void DecodeLoadStore(Instruction* instr);
+
+  // Decode the logical immediate and move wide immediate parts of the
+  // instruction tree, and call the corresponding visitors.
+  // On entry, instruction bits 27:24 = 0x2.
+  void DecodeLogical(Instruction* instr);
+
+  // Decode the bitfield and extraction parts of the instruction tree,
+  // and call the corresponding visitors.
+  // On entry, instruction bits 27:24 = 0x3.
+  void DecodeBitfieldExtract(Instruction* instr);
+
+  // Decode the data processing parts of the instruction tree, and call the
+  // corresponding visitors.
+  // On entry, instruction bits 27:24 = {0x1, 0xA, 0xB}.
+  void DecodeDataProcessing(Instruction* instr);
+
+  // Decode the floating point parts of the instruction tree, and call the
+  // corresponding visitors.
+  // On entry, instruction bits 27:24 = {0xE, 0xF}.
+  void DecodeFP(Instruction* instr);
+
+  // Decode the Advanced SIMD (NEON) load/store part of the instruction tree,
+  // and call the corresponding visitors.
+  // On entry, instruction bits 29:25 = 0x6.
+  void DecodeAdvSIMDLoadStore(Instruction* instr);
+
+  // Decode the Advanced SIMD (NEON) data processing part of the instruction
+  // tree, and call the corresponding visitors.
+  // On entry, instruction bits 27:25 = 0x7.
+  void DecodeAdvSIMDDataProcessing(Instruction* instr);
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_DECODER_ARM64_H_
diff --git a/src/arm64/delayed-masm-arm64-inl.h b/src/arm64/delayed-masm-arm64-inl.h
new file mode 100644
index 0000000..2c44630
--- /dev/null
+++ b/src/arm64/delayed-masm-arm64-inl.h
@@ -0,0 +1,55 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_DELAYED_MASM_ARM64_INL_H_
+#define V8_ARM64_DELAYED_MASM_ARM64_INL_H_
+
+#include "src/arm64/delayed-masm-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm_)
+
+
+void DelayedMasm::EndDelayedUse() {
+  EmitPending();
+  DCHECK(!scratch_register_acquired_);
+  ResetSavedValue();
+}
+
+
+void DelayedMasm::Mov(const Register& rd,
+                      const Operand& operand,
+                      DiscardMoveMode discard_mode) {
+  EmitPending();
+  DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
+  __ Mov(rd, operand, discard_mode);
+}
+
+
+void DelayedMasm::Fmov(FPRegister fd, FPRegister fn) {
+  EmitPending();
+  __ Fmov(fd, fn);
+}
+
+
+void DelayedMasm::Fmov(FPRegister fd, double imm) {
+  EmitPending();
+  __ Fmov(fd, imm);
+}
+
+
+void DelayedMasm::LoadObject(Register result, Handle<Object> object) {
+  EmitPending();
+  DCHECK(!IsScratchRegister(result) || scratch_register_acquired_);
+  __ LoadObject(result, object);
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_DELAYED_MASM_ARM64_INL_H_
diff --git a/src/arm64/delayed-masm-arm64.cc b/src/arm64/delayed-masm-arm64.cc
new file mode 100644
index 0000000..c3bda91
--- /dev/null
+++ b/src/arm64/delayed-masm-arm64.cc
@@ -0,0 +1,198 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/delayed-masm-arm64.h"
+#include "src/arm64/lithium-codegen-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm_)
+
+
+void DelayedMasm::StackSlotMove(LOperand* src, LOperand* dst) {
+  DCHECK(src->IsStackSlot());
+  DCHECK(dst->IsStackSlot());
+  MemOperand src_operand = cgen_->ToMemOperand(src);
+  MemOperand dst_operand = cgen_->ToMemOperand(dst);
+  if (pending_ == kStackSlotMove) {
+    DCHECK(pending_pc_ == masm_->pc_offset());
+    UseScratchRegisterScope scope(masm_);
+    DoubleRegister temp1 = scope.AcquireD();
+    DoubleRegister temp2 = scope.AcquireD();
+    switch (MemOperand::AreConsistentForPair(pending_address_src_,
+                                             src_operand)) {
+      case MemOperand::kNotPair:
+        __ Ldr(temp1, pending_address_src_);
+        __ Ldr(temp2, src_operand);
+        break;
+      case MemOperand::kPairAB:
+        __ Ldp(temp1, temp2, pending_address_src_);
+        break;
+      case MemOperand::kPairBA:
+        __ Ldp(temp2, temp1, src_operand);
+        break;
+    }
+    switch (MemOperand::AreConsistentForPair(pending_address_dst_,
+                                             dst_operand)) {
+      case MemOperand::kNotPair:
+        __ Str(temp1, pending_address_dst_);
+        __ Str(temp2, dst_operand);
+        break;
+      case MemOperand::kPairAB:
+        __ Stp(temp1, temp2, pending_address_dst_);
+        break;
+      case MemOperand::kPairBA:
+        __ Stp(temp2, temp1, dst_operand);
+        break;
+    }
+    ResetPending();
+    return;
+  }
+
+  EmitPending();
+  pending_ = kStackSlotMove;
+  pending_address_src_ = src_operand;
+  pending_address_dst_ = dst_operand;
+#ifdef DEBUG
+  pending_pc_ = masm_->pc_offset();
+#endif
+}
+
+
+void DelayedMasm::StoreConstant(uint64_t value, const MemOperand& operand) {
+  DCHECK(!scratch_register_acquired_);
+  if ((pending_ == kStoreConstant) && (value == pending_value_)) {
+    MemOperand::PairResult result =
+        MemOperand::AreConsistentForPair(pending_address_dst_, operand);
+    if (result != MemOperand::kNotPair) {
+      const MemOperand& dst =
+          (result == MemOperand::kPairAB) ?
+              pending_address_dst_ :
+              operand;
+      DCHECK(pending_pc_ == masm_->pc_offset());
+      if (pending_value_ == 0) {
+        __ Stp(xzr, xzr, dst);
+      } else {
+        SetSavedValue(pending_value_);
+        __ Stp(ScratchRegister(), ScratchRegister(), dst);
+      }
+      ResetPending();
+      return;
+    }
+  }
+
+  EmitPending();
+  pending_ = kStoreConstant;
+  pending_address_dst_ = operand;
+  pending_value_ = value;
+#ifdef DEBUG
+  pending_pc_ = masm_->pc_offset();
+#endif
+}
+
+
+void DelayedMasm::Load(const CPURegister& rd, const MemOperand& operand) {
+  if ((pending_ == kLoad) &&
+      pending_register_.IsSameSizeAndType(rd)) {
+    switch (MemOperand::AreConsistentForPair(pending_address_src_, operand)) {
+      case MemOperand::kNotPair:
+        break;
+      case MemOperand::kPairAB:
+        DCHECK(pending_pc_ == masm_->pc_offset());
+        DCHECK(!IsScratchRegister(pending_register_) ||
+               scratch_register_acquired_);
+        DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
+        __ Ldp(pending_register_, rd, pending_address_src_);
+        ResetPending();
+        return;
+      case MemOperand::kPairBA:
+        DCHECK(pending_pc_ == masm_->pc_offset());
+        DCHECK(!IsScratchRegister(pending_register_) ||
+               scratch_register_acquired_);
+        DCHECK(!IsScratchRegister(rd) || scratch_register_acquired_);
+        __ Ldp(rd, pending_register_, operand);
+        ResetPending();
+        return;
+    }
+  }
+
+  EmitPending();
+  pending_ = kLoad;
+  pending_register_ = rd;
+  pending_address_src_ = operand;
+#ifdef DEBUG
+  pending_pc_ = masm_->pc_offset();
+#endif
+}
+
+
+void DelayedMasm::Store(const CPURegister& rd, const MemOperand& operand) {
+  if ((pending_ == kStore) &&
+      pending_register_.IsSameSizeAndType(rd)) {
+    switch (MemOperand::AreConsistentForPair(pending_address_dst_, operand)) {
+      case MemOperand::kNotPair:
+        break;
+      case MemOperand::kPairAB:
+        DCHECK(pending_pc_ == masm_->pc_offset());
+        __ Stp(pending_register_, rd, pending_address_dst_);
+        ResetPending();
+        return;
+      case MemOperand::kPairBA:
+        DCHECK(pending_pc_ == masm_->pc_offset());
+        __ Stp(rd, pending_register_, operand);
+        ResetPending();
+        return;
+    }
+  }
+
+  EmitPending();
+  pending_ = kStore;
+  pending_register_ = rd;
+  pending_address_dst_ = operand;
+#ifdef DEBUG
+  pending_pc_ = masm_->pc_offset();
+#endif
+}
+
+
+void DelayedMasm::EmitPending() {
+  DCHECK((pending_ == kNone) || (pending_pc_ == masm_->pc_offset()));
+  switch (pending_) {
+    case kNone:
+      return;
+    case kStoreConstant:
+      if (pending_value_ == 0) {
+        __ Str(xzr, pending_address_dst_);
+      } else {
+        SetSavedValue(pending_value_);
+        __ Str(ScratchRegister(), pending_address_dst_);
+      }
+      break;
+    case kLoad:
+      DCHECK(!IsScratchRegister(pending_register_) ||
+              scratch_register_acquired_);
+      __ Ldr(pending_register_, pending_address_src_);
+      break;
+    case kStore:
+      __ Str(pending_register_, pending_address_dst_);
+      break;
+    case kStackSlotMove: {
+      UseScratchRegisterScope scope(masm_);
+      DoubleRegister temp = scope.AcquireD();
+      __ Ldr(temp, pending_address_src_);
+      __ Str(temp, pending_address_dst_);
+      break;
+    }
+  }
+  ResetPending();
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/delayed-masm-arm64.h b/src/arm64/delayed-masm-arm64.h
new file mode 100644
index 0000000..76227a3
--- /dev/null
+++ b/src/arm64/delayed-masm-arm64.h
@@ -0,0 +1,164 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_DELAYED_MASM_ARM64_H_
+#define V8_ARM64_DELAYED_MASM_ARM64_H_
+
+#include "src/lithium.h"
+
+namespace v8 {
+namespace internal {
+
+class LCodeGen;
+
+// This class delays the generation of some instructions. This way, we have a
+// chance to merge two instructions in one (with load/store pair).
+// Each instruction must either:
+//  - merge with the pending instruction and generate just one instruction.
+//  - emit the pending instruction and then generate the instruction (or set the
+//    pending instruction).
+class DelayedMasm BASE_EMBEDDED {
+ public:
+  DelayedMasm(LCodeGen* owner,
+              MacroAssembler* masm,
+              const Register& scratch_register)
+    : cgen_(owner), masm_(masm), scratch_register_(scratch_register),
+      scratch_register_used_(false), pending_(kNone), saved_value_(0) {
+#ifdef DEBUG
+    pending_register_ = no_reg;
+    pending_value_ = 0;
+    pending_pc_ = 0;
+    scratch_register_acquired_ = false;
+#endif
+  }
+  ~DelayedMasm() {
+    DCHECK(!scratch_register_acquired_);
+    DCHECK(!scratch_register_used_);
+    DCHECK(!pending());
+  }
+  inline void EndDelayedUse();
+
+  const Register& ScratchRegister() {
+    scratch_register_used_ = true;
+    return scratch_register_;
+  }
+  bool IsScratchRegister(const CPURegister& reg) {
+    return reg.Is(scratch_register_);
+  }
+  bool scratch_register_used() const { return scratch_register_used_; }
+  void reset_scratch_register_used() { scratch_register_used_ = false; }
+  // Acquire/Release scratch register for use outside this class.
+  void AcquireScratchRegister() {
+    EmitPending();
+    ResetSavedValue();
+#ifdef DEBUG
+    DCHECK(!scratch_register_acquired_);
+    scratch_register_acquired_ = true;
+#endif
+  }
+  void ReleaseScratchRegister() {
+#ifdef DEBUG
+    DCHECK(scratch_register_acquired_);
+    scratch_register_acquired_ = false;
+#endif
+  }
+  bool pending() { return pending_ != kNone; }
+
+  // Extra layer over the macro-assembler instructions (which emits the
+  // potential pending instruction).
+  inline void Mov(const Register& rd,
+                  const Operand& operand,
+                  DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
+  inline void Fmov(FPRegister fd, FPRegister fn);
+  inline void Fmov(FPRegister fd, double imm);
+  inline void LoadObject(Register result, Handle<Object> object);
+  // Instructions which try to merge which the pending instructions.
+  void StackSlotMove(LOperand* src, LOperand* dst);
+  // StoreConstant can only be used if the scratch register is not acquired.
+  void StoreConstant(uint64_t value, const MemOperand& operand);
+  void Load(const CPURegister& rd, const MemOperand& operand);
+  void Store(const CPURegister& rd, const MemOperand& operand);
+  // Emit the potential pending instruction.
+  void EmitPending();
+  // Reset the pending state.
+  void ResetPending() {
+    pending_ = kNone;
+#ifdef DEBUG
+    pending_register_ = no_reg;
+    MemOperand tmp;
+    pending_address_src_ = tmp;
+    pending_address_dst_ = tmp;
+    pending_value_ = 0;
+    pending_pc_ = 0;
+#endif
+  }
+  void InitializeRootRegister() {
+    masm_->InitializeRootRegister();
+  }
+
+ private:
+  // Set the saved value and load the ScratchRegister with it.
+  void SetSavedValue(uint64_t saved_value) {
+    DCHECK(saved_value != 0);
+    if (saved_value_ != saved_value) {
+      masm_->Mov(ScratchRegister(), saved_value);
+      saved_value_ = saved_value;
+    }
+  }
+  // Reset the saved value (i.e. the value of ScratchRegister is no longer
+  // known).
+  void ResetSavedValue() {
+    saved_value_ = 0;
+  }
+
+  LCodeGen* cgen_;
+  MacroAssembler* masm_;
+
+  // Register used to store a constant.
+  Register scratch_register_;
+  bool scratch_register_used_;
+
+  // Sometimes we store or load two values in two contiguous stack slots.
+  // In this case, we try to use the ldp/stp instructions to reduce code size.
+  // To be able to do that, instead of generating directly the instructions,
+  // we register with the following fields that an instruction needs to be
+  // generated. Then with the next instruction, if the instruction is
+  // consistent with the pending one for stp/ldp we generate ldp/stp. Else,
+  // if they are not consistent, we generate the pending instruction and we
+  // register the new instruction (which becomes pending).
+
+  // Enumeration of instructions which can be pending.
+  enum Pending {
+    kNone,
+    kStoreConstant,
+    kLoad, kStore,
+    kStackSlotMove
+  };
+  // The pending instruction.
+  Pending pending_;
+  // For kLoad, kStore: register which must be loaded/stored.
+  CPURegister pending_register_;
+  // For kLoad, kStackSlotMove: address of the load.
+  MemOperand pending_address_src_;
+  // For kStoreConstant, kStore, kStackSlotMove: address of the store.
+  MemOperand pending_address_dst_;
+  // For kStoreConstant: value to be stored.
+  uint64_t pending_value_;
+  // Value held into the ScratchRegister if the saved_value_ is not 0.
+  // For 0, we use xzr.
+  uint64_t saved_value_;
+#ifdef DEBUG
+  // Address where the pending instruction must be generated. It's only used to
+  // check that nothing else has been generated since we set the pending
+  // instruction.
+  int pending_pc_;
+  // If true, the scratch register has been acquired outside this class. The
+  // scratch register can no longer be used for constants.
+  bool scratch_register_acquired_;
+#endif
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_DELAYED_MASM_ARM64_H_
diff --git a/src/arm64/deoptimizer-arm64.cc b/src/arm64/deoptimizer-arm64.cc
new file mode 100644
index 0000000..d67dc8f
--- /dev/null
+++ b/src/arm64/deoptimizer-arm64.cc
@@ -0,0 +1,356 @@
+// Copyright 2013 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/v8.h"
+
+#include "src/codegen.h"
+#include "src/deoptimizer.h"
+#include "src/full-codegen.h"
+#include "src/safepoint-table.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+int Deoptimizer::patch_size() {
+  // Size of the code used to patch lazy bailout points.
+  // Patching is done by Deoptimizer::DeoptimizeFunction.
+  return 4 * kInstructionSize;
+}
+
+
+
+void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
+  // Invalidate the relocation information, as it will become invalid by the
+  // code patching below, and is not needed any more.
+  code->InvalidateRelocation();
+
+  // TODO(jkummerow): if (FLAG_zap_code_space), make the code object's
+  // entry sequence unusable (see other architectures).
+
+  DeoptimizationInputData* deopt_data =
+      DeoptimizationInputData::cast(code->deoptimization_data());
+  Address code_start_address = code->instruction_start();
+#ifdef DEBUG
+  Address prev_call_address = NULL;
+#endif
+  // For each LLazyBailout instruction insert a call to the corresponding
+  // deoptimization entry.
+  for (int i = 0; i < deopt_data->DeoptCount(); i++) {
+    if (deopt_data->Pc(i)->value() == -1) continue;
+
+    Address call_address = code_start_address + deopt_data->Pc(i)->value();
+    Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY);
+
+    PatchingAssembler patcher(call_address, patch_size() / kInstructionSize);
+    patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2);
+    patcher.blr(ip0);
+    patcher.dc64(reinterpret_cast<intptr_t>(deopt_entry));
+
+    DCHECK((prev_call_address == NULL) ||
+           (call_address >= prev_call_address + patch_size()));
+    DCHECK(call_address + patch_size() <= code->instruction_end());
+#ifdef DEBUG
+    prev_call_address = call_address;
+#endif
+  }
+}
+
+
+void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
+  // Set the register values. The values are not important as there are no
+  // callee saved registers in JavaScript frames, so all registers are
+  // spilled. Registers fp and sp are set to the correct values though.
+  for (int i = 0; i < Register::NumRegisters(); i++) {
+    input_->SetRegister(i, 0);
+  }
+
+  // TODO(all): Do we also need to set a value to csp?
+  input_->SetRegister(jssp.code(), reinterpret_cast<intptr_t>(frame->sp()));
+  input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp()));
+
+  for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) {
+    input_->SetDoubleRegister(i, 0.0);
+  }
+
+  // Fill the frame content from the actual data on the frame.
+  for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
+    input_->SetFrameSlot(i, Memory::uint64_at(tos + i));
+  }
+}
+
+
+bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
+  // There is no dynamic alignment padding on ARM64 in the input frame.
+  return false;
+}
+
+
+void Deoptimizer::SetPlatformCompiledStubRegisters(
+    FrameDescription* output_frame, CodeStubDescriptor* descriptor) {
+  ApiFunction function(descriptor->deoptimization_handler());
+  ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
+  intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
+  int params = descriptor->GetHandlerParameterCount();
+  output_frame->SetRegister(x0.code(), params);
+  output_frame->SetRegister(x1.code(), handler);
+}
+
+
+void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
+  for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) {
+    double double_value = input_->GetDoubleRegister(i);
+    output_frame->SetDoubleRegister(i, double_value);
+  }
+}
+
+
+
+#define __ masm()->
+
+void Deoptimizer::EntryGenerator::Generate() {
+  GeneratePrologue();
+
+  // TODO(all): This code needs to be revisited. We probably only need to save
+  // caller-saved registers here. Callee-saved registers can be stored directly
+  // in the input frame.
+
+  // Save all allocatable floating point registers.
+  CPURegList saved_fp_registers(CPURegister::kFPRegister, kDRegSizeInBits,
+                                FPRegister::kAllocatableFPRegisters);
+  __ PushCPURegList(saved_fp_registers);
+
+  // We save all the registers expcept jssp, sp and lr.
+  CPURegList saved_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 27);
+  saved_registers.Combine(fp);
+  __ PushCPURegList(saved_registers);
+
+  const int kSavedRegistersAreaSize =
+      (saved_registers.Count() * kXRegSize) +
+      (saved_fp_registers.Count() * kDRegSize);
+
+  // Floating point registers are saved on the stack above core registers.
+  const int kFPRegistersOffset = saved_registers.Count() * kXRegSize;
+
+  // Get the bailout id from the stack.
+  Register bailout_id = x2;
+  __ Peek(bailout_id, kSavedRegistersAreaSize);
+
+  Register code_object = x3;
+  Register fp_to_sp = x4;
+  // Get the address of the location in the code object. This is the return
+  // address for lazy deoptimization.
+  __ Mov(code_object, lr);
+  // Compute the fp-to-sp delta, and correct one word for bailout id.
+  __ Add(fp_to_sp, masm()->StackPointer(),
+         kSavedRegistersAreaSize + (1 * kPointerSize));
+  __ Sub(fp_to_sp, fp, fp_to_sp);
+
+  // Allocate a new deoptimizer object.
+  __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Mov(x1, type());
+  // Following arguments are already loaded:
+  //  - x2: bailout id
+  //  - x3: code object address
+  //  - x4: fp-to-sp delta
+  __ Mov(x5, ExternalReference::isolate_address(isolate()));
+
+  {
+    // Call Deoptimizer::New().
+    AllowExternalCallThatCantCauseGC scope(masm());
+    __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
+  }
+
+  // Preserve "deoptimizer" object in register x0.
+  Register deoptimizer = x0;
+
+  // Get the input frame descriptor pointer.
+  __ Ldr(x1, MemOperand(deoptimizer, Deoptimizer::input_offset()));
+
+  // Copy core registers into the input frame.
+  CPURegList copy_to_input = saved_registers;
+  for (int i = 0; i < saved_registers.Count(); i++) {
+    __ Peek(x2, i * kPointerSize);
+    CPURegister current_reg = copy_to_input.PopLowestIndex();
+    int offset = (current_reg.code() * kPointerSize) +
+        FrameDescription::registers_offset();
+    __ Str(x2, MemOperand(x1, offset));
+  }
+
+  // Copy FP registers to the input frame.
+  for (int i = 0; i < saved_fp_registers.Count(); i++) {
+    int dst_offset = FrameDescription::double_registers_offset() +
+        (i * kDoubleSize);
+    int src_offset = kFPRegistersOffset + (i * kDoubleSize);
+    __ Peek(x2, src_offset);
+    __ Str(x2, MemOperand(x1, dst_offset));
+  }
+
+  // Remove the bailout id and the saved registers from the stack.
+  __ Drop(1 + (kSavedRegistersAreaSize / kXRegSize));
+
+  // Compute a pointer to the unwinding limit in register x2; that is
+  // the first stack slot not part of the input frame.
+  Register unwind_limit = x2;
+  __ Ldr(unwind_limit, MemOperand(x1, FrameDescription::frame_size_offset()));
+  __ Add(unwind_limit, unwind_limit, __ StackPointer());
+
+  // Unwind the stack down to - but not including - the unwinding
+  // limit and copy the contents of the activation frame to the input
+  // frame description.
+  __ Add(x3, x1, FrameDescription::frame_content_offset());
+  Label pop_loop;
+  Label pop_loop_header;
+  __ B(&pop_loop_header);
+  __ Bind(&pop_loop);
+  __ Pop(x4);
+  __ Str(x4, MemOperand(x3, kPointerSize, PostIndex));
+  __ Bind(&pop_loop_header);
+  __ Cmp(unwind_limit, __ StackPointer());
+  __ B(ne, &pop_loop);
+
+  // Compute the output frame in the deoptimizer.
+  __ Push(x0);  // Preserve deoptimizer object across call.
+
+  {
+    // Call Deoptimizer::ComputeOutputFrames().
+    AllowExternalCallThatCantCauseGC scope(masm());
+    __ CallCFunction(
+        ExternalReference::compute_output_frames_function(isolate()), 1);
+  }
+  __ Pop(x4);  // Restore deoptimizer object (class Deoptimizer).
+
+  // Replace the current (input) frame with the output frames.
+  Label outer_push_loop, inner_push_loop,
+      outer_loop_header, inner_loop_header;
+  __ Ldrsw(x1, MemOperand(x4, Deoptimizer::output_count_offset()));
+  __ Ldr(x0, MemOperand(x4, Deoptimizer::output_offset()));
+  __ Add(x1, x0, Operand(x1, LSL, kPointerSizeLog2));
+  __ B(&outer_loop_header);
+
+  __ Bind(&outer_push_loop);
+  Register current_frame = x2;
+  __ Ldr(current_frame, MemOperand(x0, 0));
+  __ Ldr(x3, MemOperand(current_frame, FrameDescription::frame_size_offset()));
+  __ B(&inner_loop_header);
+
+  __ Bind(&inner_push_loop);
+  __ Sub(x3, x3, kPointerSize);
+  __ Add(x6, current_frame, x3);
+  __ Ldr(x7, MemOperand(x6, FrameDescription::frame_content_offset()));
+  __ Push(x7);
+  __ Bind(&inner_loop_header);
+  __ Cbnz(x3, &inner_push_loop);
+
+  __ Add(x0, x0, kPointerSize);
+  __ Bind(&outer_loop_header);
+  __ Cmp(x0, x1);
+  __ B(lt, &outer_push_loop);
+
+  __ Ldr(x1, MemOperand(x4, Deoptimizer::input_offset()));
+  DCHECK(!saved_fp_registers.IncludesAliasOf(crankshaft_fp_scratch) &&
+         !saved_fp_registers.IncludesAliasOf(fp_zero) &&
+         !saved_fp_registers.IncludesAliasOf(fp_scratch));
+  int src_offset = FrameDescription::double_registers_offset();
+  while (!saved_fp_registers.IsEmpty()) {
+    const CPURegister reg = saved_fp_registers.PopLowestIndex();
+    __ Ldr(reg, MemOperand(x1, src_offset));
+    src_offset += kDoubleSize;
+  }
+
+  // Push state from the last output frame.
+  __ Ldr(x6, MemOperand(current_frame, FrameDescription::state_offset()));
+  __ Push(x6);
+
+  // TODO(all): ARM copies a lot (if not all) of the last output frame onto the
+  // stack, then pops it all into registers. Here, we try to load it directly
+  // into the relevant registers. Is this correct? If so, we should improve the
+  // ARM code.
+
+  // TODO(all): This code needs to be revisited, We probably don't need to
+  // restore all the registers as fullcodegen does not keep live values in
+  // registers (note that at least fp must be restored though).
+
+  // Restore registers from the last output frame.
+  // Note that lr is not in the list of saved_registers and will be restored
+  // later. We can use it to hold the address of last output frame while
+  // reloading the other registers.
+  DCHECK(!saved_registers.IncludesAliasOf(lr));
+  Register last_output_frame = lr;
+  __ Mov(last_output_frame, current_frame);
+
+  // We don't need to restore x7 as it will be clobbered later to hold the
+  // continuation address.
+  Register continuation = x7;
+  saved_registers.Remove(continuation);
+
+  while (!saved_registers.IsEmpty()) {
+    // TODO(all): Look for opportunities to optimize this by using ldp.
+    CPURegister current_reg = saved_registers.PopLowestIndex();
+    int offset = (current_reg.code() * kPointerSize) +
+        FrameDescription::registers_offset();
+    __ Ldr(current_reg, MemOperand(last_output_frame, offset));
+  }
+
+  __ Ldr(continuation, MemOperand(last_output_frame,
+                                  FrameDescription::continuation_offset()));
+  __ Ldr(lr, MemOperand(last_output_frame, FrameDescription::pc_offset()));
+  __ InitializeRootRegister();
+  __ Br(continuation);
+}
+
+
+// Size of an entry of the second level deopt table.
+// This is the code size generated by GeneratePrologue for one entry.
+const int Deoptimizer::table_entry_size_ = 2 * kInstructionSize;
+
+
+void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
+  UseScratchRegisterScope temps(masm());
+  Register entry_id = temps.AcquireX();
+
+  // Create a sequence of deoptimization entries.
+  // Note that registers are still live when jumping to an entry.
+  Label done;
+  {
+    InstructionAccurateScope scope(masm());
+
+    // The number of entry will never exceed kMaxNumberOfEntries.
+    // As long as kMaxNumberOfEntries is a valid 16 bits immediate you can use
+    // a movz instruction to load the entry id.
+    DCHECK(is_uint16(Deoptimizer::kMaxNumberOfEntries));
+
+    for (int i = 0; i < count(); i++) {
+      int start = masm()->pc_offset();
+      USE(start);
+      __ movz(entry_id, i);
+      __ b(&done);
+      DCHECK(masm()->pc_offset() - start == table_entry_size_);
+    }
+  }
+  __ Bind(&done);
+  __ Push(entry_id);
+}
+
+
+void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) {
+  SetFrameSlot(offset, value);
+}
+
+
+void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
+  SetFrameSlot(offset, value);
+}
+
+
+void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
+  // No out-of-line constant pool support.
+  UNREACHABLE();
+}
+
+
+#undef __
+
+} }  // namespace v8::internal
diff --git a/src/arm64/disasm-arm64.cc b/src/arm64/disasm-arm64.cc
new file mode 100644
index 0000000..ac7cb37
--- /dev/null
+++ b/src/arm64/disasm-arm64.cc
@@ -0,0 +1,1834 @@
+// Copyright 2013 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 <assert.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/decoder-arm64-inl.h"
+#include "src/arm64/disasm-arm64.h"
+#include "src/base/platform/platform.h"
+#include "src/disasm.h"
+#include "src/macro-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+
+Disassembler::Disassembler() {
+  buffer_size_ = 256;
+  buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
+  buffer_pos_ = 0;
+  own_buffer_ = true;
+}
+
+
+Disassembler::Disassembler(char* text_buffer, int buffer_size) {
+  buffer_size_ = buffer_size;
+  buffer_ = text_buffer;
+  buffer_pos_ = 0;
+  own_buffer_ = false;
+}
+
+
+Disassembler::~Disassembler() {
+  if (own_buffer_) {
+    free(buffer_);
+  }
+}
+
+
+char* Disassembler::GetOutput() {
+  return buffer_;
+}
+
+
+void Disassembler::VisitAddSubImmediate(Instruction* instr) {
+  bool rd_is_zr = RdIsZROrSP(instr);
+  bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
+                  (instr->ImmAddSub() == 0) ? true : false;
+  const char *mnemonic = "";
+  const char *form = "'Rds, 'Rns, 'IAddSub";
+  const char *form_cmp = "'Rns, 'IAddSub";
+  const char *form_mov = "'Rds, 'Rns";
+
+  switch (instr->Mask(AddSubImmediateMask)) {
+    case ADD_w_imm:
+    case ADD_x_imm: {
+      mnemonic = "add";
+      if (stack_op) {
+        mnemonic = "mov";
+        form = form_mov;
+      }
+      break;
+    }
+    case ADDS_w_imm:
+    case ADDS_x_imm: {
+      mnemonic = "adds";
+      if (rd_is_zr) {
+        mnemonic = "cmn";
+        form = form_cmp;
+      }
+      break;
+    }
+    case SUB_w_imm:
+    case SUB_x_imm: mnemonic = "sub"; break;
+    case SUBS_w_imm:
+    case SUBS_x_imm: {
+      mnemonic = "subs";
+      if (rd_is_zr) {
+        mnemonic = "cmp";
+        form = form_cmp;
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitAddSubShifted(Instruction* instr) {
+  bool rd_is_zr = RdIsZROrSP(instr);
+  bool rn_is_zr = RnIsZROrSP(instr);
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn, 'Rm'HDP";
+  const char *form_cmp = "'Rn, 'Rm'HDP";
+  const char *form_neg = "'Rd, 'Rm'HDP";
+
+  switch (instr->Mask(AddSubShiftedMask)) {
+    case ADD_w_shift:
+    case ADD_x_shift: mnemonic = "add"; break;
+    case ADDS_w_shift:
+    case ADDS_x_shift: {
+      mnemonic = "adds";
+      if (rd_is_zr) {
+        mnemonic = "cmn";
+        form = form_cmp;
+      }
+      break;
+    }
+    case SUB_w_shift:
+    case SUB_x_shift: {
+      mnemonic = "sub";
+      if (rn_is_zr) {
+        mnemonic = "neg";
+        form = form_neg;
+      }
+      break;
+    }
+    case SUBS_w_shift:
+    case SUBS_x_shift: {
+      mnemonic = "subs";
+      if (rd_is_zr) {
+        mnemonic = "cmp";
+        form = form_cmp;
+      } else if (rn_is_zr) {
+        mnemonic = "negs";
+        form = form_neg;
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitAddSubExtended(Instruction* instr) {
+  bool rd_is_zr = RdIsZROrSP(instr);
+  const char *mnemonic = "";
+  Extend mode = static_cast<Extend>(instr->ExtendMode());
+  const char *form = ((mode == UXTX) || (mode == SXTX)) ?
+                     "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
+  const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
+                         "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
+
+  switch (instr->Mask(AddSubExtendedMask)) {
+    case ADD_w_ext:
+    case ADD_x_ext: mnemonic = "add"; break;
+    case ADDS_w_ext:
+    case ADDS_x_ext: {
+      mnemonic = "adds";
+      if (rd_is_zr) {
+        mnemonic = "cmn";
+        form = form_cmp;
+      }
+      break;
+    }
+    case SUB_w_ext:
+    case SUB_x_ext: mnemonic = "sub"; break;
+    case SUBS_w_ext:
+    case SUBS_x_ext: {
+      mnemonic = "subs";
+      if (rd_is_zr) {
+        mnemonic = "cmp";
+        form = form_cmp;
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
+  bool rn_is_zr = RnIsZROrSP(instr);
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn, 'Rm";
+  const char *form_neg = "'Rd, 'Rm";
+
+  switch (instr->Mask(AddSubWithCarryMask)) {
+    case ADC_w:
+    case ADC_x: mnemonic = "adc"; break;
+    case ADCS_w:
+    case ADCS_x: mnemonic = "adcs"; break;
+    case SBC_w:
+    case SBC_x: {
+      mnemonic = "sbc";
+      if (rn_is_zr) {
+        mnemonic = "ngc";
+        form = form_neg;
+      }
+      break;
+    }
+    case SBCS_w:
+    case SBCS_x: {
+      mnemonic = "sbcs";
+      if (rn_is_zr) {
+        mnemonic = "ngcs";
+        form = form_neg;
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLogicalImmediate(Instruction* instr) {
+  bool rd_is_zr = RdIsZROrSP(instr);
+  bool rn_is_zr = RnIsZROrSP(instr);
+  const char *mnemonic = "";
+  const char *form = "'Rds, 'Rn, 'ITri";
+
+  if (instr->ImmLogical() == 0) {
+    // The immediate encoded in the instruction is not in the expected format.
+    Format(instr, "unallocated", "(LogicalImmediate)");
+    return;
+  }
+
+  switch (instr->Mask(LogicalImmediateMask)) {
+    case AND_w_imm:
+    case AND_x_imm: mnemonic = "and"; break;
+    case ORR_w_imm:
+    case ORR_x_imm: {
+      mnemonic = "orr";
+      unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
+                                                        : kWRegSizeInBits;
+      if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
+        mnemonic = "mov";
+        form = "'Rds, 'ITri";
+      }
+      break;
+    }
+    case EOR_w_imm:
+    case EOR_x_imm: mnemonic = "eor"; break;
+    case ANDS_w_imm:
+    case ANDS_x_imm: {
+      mnemonic = "ands";
+      if (rd_is_zr) {
+        mnemonic = "tst";
+        form = "'Rn, 'ITri";
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
+  DCHECK((reg_size == kXRegSizeInBits) ||
+         ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff)));
+
+  // Test for movz: 16-bits set at positions 0, 16, 32 or 48.
+  if (((value & 0xffffffffffff0000UL) == 0UL) ||
+      ((value & 0xffffffff0000ffffUL) == 0UL) ||
+      ((value & 0xffff0000ffffffffUL) == 0UL) ||
+      ((value & 0x0000ffffffffffffUL) == 0UL)) {
+    return true;
+  }
+
+  // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48).
+  if ((reg_size == kXRegSizeInBits) &&
+      (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
+       ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
+       ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
+       ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
+    return true;
+  }
+  if ((reg_size == kWRegSizeInBits) &&
+      (((value & 0xffff0000) == 0xffff0000) ||
+       ((value & 0x0000ffff) == 0x0000ffff))) {
+    return true;
+  }
+  return false;
+}
+
+
+void Disassembler::VisitLogicalShifted(Instruction* instr) {
+  bool rd_is_zr = RdIsZROrSP(instr);
+  bool rn_is_zr = RnIsZROrSP(instr);
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn, 'Rm'HLo";
+
+  switch (instr->Mask(LogicalShiftedMask)) {
+    case AND_w:
+    case AND_x: mnemonic = "and"; break;
+    case BIC_w:
+    case BIC_x: mnemonic = "bic"; break;
+    case EOR_w:
+    case EOR_x: mnemonic = "eor"; break;
+    case EON_w:
+    case EON_x: mnemonic = "eon"; break;
+    case BICS_w:
+    case BICS_x: mnemonic = "bics"; break;
+    case ANDS_w:
+    case ANDS_x: {
+      mnemonic = "ands";
+      if (rd_is_zr) {
+        mnemonic = "tst";
+        form = "'Rn, 'Rm'HLo";
+      }
+      break;
+    }
+    case ORR_w:
+    case ORR_x: {
+      mnemonic = "orr";
+      if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
+        mnemonic = "mov";
+        form = "'Rd, 'Rm";
+      }
+      break;
+    }
+    case ORN_w:
+    case ORN_x: {
+      mnemonic = "orn";
+      if (rn_is_zr) {
+        mnemonic = "mvn";
+        form = "'Rd, 'Rm'HLo";
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
+
+  switch (instr->Mask(ConditionalCompareRegisterMask)) {
+    case CCMN_w:
+    case CCMN_x: mnemonic = "ccmn"; break;
+    case CCMP_w:
+    case CCMP_x: mnemonic = "ccmp"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
+
+  switch (instr->Mask(ConditionalCompareImmediateMask)) {
+    case CCMN_w_imm:
+    case CCMN_x_imm: mnemonic = "ccmn"; break;
+    case CCMP_w_imm:
+    case CCMP_x_imm: mnemonic = "ccmp"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitConditionalSelect(Instruction* instr) {
+  bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
+  bool rn_is_rm = (instr->Rn() == instr->Rm());
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
+  const char *form_test = "'Rd, 'CInv";
+  const char *form_update = "'Rd, 'Rn, 'CInv";
+
+  Condition cond = static_cast<Condition>(instr->Condition());
+  bool invertible_cond = (cond != al) && (cond != nv);
+
+  switch (instr->Mask(ConditionalSelectMask)) {
+    case CSEL_w:
+    case CSEL_x: mnemonic = "csel"; break;
+    case CSINC_w:
+    case CSINC_x: {
+      mnemonic = "csinc";
+      if (rnm_is_zr && invertible_cond) {
+        mnemonic = "cset";
+        form = form_test;
+      } else if (rn_is_rm && invertible_cond) {
+        mnemonic = "cinc";
+        form = form_update;
+      }
+      break;
+    }
+    case CSINV_w:
+    case CSINV_x: {
+      mnemonic = "csinv";
+      if (rnm_is_zr && invertible_cond) {
+        mnemonic = "csetm";
+        form = form_test;
+      } else if (rn_is_rm && invertible_cond) {
+        mnemonic = "cinv";
+        form = form_update;
+      }
+      break;
+    }
+    case CSNEG_w:
+    case CSNEG_x: {
+      mnemonic = "csneg";
+      if (rn_is_rm && invertible_cond) {
+        mnemonic = "cneg";
+        form = form_update;
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitBitfield(Instruction* instr) {
+  unsigned s = instr->ImmS();
+  unsigned r = instr->ImmR();
+  unsigned rd_size_minus_1 =
+    ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1;
+  const char *mnemonic = "";
+  const char *form = "";
+  const char *form_shift_right = "'Rd, 'Rn, 'IBr";
+  const char *form_extend = "'Rd, 'Wn";
+  const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
+  const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
+  const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
+
+  switch (instr->Mask(BitfieldMask)) {
+    case SBFM_w:
+    case SBFM_x: {
+      mnemonic = "sbfx";
+      form = form_bfx;
+      if (r == 0) {
+        form = form_extend;
+        if (s == 7) {
+          mnemonic = "sxtb";
+        } else if (s == 15) {
+          mnemonic = "sxth";
+        } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
+          mnemonic = "sxtw";
+        } else {
+          form = form_bfx;
+        }
+      } else if (s == rd_size_minus_1) {
+        mnemonic = "asr";
+        form = form_shift_right;
+      } else if (s < r) {
+        mnemonic = "sbfiz";
+        form = form_bfiz;
+      }
+      break;
+    }
+    case UBFM_w:
+    case UBFM_x: {
+      mnemonic = "ubfx";
+      form = form_bfx;
+      if (r == 0) {
+        form = form_extend;
+        if (s == 7) {
+          mnemonic = "uxtb";
+        } else if (s == 15) {
+          mnemonic = "uxth";
+        } else {
+          form = form_bfx;
+        }
+      }
+      if (s == rd_size_minus_1) {
+        mnemonic = "lsr";
+        form = form_shift_right;
+      } else if (r == s + 1) {
+        mnemonic = "lsl";
+        form = form_lsl;
+      } else if (s < r) {
+        mnemonic = "ubfiz";
+        form = form_bfiz;
+      }
+      break;
+    }
+    case BFM_w:
+    case BFM_x: {
+      mnemonic = "bfxil";
+      form = form_bfx;
+      if (s < r) {
+        mnemonic = "bfi";
+        form = form_bfiz;
+      }
+    }
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitExtract(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
+
+  switch (instr->Mask(ExtractMask)) {
+    case EXTR_w:
+    case EXTR_x: {
+      if (instr->Rn() == instr->Rm()) {
+        mnemonic = "ror";
+        form = "'Rd, 'Rn, 'IExtract";
+      } else {
+        mnemonic = "extr";
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitPCRelAddressing(Instruction* instr) {
+  switch (instr->Mask(PCRelAddressingMask)) {
+    case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
+    // ADRP is not implemented.
+    default: Format(instr, "unimplemented", "(PCRelAddressing)");
+  }
+}
+
+
+void Disassembler::VisitConditionalBranch(Instruction* instr) {
+  switch (instr->Mask(ConditionalBranchMask)) {
+    case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
+    default: UNREACHABLE();
+  }
+}
+
+
+void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Xn";
+
+  switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
+    case BR: mnemonic = "br"; break;
+    case BLR: mnemonic = "blr"; break;
+    case RET: {
+      mnemonic = "ret";
+      if (instr->Rn() == kLinkRegCode) {
+        form = NULL;
+      }
+      break;
+    }
+    default: form = "(UnconditionalBranchToRegister)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'BImmUncn";
+
+  switch (instr->Mask(UnconditionalBranchMask)) {
+    case B: mnemonic = "b"; break;
+    case BL: mnemonic = "bl"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Rn";
+
+  switch (instr->Mask(DataProcessing1SourceMask)) {
+    #define FORMAT(A, B)  \
+    case A##_w:           \
+    case A##_x: mnemonic = B; break;
+    FORMAT(RBIT, "rbit");
+    FORMAT(REV16, "rev16");
+    FORMAT(REV, "rev");
+    FORMAT(CLZ, "clz");
+    FORMAT(CLS, "cls");
+    #undef FORMAT
+    case REV32_x: mnemonic = "rev32"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Rd, 'Rn, 'Rm";
+
+  switch (instr->Mask(DataProcessing2SourceMask)) {
+    #define FORMAT(A, B)  \
+    case A##_w:           \
+    case A##_x: mnemonic = B; break;
+    FORMAT(UDIV, "udiv");
+    FORMAT(SDIV, "sdiv");
+    FORMAT(LSLV, "lsl");
+    FORMAT(LSRV, "lsr");
+    FORMAT(ASRV, "asr");
+    FORMAT(RORV, "ror");
+    #undef FORMAT
+    default: form = "(DataProcessing2Source)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
+  bool ra_is_zr = RaIsZROrSP(instr);
+  const char *mnemonic = "";
+  const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
+  const char *form_rrr = "'Rd, 'Rn, 'Rm";
+  const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
+  const char *form_xww = "'Xd, 'Wn, 'Wm";
+  const char *form_xxx = "'Xd, 'Xn, 'Xm";
+
+  switch (instr->Mask(DataProcessing3SourceMask)) {
+    case MADD_w:
+    case MADD_x: {
+      mnemonic = "madd";
+      form = form_rrrr;
+      if (ra_is_zr) {
+        mnemonic = "mul";
+        form = form_rrr;
+      }
+      break;
+    }
+    case MSUB_w:
+    case MSUB_x: {
+      mnemonic = "msub";
+      form = form_rrrr;
+      if (ra_is_zr) {
+        mnemonic = "mneg";
+        form = form_rrr;
+      }
+      break;
+    }
+    case SMADDL_x: {
+      mnemonic = "smaddl";
+      if (ra_is_zr) {
+        mnemonic = "smull";
+        form = form_xww;
+      }
+      break;
+    }
+    case SMSUBL_x: {
+      mnemonic = "smsubl";
+      if (ra_is_zr) {
+        mnemonic = "smnegl";
+        form = form_xww;
+      }
+      break;
+    }
+    case UMADDL_x: {
+      mnemonic = "umaddl";
+      if (ra_is_zr) {
+        mnemonic = "umull";
+        form = form_xww;
+      }
+      break;
+    }
+    case UMSUBL_x: {
+      mnemonic = "umsubl";
+      if (ra_is_zr) {
+        mnemonic = "umnegl";
+        form = form_xww;
+      }
+      break;
+    }
+    case SMULH_x: {
+      mnemonic = "smulh";
+      form = form_xxx;
+      break;
+    }
+    case UMULH_x: {
+      mnemonic = "umulh";
+      form = form_xxx;
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitCompareBranch(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rt, 'BImmCmpa";
+
+  switch (instr->Mask(CompareBranchMask)) {
+    case CBZ_w:
+    case CBZ_x: mnemonic = "cbz"; break;
+    case CBNZ_w:
+    case CBNZ_x: mnemonic = "cbnz"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitTestBranch(Instruction* instr) {
+  const char *mnemonic = "";
+  // If the top bit of the immediate is clear, the tested register is
+  // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
+  // encoded in bit 31 of the instruction, we can reuse the Rt form, which
+  // uses bit 31 (normally "sf") to choose the register size.
+  const char *form = "'Rt, 'IS, 'BImmTest";
+
+  switch (instr->Mask(TestBranchMask)) {
+    case TBZ: mnemonic = "tbz"; break;
+    case TBNZ: mnemonic = "tbnz"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'IMoveImm";
+
+  // Print the shift separately for movk, to make it clear which half word will
+  // be overwritten. Movn and movz print the computed immediate, which includes
+  // shift calculation.
+  switch (instr->Mask(MoveWideImmediateMask)) {
+    case MOVN_w:
+    case MOVN_x: mnemonic = "movn"; break;
+    case MOVZ_w:
+    case MOVZ_x: mnemonic = "movz"; break;
+    case MOVK_w:
+    case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+#define LOAD_STORE_LIST(V)    \
+  V(STRB_w, "strb", "'Wt")    \
+  V(STRH_w, "strh", "'Wt")    \
+  V(STR_w, "str", "'Wt")      \
+  V(STR_x, "str", "'Xt")      \
+  V(LDRB_w, "ldrb", "'Wt")    \
+  V(LDRH_w, "ldrh", "'Wt")    \
+  V(LDR_w, "ldr", "'Wt")      \
+  V(LDR_x, "ldr", "'Xt")      \
+  V(LDRSB_x, "ldrsb", "'Xt")  \
+  V(LDRSH_x, "ldrsh", "'Xt")  \
+  V(LDRSW_x, "ldrsw", "'Xt")  \
+  V(LDRSB_w, "ldrsb", "'Wt")  \
+  V(LDRSH_w, "ldrsh", "'Wt")  \
+  V(STR_s, "str", "'St")      \
+  V(STR_d, "str", "'Dt")      \
+  V(LDR_s, "ldr", "'St")      \
+  V(LDR_d, "ldr", "'Dt")
+
+void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStorePreIndex)";
+
+  switch (instr->Mask(LoadStorePreIndexMask)) {
+    #define LS_PREINDEX(A, B, C) \
+    case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
+    LOAD_STORE_LIST(LS_PREINDEX)
+    #undef LS_PREINDEX
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStorePostIndex)";
+
+  switch (instr->Mask(LoadStorePostIndexMask)) {
+    #define LS_POSTINDEX(A, B, C) \
+    case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
+    LOAD_STORE_LIST(LS_POSTINDEX)
+    #undef LS_POSTINDEX
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStoreUnsignedOffset)";
+
+  switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
+    #define LS_UNSIGNEDOFFSET(A, B, C) \
+    case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
+    LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
+    #undef LS_UNSIGNEDOFFSET
+    case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStoreRegisterOffset)";
+
+  switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
+    #define LS_REGISTEROFFSET(A, B, C) \
+    case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
+    LOAD_STORE_LIST(LS_REGISTEROFFSET)
+    #undef LS_REGISTEROFFSET
+    case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Wt, ['Xns'ILS]";
+  const char *form_x = "'Xt, ['Xns'ILS]";
+  const char *form_s = "'St, ['Xns'ILS]";
+  const char *form_d = "'Dt, ['Xns'ILS]";
+
+  switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
+    case STURB_w:  mnemonic = "sturb"; break;
+    case STURH_w:  mnemonic = "sturh"; break;
+    case STUR_w:   mnemonic = "stur"; break;
+    case STUR_x:   mnemonic = "stur"; form = form_x; break;
+    case STUR_s:   mnemonic = "stur"; form = form_s; break;
+    case STUR_d:   mnemonic = "stur"; form = form_d; break;
+    case LDURB_w:  mnemonic = "ldurb"; break;
+    case LDURH_w:  mnemonic = "ldurh"; break;
+    case LDUR_w:   mnemonic = "ldur"; break;
+    case LDUR_x:   mnemonic = "ldur"; form = form_x; break;
+    case LDUR_s:   mnemonic = "ldur"; form = form_s; break;
+    case LDUR_d:   mnemonic = "ldur"; form = form_d; break;
+    case LDURSB_x: form = form_x;  // Fall through.
+    case LDURSB_w: mnemonic = "ldursb"; break;
+    case LDURSH_x: form = form_x;  // Fall through.
+    case LDURSH_w: mnemonic = "ldursh"; break;
+    case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
+    default: form = "(LoadStoreUnscaledOffset)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadLiteral(Instruction* instr) {
+  const char *mnemonic = "ldr";
+  const char *form = "(LoadLiteral)";
+
+  switch (instr->Mask(LoadLiteralMask)) {
+    case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
+    case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
+    case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
+    case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
+    default: mnemonic = "unimplemented";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+#define LOAD_STORE_PAIR_LIST(V)         \
+  V(STP_w, "stp", "'Wt, 'Wt2", "4")     \
+  V(LDP_w, "ldp", "'Wt, 'Wt2", "4")     \
+  V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
+  V(STP_x, "stp", "'Xt, 'Xt2", "8")     \
+  V(LDP_x, "ldp", "'Xt, 'Xt2", "8")     \
+  V(STP_s, "stp", "'St, 'St2", "4")     \
+  V(LDP_s, "ldp", "'St, 'St2", "4")     \
+  V(STP_d, "stp", "'Dt, 'Dt2", "8")     \
+  V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
+
+void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStorePairPostIndex)";
+
+  switch (instr->Mask(LoadStorePairPostIndexMask)) {
+    #define LSP_POSTINDEX(A, B, C, D) \
+    case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
+    LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
+    #undef LSP_POSTINDEX
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStorePairPreIndex)";
+
+  switch (instr->Mask(LoadStorePairPreIndexMask)) {
+    #define LSP_PREINDEX(A, B, C, D) \
+    case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
+    LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
+    #undef LSP_PREINDEX
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(LoadStorePairOffset)";
+
+  switch (instr->Mask(LoadStorePairOffsetMask)) {
+    #define LSP_OFFSET(A, B, C, D) \
+    case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
+    LOAD_STORE_PAIR_LIST(LSP_OFFSET)
+    #undef LSP_OFFSET
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form;
+
+  switch (instr->Mask(LoadStorePairNonTemporalMask)) {
+    case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
+    case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
+    case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
+    case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
+    case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
+    case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
+    case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
+    case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
+    default: form = "(LoadStorePairNonTemporal)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPCompare(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Fn, 'Fm";
+  const char *form_zero = "'Fn, #0.0";
+
+  switch (instr->Mask(FPCompareMask)) {
+    case FCMP_s_zero:
+    case FCMP_d_zero: form = form_zero;  // Fall through.
+    case FCMP_s:
+    case FCMP_d: mnemonic = "fcmp"; break;
+    default: form = "(FPCompare)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
+
+  switch (instr->Mask(FPConditionalCompareMask)) {
+    case FCCMP_s:
+    case FCCMP_d: mnemonic = "fccmp"; break;
+    case FCCMPE_s:
+    case FCCMPE_d: mnemonic = "fccmpe"; break;
+    default: form = "(FPConditionalCompare)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
+
+  switch (instr->Mask(FPConditionalSelectMask)) {
+    case FCSEL_s:
+    case FCSEL_d: mnemonic = "fcsel"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'Fd, 'Fn";
+
+  switch (instr->Mask(FPDataProcessing1SourceMask)) {
+    #define FORMAT(A, B)  \
+    case A##_s:           \
+    case A##_d: mnemonic = B; break;
+    FORMAT(FMOV, "fmov");
+    FORMAT(FABS, "fabs");
+    FORMAT(FNEG, "fneg");
+    FORMAT(FSQRT, "fsqrt");
+    FORMAT(FRINTN, "frintn");
+    FORMAT(FRINTP, "frintp");
+    FORMAT(FRINTM, "frintm");
+    FORMAT(FRINTZ, "frintz");
+    FORMAT(FRINTA, "frinta");
+    FORMAT(FRINTX, "frintx");
+    FORMAT(FRINTI, "frinti");
+    #undef FORMAT
+    case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
+    case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
+    default: form = "(FPDataProcessing1Source)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Fd, 'Fn, 'Fm";
+
+  switch (instr->Mask(FPDataProcessing2SourceMask)) {
+    #define FORMAT(A, B)  \
+    case A##_s:           \
+    case A##_d: mnemonic = B; break;
+    FORMAT(FMUL, "fmul");
+    FORMAT(FDIV, "fdiv");
+    FORMAT(FADD, "fadd");
+    FORMAT(FSUB, "fsub");
+    FORMAT(FMAX, "fmax");
+    FORMAT(FMIN, "fmin");
+    FORMAT(FMAXNM, "fmaxnm");
+    FORMAT(FMINNM, "fminnm");
+    FORMAT(FNMUL, "fnmul");
+    #undef FORMAT
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
+
+  switch (instr->Mask(FPDataProcessing3SourceMask)) {
+    #define FORMAT(A, B)  \
+    case A##_s:           \
+    case A##_d: mnemonic = B; break;
+    FORMAT(FMADD, "fmadd");
+    FORMAT(FMSUB, "fmsub");
+    FORMAT(FNMADD, "fnmadd");
+    FORMAT(FNMSUB, "fnmsub");
+    #undef FORMAT
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPImmediate(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "(FPImmediate)";
+
+  switch (instr->Mask(FPImmediateMask)) {
+    case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
+    case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
+    default: UNREACHABLE();
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "(FPIntegerConvert)";
+  const char *form_rf = "'Rd, 'Fn";
+  const char *form_fr = "'Fd, 'Rn";
+
+  switch (instr->Mask(FPIntegerConvertMask)) {
+    case FMOV_ws:
+    case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
+    case FMOV_sw:
+    case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
+    case FCVTAS_ws:
+    case FCVTAS_xs:
+    case FCVTAS_wd:
+    case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
+    case FCVTAU_ws:
+    case FCVTAU_xs:
+    case FCVTAU_wd:
+    case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
+    case FCVTMS_ws:
+    case FCVTMS_xs:
+    case FCVTMS_wd:
+    case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
+    case FCVTMU_ws:
+    case FCVTMU_xs:
+    case FCVTMU_wd:
+    case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
+    case FCVTNS_ws:
+    case FCVTNS_xs:
+    case FCVTNS_wd:
+    case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
+    case FCVTNU_ws:
+    case FCVTNU_xs:
+    case FCVTNU_wd:
+    case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
+    case FCVTZU_xd:
+    case FCVTZU_ws:
+    case FCVTZU_wd:
+    case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
+    case FCVTZS_xd:
+    case FCVTZS_wd:
+    case FCVTZS_xs:
+    case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
+    case SCVTF_sw:
+    case SCVTF_sx:
+    case SCVTF_dw:
+    case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
+    case UCVTF_sw:
+    case UCVTF_sx:
+    case UCVTF_dw:
+    case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
+  const char *mnemonic = "";
+  const char *form = "'Rd, 'Fn, 'IFPFBits";
+  const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
+
+  switch (instr->Mask(FPFixedPointConvertMask)) {
+    case FCVTZS_ws_fixed:
+    case FCVTZS_xs_fixed:
+    case FCVTZS_wd_fixed:
+    case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
+    case FCVTZU_ws_fixed:
+    case FCVTZU_xs_fixed:
+    case FCVTZU_wd_fixed:
+    case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
+    case SCVTF_sw_fixed:
+    case SCVTF_sx_fixed:
+    case SCVTF_dw_fixed:
+    case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
+    case UCVTF_sw_fixed:
+    case UCVTF_sx_fixed:
+    case UCVTF_dw_fixed:
+    case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitSystem(Instruction* instr) {
+  // Some system instructions hijack their Op and Cp fields to represent a
+  // range of immediates instead of indicating a different instruction. This
+  // makes the decoding tricky.
+  const char *mnemonic = "unimplemented";
+  const char *form = "(System)";
+
+  if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
+    switch (instr->Mask(SystemSysRegMask)) {
+      case MRS: {
+        mnemonic = "mrs";
+        switch (instr->ImmSystemRegister()) {
+          case NZCV: form = "'Xt, nzcv"; break;
+          case FPCR: form = "'Xt, fpcr"; break;
+          default: form = "'Xt, (unknown)"; break;
+        }
+        break;
+      }
+      case MSR: {
+        mnemonic = "msr";
+        switch (instr->ImmSystemRegister()) {
+          case NZCV: form = "nzcv, 'Xt"; break;
+          case FPCR: form = "fpcr, 'Xt"; break;
+          default: form = "(unknown), 'Xt"; break;
+        }
+        break;
+      }
+    }
+  } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
+    DCHECK(instr->Mask(SystemHintMask) == HINT);
+    switch (instr->ImmHint()) {
+      case NOP: {
+        mnemonic = "nop";
+        form = NULL;
+        break;
+      }
+    }
+  } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
+    switch (instr->Mask(MemBarrierMask)) {
+      case DMB: {
+        mnemonic = "dmb";
+        form = "'M";
+        break;
+      }
+      case DSB: {
+        mnemonic = "dsb";
+        form = "'M";
+        break;
+      }
+      case ISB: {
+        mnemonic = "isb";
+        form = NULL;
+        break;
+      }
+    }
+  }
+
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitException(Instruction* instr) {
+  const char *mnemonic = "unimplemented";
+  const char *form = "'IDebug";
+
+  switch (instr->Mask(ExceptionMask)) {
+    case HLT: mnemonic = "hlt"; break;
+    case BRK: mnemonic = "brk"; break;
+    case SVC: mnemonic = "svc"; break;
+    case HVC: mnemonic = "hvc"; break;
+    case SMC: mnemonic = "smc"; break;
+    case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
+    case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
+    case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
+    default: form = "(Exception)";
+  }
+  Format(instr, mnemonic, form);
+}
+
+
+void Disassembler::VisitUnimplemented(Instruction* instr) {
+  Format(instr, "unimplemented", "(Unimplemented)");
+}
+
+
+void Disassembler::VisitUnallocated(Instruction* instr) {
+  Format(instr, "unallocated", "(Unallocated)");
+}
+
+
+void Disassembler::ProcessOutput(Instruction* /*instr*/) {
+  // The base disasm does nothing more than disassembling into a buffer.
+}
+
+
+void Disassembler::Format(Instruction* instr, const char* mnemonic,
+                          const char* format) {
+  // TODO(mcapewel) don't think I can use the instr address here - there needs
+  //                to be a base address too
+  DCHECK(mnemonic != NULL);
+  ResetOutput();
+  Substitute(instr, mnemonic);
+  if (format != NULL) {
+    buffer_[buffer_pos_++] = ' ';
+    Substitute(instr, format);
+  }
+  buffer_[buffer_pos_] = 0;
+  ProcessOutput(instr);
+}
+
+
+void Disassembler::Substitute(Instruction* instr, const char* string) {
+  char chr = *string++;
+  while (chr != '\0') {
+    if (chr == '\'') {
+      string += SubstituteField(instr, string);
+    } else {
+      buffer_[buffer_pos_++] = chr;
+    }
+    chr = *string++;
+  }
+}
+
+
+int Disassembler::SubstituteField(Instruction* instr, const char* format) {
+  switch (format[0]) {
+    case 'R':  // Register. X or W, selected by sf bit.
+    case 'F':  // FP Register. S or D, selected by type field.
+    case 'W':
+    case 'X':
+    case 'S':
+    case 'D': return SubstituteRegisterField(instr, format);
+    case 'I': return SubstituteImmediateField(instr, format);
+    case 'L': return SubstituteLiteralField(instr, format);
+    case 'H': return SubstituteShiftField(instr, format);
+    case 'P': return SubstitutePrefetchField(instr, format);
+    case 'C': return SubstituteConditionField(instr, format);
+    case 'E': return SubstituteExtendField(instr, format);
+    case 'A': return SubstitutePCRelAddressField(instr, format);
+    case 'B': return SubstituteBranchTargetField(instr, format);
+    case 'O': return SubstituteLSRegOffsetField(instr, format);
+    case 'M': return SubstituteBarrierField(instr, format);
+    default: {
+      UNREACHABLE();
+      return 1;
+    }
+  }
+}
+
+
+int Disassembler::SubstituteRegisterField(Instruction* instr,
+                                          const char* format) {
+  unsigned reg_num = 0;
+  unsigned field_len = 2;
+  switch (format[1]) {
+    case 'd': reg_num = instr->Rd(); break;
+    case 'n': reg_num = instr->Rn(); break;
+    case 'm': reg_num = instr->Rm(); break;
+    case 'a': reg_num = instr->Ra(); break;
+    case 't': {
+      if (format[2] == '2') {
+        reg_num = instr->Rt2();
+        field_len = 3;
+      } else {
+        reg_num = instr->Rt();
+      }
+      break;
+    }
+    default: UNREACHABLE();
+  }
+
+  // Increase field length for registers tagged as stack.
+  if (format[2] == 's') {
+    field_len = 3;
+  }
+
+  char reg_type;
+  if (format[0] == 'R') {
+    // Register type is R: use sf bit to choose X and W.
+    reg_type = instr->SixtyFourBits() ? 'x' : 'w';
+  } else if (format[0] == 'F') {
+    // Floating-point register: use type field to choose S or D.
+    reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
+  } else {
+    // Register type is specified. Make it lower case.
+    reg_type = format[0] + 0x20;
+  }
+
+  if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
+    // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
+
+    // Filter special registers
+    if ((reg_type == 'x') && (reg_num == 27)) {
+      AppendToOutput("cp");
+    } else if ((reg_type == 'x') && (reg_num == 28)) {
+      AppendToOutput("jssp");
+    } else if ((reg_type == 'x') && (reg_num == 29)) {
+      AppendToOutput("fp");
+    } else if ((reg_type == 'x') && (reg_num == 30)) {
+      AppendToOutput("lr");
+    } else {
+      AppendToOutput("%c%d", reg_type, reg_num);
+    }
+  } else if (format[2] == 's') {
+    // Disassemble w31/x31 as stack pointer wcsp/csp.
+    AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp");
+  } else {
+    // Disassemble w31/x31 as zero register wzr/xzr.
+    AppendToOutput("%czr", reg_type);
+  }
+
+  return field_len;
+}
+
+
+int Disassembler::SubstituteImmediateField(Instruction* instr,
+                                           const char* format) {
+  DCHECK(format[0] == 'I');
+
+  switch (format[1]) {
+    case 'M': {  // IMoveImm or IMoveLSL.
+      if (format[5] == 'I') {
+        uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
+        AppendToOutput("#0x%" PRIx64, imm);
+      } else {
+        DCHECK(format[5] == 'L');
+        AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
+        if (instr->ShiftMoveWide() > 0) {
+          AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
+        }
+      }
+      return 8;
+    }
+    case 'L': {
+      switch (format[2]) {
+        case 'L': {  // ILLiteral - Immediate Load Literal.
+          AppendToOutput("pc%+" PRId64,
+                         instr->ImmLLiteral() << kLoadLiteralScaleLog2);
+          return 9;
+        }
+        case 'S': {  // ILS - Immediate Load/Store.
+          if (instr->ImmLS() != 0) {
+            AppendToOutput(", #%" PRId64, instr->ImmLS());
+          }
+          return 3;
+        }
+        case 'P': {  // ILPx - Immediate Load/Store Pair, x = access size.
+          if (instr->ImmLSPair() != 0) {
+            // format[3] is the scale value. Convert to a number.
+            int scale = format[3] - 0x30;
+            AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
+          }
+          return 4;
+        }
+        case 'U': {  // ILU - Immediate Load/Store Unsigned.
+          if (instr->ImmLSUnsigned() != 0) {
+            AppendToOutput(", #%" PRIu64,
+                           instr->ImmLSUnsigned() << instr->SizeLS());
+          }
+          return 3;
+        }
+      }
+    }
+    case 'C': {  // ICondB - Immediate Conditional Branch.
+      int64_t offset = instr->ImmCondBranch() << 2;
+      char sign = (offset >= 0) ? '+' : '-';
+      AppendToOutput("#%c0x%" PRIx64, sign, offset);
+      return 6;
+    }
+    case 'A': {  // IAddSub.
+      DCHECK(instr->ShiftAddSub() <= 1);
+      int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
+      AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
+      return 7;
+    }
+    case 'F': {  // IFPSingle, IFPDouble or IFPFBits.
+      if (format[3] == 'F') {  // IFPFBits.
+        AppendToOutput("#%d", 64 - instr->FPScale());
+        return 8;
+      } else {
+        AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
+                       format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
+        return 9;
+      }
+    }
+    case 'T': {  // ITri - Immediate Triangular Encoded.
+      AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
+      return 4;
+    }
+    case 'N': {  // INzcv.
+      int nzcv = (instr->Nzcv() << Flags_offset);
+      AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
+                                  ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
+                                  ((nzcv & CFlag) == 0) ? 'c' : 'C',
+                                  ((nzcv & VFlag) == 0) ? 'v' : 'V');
+      return 5;
+    }
+    case 'P': {  // IP - Conditional compare.
+      AppendToOutput("#%d", instr->ImmCondCmp());
+      return 2;
+    }
+    case 'B': {  // Bitfields.
+      return SubstituteBitfieldImmediateField(instr, format);
+    }
+    case 'E': {  // IExtract.
+      AppendToOutput("#%d", instr->ImmS());
+      return 8;
+    }
+    case 'S': {  // IS - Test and branch bit.
+      AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
+                            instr->ImmTestBranchBit40());
+      return 2;
+    }
+    case 'D': {  // IDebug - HLT and BRK instructions.
+      AppendToOutput("#0x%x", instr->ImmException());
+      return 6;
+    }
+    default: {
+      UNREACHABLE();
+      return 0;
+    }
+  }
+}
+
+
+int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
+                                                   const char* format) {
+  DCHECK((format[0] == 'I') && (format[1] == 'B'));
+  unsigned r = instr->ImmR();
+  unsigned s = instr->ImmS();
+
+  switch (format[2]) {
+    case 'r': {  // IBr.
+      AppendToOutput("#%d", r);
+      return 3;
+    }
+    case 's': {  // IBs+1 or IBs-r+1.
+      if (format[3] == '+') {
+        AppendToOutput("#%d", s + 1);
+        return 5;
+      } else {
+        DCHECK(format[3] == '-');
+        AppendToOutput("#%d", s - r + 1);
+        return 7;
+      }
+    }
+    case 'Z': {  // IBZ-r.
+      DCHECK((format[3] == '-') && (format[4] == 'r'));
+      unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits
+                                                        : kWRegSizeInBits;
+      AppendToOutput("#%d", reg_size - r);
+      return 5;
+    }
+    default: {
+      UNREACHABLE();
+      return 0;
+    }
+  }
+}
+
+
+int Disassembler::SubstituteLiteralField(Instruction* instr,
+                                         const char* format) {
+  DCHECK(strncmp(format, "LValue", 6) == 0);
+  USE(format);
+
+  switch (instr->Mask(LoadLiteralMask)) {
+    case LDR_w_lit:
+    case LDR_x_lit:
+    case LDR_s_lit:
+    case LDR_d_lit:
+      AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
+      break;
+    default: UNREACHABLE();
+  }
+
+  return 6;
+}
+
+
+int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
+  DCHECK(format[0] == 'H');
+  DCHECK(instr->ShiftDP() <= 0x3);
+
+  switch (format[1]) {
+    case 'D': {  // HDP.
+      DCHECK(instr->ShiftDP() != ROR);
+    }  // Fall through.
+    case 'L': {  // HLo.
+      if (instr->ImmDPShift() != 0) {
+        const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
+        AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
+                       instr->ImmDPShift());
+      }
+      return 3;
+    }
+    default:
+      UNREACHABLE();
+      return 0;
+  }
+}
+
+
+int Disassembler::SubstituteConditionField(Instruction* instr,
+                                           const char* format) {
+  DCHECK(format[0] == 'C');
+  const char* condition_code[] = { "eq", "ne", "hs", "lo",
+                                   "mi", "pl", "vs", "vc",
+                                   "hi", "ls", "ge", "lt",
+                                   "gt", "le", "al", "nv" };
+  int cond;
+  switch (format[1]) {
+    case 'B': cond = instr->ConditionBranch(); break;
+    case 'I': {
+      cond = NegateCondition(static_cast<Condition>(instr->Condition()));
+      break;
+    }
+    default: cond = instr->Condition();
+  }
+  AppendToOutput("%s", condition_code[cond]);
+  return 4;
+}
+
+
+int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
+                                              const char* format) {
+  USE(format);
+  DCHECK(strncmp(format, "AddrPCRel", 9) == 0);
+
+  int offset = instr->ImmPCRel();
+
+  // Only ADR (AddrPCRelByte) is supported.
+  DCHECK(strcmp(format, "AddrPCRelByte") == 0);
+
+  char sign = '+';
+  if (offset < 0) {
+    offset = -offset;
+    sign = '-';
+  }
+  AppendToOutput("#%c0x%x (addr %p)", sign, offset,
+                 instr->InstructionAtOffset(offset, Instruction::NO_CHECK));
+  return 13;
+}
+
+
+int Disassembler::SubstituteBranchTargetField(Instruction* instr,
+                                              const char* format) {
+  DCHECK(strncmp(format, "BImm", 4) == 0);
+
+  int64_t offset = 0;
+  switch (format[5]) {
+    // BImmUncn - unconditional branch immediate.
+    case 'n': offset = instr->ImmUncondBranch(); break;
+    // BImmCond - conditional branch immediate.
+    case 'o': offset = instr->ImmCondBranch(); break;
+    // BImmCmpa - compare and branch immediate.
+    case 'm': offset = instr->ImmCmpBranch(); break;
+    // BImmTest - test and branch immediate.
+    case 'e': offset = instr->ImmTestBranch(); break;
+    default: UNREACHABLE();
+  }
+  offset <<= kInstructionSizeLog2;
+  char sign = '+';
+  if (offset < 0) {
+    sign = '-';
+  }
+  AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset),
+                 instr->InstructionAtOffset(offset), Instruction::NO_CHECK);
+  return 8;
+}
+
+
+int Disassembler::SubstituteExtendField(Instruction* instr,
+                                        const char* format) {
+  DCHECK(strncmp(format, "Ext", 3) == 0);
+  DCHECK(instr->ExtendMode() <= 7);
+  USE(format);
+
+  const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
+                                "sxtb", "sxth", "sxtw", "sxtx" };
+
+  // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
+  // registers becomes lsl.
+  if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
+      (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
+       (instr->ExtendMode() == UXTX))) {
+    if (instr->ImmExtendShift() > 0) {
+      AppendToOutput(", lsl #%d", instr->ImmExtendShift());
+    }
+  } else {
+    AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
+    if (instr->ImmExtendShift() > 0) {
+      AppendToOutput(" #%d", instr->ImmExtendShift());
+    }
+  }
+  return 3;
+}
+
+
+int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
+                                             const char* format) {
+  DCHECK(strncmp(format, "Offsetreg", 9) == 0);
+  const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
+                                "undefined", "undefined", "sxtw", "sxtx" };
+  USE(format);
+
+  unsigned shift = instr->ImmShiftLS();
+  Extend ext = static_cast<Extend>(instr->ExtendMode());
+  char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
+
+  unsigned rm = instr->Rm();
+  if (rm == kZeroRegCode) {
+    AppendToOutput("%czr", reg_type);
+  } else {
+    AppendToOutput("%c%d", reg_type, rm);
+  }
+
+  // Extend mode UXTX is an alias for shift mode LSL here.
+  if (!((ext == UXTX) && (shift == 0))) {
+    AppendToOutput(", %s", extend_mode[ext]);
+    if (shift != 0) {
+      AppendToOutput(" #%d", instr->SizeLS());
+    }
+  }
+  return 9;
+}
+
+
+int Disassembler::SubstitutePrefetchField(Instruction* instr,
+                                          const char* format) {
+  DCHECK(format[0] == 'P');
+  USE(format);
+
+  int prefetch_mode = instr->PrefetchMode();
+
+  const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
+  int level = (prefetch_mode >> 1) + 1;
+  const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
+
+  AppendToOutput("p%sl%d%s", ls, level, ks);
+  return 6;
+}
+
+int Disassembler::SubstituteBarrierField(Instruction* instr,
+                                         const char* format) {
+  DCHECK(format[0] == 'M');
+  USE(format);
+
+  static const char* options[4][4] = {
+    { "sy (0b0000)", "oshld", "oshst", "osh" },
+    { "sy (0b0100)", "nshld", "nshst", "nsh" },
+    { "sy (0b1000)", "ishld", "ishst", "ish" },
+    { "sy (0b1100)", "ld", "st", "sy" }
+  };
+  int domain = instr->ImmBarrierDomain();
+  int type = instr->ImmBarrierType();
+
+  AppendToOutput("%s", options[domain][type]);
+  return 1;
+}
+
+
+void Disassembler::ResetOutput() {
+  buffer_pos_ = 0;
+  buffer_[buffer_pos_] = 0;
+}
+
+
+void Disassembler::AppendToOutput(const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
+  va_end(args);
+}
+
+
+void PrintDisassembler::ProcessOutput(Instruction* instr) {
+  fprintf(stream_, "0x%016" PRIx64 "  %08" PRIx32 "\t\t%s\n",
+          reinterpret_cast<uint64_t>(instr), instr->InstructionBits(),
+          GetOutput());
+}
+
+} }  // namespace v8::internal
+
+
+namespace disasm {
+
+
+const char* NameConverter::NameOfAddress(byte* addr) const {
+  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
+  return tmp_buffer_.start();
+}
+
+
+const char* NameConverter::NameOfConstant(byte* addr) const {
+  return NameOfAddress(addr);
+}
+
+
+const char* NameConverter::NameOfCPURegister(int reg) const {
+  unsigned ureg = reg;  // Avoid warnings about signed/unsigned comparisons.
+  if (ureg >= v8::internal::kNumberOfRegisters) {
+    return "noreg";
+  }
+  if (ureg == v8::internal::kZeroRegCode) {
+    return "xzr";
+  }
+  v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg);
+  return tmp_buffer_.start();
+}
+
+
+const char* NameConverter::NameOfByteCPURegister(int reg) const {
+  UNREACHABLE();  // ARM64 does not have the concept of a byte register
+  return "nobytereg";
+}
+
+
+const char* NameConverter::NameOfXMMRegister(int reg) const {
+  UNREACHABLE();  // ARM64 does not have any XMM registers
+  return "noxmmreg";
+}
+
+
+const char* NameConverter::NameInCode(byte* addr) const {
+  // The default name converter is called for unknown code, so we will not try
+  // to access any memory.
+  return "";
+}
+
+
+//------------------------------------------------------------------------------
+
+class BufferDisassembler : public v8::internal::Disassembler {
+ public:
+  explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
+      : out_buffer_(out_buffer) { }
+
+  ~BufferDisassembler() { }
+
+  virtual void ProcessOutput(v8::internal::Instruction* instr) {
+    v8::internal::SNPrintF(out_buffer_, "%s", GetOutput());
+  }
+
+ private:
+  v8::internal::Vector<char> out_buffer_;
+};
+
+Disassembler::Disassembler(const NameConverter& converter)
+    : converter_(converter) {}
+
+
+Disassembler::~Disassembler() { USE(converter_); }
+
+
+int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
+                                    byte* instr) {
+  v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
+  BufferDisassembler disasm(buffer);
+  decoder.AppendVisitor(&disasm);
+
+  decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr));
+  return v8::internal::kInstructionSize;
+}
+
+
+int Disassembler::ConstantPoolSizeAt(byte* instr) {
+  return v8::internal::Assembler::ConstantPoolSizeAt(
+      reinterpret_cast<v8::internal::Instruction*>(instr));
+}
+
+
+void Disassembler::Disassemble(FILE* file, byte* start, byte* end) {
+  v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder;
+  v8::internal::PrintDisassembler disasm(file);
+  decoder.AppendVisitor(&disasm);
+
+  for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) {
+    decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc));
+  }
+}
+
+}  // namespace disasm
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/disasm-arm64.h b/src/arm64/disasm-arm64.h
new file mode 100644
index 0000000..8cd3b80
--- /dev/null
+++ b/src/arm64/disasm-arm64.h
@@ -0,0 +1,92 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_DISASM_ARM64_H
+#define V8_ARM64_DISASM_ARM64_H
+
+#include "src/v8.h"
+
+#include "src/arm64/decoder-arm64.h"
+#include "src/arm64/instructions-arm64.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+
+class Disassembler: public DecoderVisitor {
+ public:
+  Disassembler();
+  Disassembler(char* text_buffer, int buffer_size);
+  virtual ~Disassembler();
+  char* GetOutput();
+
+  // Declare all Visitor functions.
+  #define DECLARE(A)  void Visit##A(Instruction* instr);
+  VISITOR_LIST(DECLARE)
+  #undef DECLARE
+
+ protected:
+  virtual void ProcessOutput(Instruction* instr);
+
+  void Format(Instruction* instr, const char* mnemonic, const char* format);
+  void Substitute(Instruction* instr, const char* string);
+  int SubstituteField(Instruction* instr, const char* format);
+  int SubstituteRegisterField(Instruction* instr, const char* format);
+  int SubstituteImmediateField(Instruction* instr, const char* format);
+  int SubstituteLiteralField(Instruction* instr, const char* format);
+  int SubstituteBitfieldImmediateField(Instruction* instr, const char* format);
+  int SubstituteShiftField(Instruction* instr, const char* format);
+  int SubstituteExtendField(Instruction* instr, const char* format);
+  int SubstituteConditionField(Instruction* instr, const char* format);
+  int SubstitutePCRelAddressField(Instruction* instr, const char* format);
+  int SubstituteBranchTargetField(Instruction* instr, const char* format);
+  int SubstituteLSRegOffsetField(Instruction* instr, const char* format);
+  int SubstitutePrefetchField(Instruction* instr, const char* format);
+  int SubstituteBarrierField(Instruction* instr, const char* format);
+
+  bool RdIsZROrSP(Instruction* instr) const {
+    return (instr->Rd() == kZeroRegCode);
+  }
+
+  bool RnIsZROrSP(Instruction* instr) const {
+    return (instr->Rn() == kZeroRegCode);
+  }
+
+  bool RmIsZROrSP(Instruction* instr) const {
+    return (instr->Rm() == kZeroRegCode);
+  }
+
+  bool RaIsZROrSP(Instruction* instr) const {
+    return (instr->Ra() == kZeroRegCode);
+  }
+
+  bool IsMovzMovnImm(unsigned reg_size, uint64_t value);
+
+  void ResetOutput();
+  void AppendToOutput(const char* string, ...);
+
+  char* buffer_;
+  uint32_t buffer_pos_;
+  uint32_t buffer_size_;
+  bool own_buffer_;
+};
+
+
+class PrintDisassembler: public Disassembler {
+ public:
+  explicit PrintDisassembler(FILE* stream) : stream_(stream) { }
+  ~PrintDisassembler() { }
+
+  virtual void ProcessOutput(Instruction* instr);
+
+ private:
+  FILE *stream_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_DISASM_ARM64_H
diff --git a/src/arm64/frames-arm64.cc b/src/arm64/frames-arm64.cc
new file mode 100644
index 0000000..b3633e0
--- /dev/null
+++ b/src/arm64/frames-arm64.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/arm64/assembler-arm64.h"
+#include "src/assembler.h"
+#include "src/frames.h"
+
+namespace v8 {
+namespace internal {
+
+
+Register JavaScriptFrame::fp_register() { return v8::internal::fp; }
+Register JavaScriptFrame::context_register() { return cp; }
+Register JavaScriptFrame::constant_pool_pointer_register() {
+  UNREACHABLE();
+  return no_reg;
+}
+
+
+Register StubFailureTrampolineFrame::fp_register() { return v8::internal::fp; }
+Register StubFailureTrampolineFrame::context_register() { return cp; }
+Register StubFailureTrampolineFrame::constant_pool_pointer_register() {
+  UNREACHABLE();
+  return no_reg;
+}
+
+
+Object*& ExitFrame::constant_pool_slot() const {
+  UNREACHABLE();
+  return Memory::Object_at(NULL);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/frames-arm64.h b/src/arm64/frames-arm64.h
new file mode 100644
index 0000000..8d4ce86
--- /dev/null
+++ b/src/arm64/frames-arm64.h
@@ -0,0 +1,109 @@
+// Copyright 2013 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/arm64/assembler-arm64.h"
+#include "src/arm64/constants-arm64.h"
+
+#ifndef V8_ARM64_FRAMES_ARM64_H_
+#define V8_ARM64_FRAMES_ARM64_H_
+
+namespace v8 {
+namespace internal {
+
+const int kNumRegs = kNumberOfRegisters;
+// Registers x0-x17 are caller-saved.
+const int kNumJSCallerSaved = 18;
+const RegList kJSCallerSaved = 0x3ffff;
+
+// Number of registers for which space is reserved in safepoints. Must be a
+// multiple of eight.
+// TODO(all): Refine this number.
+const int kNumSafepointRegisters = 32;
+
+// Define the list of registers actually saved at safepoints.
+// Note that the number of saved registers may be smaller than the reserved
+// space, i.e. kNumSafepointSavedRegisters <= kNumSafepointRegisters.
+#define kSafepointSavedRegisters CPURegList::GetSafepointSavedRegisters().list()
+#define kNumSafepointSavedRegisters \
+  CPURegList::GetSafepointSavedRegisters().Count();
+
+class EntryFrameConstants : public AllStatic {
+ public:
+  static const int kCallerFPOffset =
+      -(StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
+};
+
+
+class ExitFrameConstants : public AllStatic {
+ public:
+  static const int kFrameSize            =  2 * kPointerSize;
+
+  static const int kCallerSPDisplacement =  2 * kPointerSize;
+  static const int kCallerPCOffset       =  1 * kPointerSize;
+  static const int kCallerFPOffset       =  0 * kPointerSize;   // <- fp
+  static const int kSPOffset             = -1 * kPointerSize;
+  static const int kCodeOffset           = -2 * kPointerSize;
+  static const int kLastExitFrameField   = kCodeOffset;
+
+  static const int kConstantPoolOffset   = 0;  // Not used
+};
+
+
+class JavaScriptFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLocal0Offset = StandardFrameConstants::kExpressionsOffset;
+
+  // There are two words on the stack (saved fp and saved lr) between fp and
+  // the arguments.
+  static const int kLastParameterOffset = 2 * kPointerSize;
+
+  static const int kFunctionOffset = StandardFrameConstants::kMarkerOffset;
+};
+
+
+class ArgumentsAdaptorFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kLengthOffset = StandardFrameConstants::kExpressionsOffset;
+
+  static const int kFrameSize =
+      StandardFrameConstants::kFixedFrameSize + kPointerSize;
+};
+
+
+class ConstructFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+  static const int kLengthOffset           = -4 * kPointerSize;
+  static const int kConstructorOffset      = -5 * kPointerSize;
+  static const int kImplicitReceiverOffset = -6 * kPointerSize;
+
+  static const int kFrameSize =
+      StandardFrameConstants::kFixedFrameSize + 4 * kPointerSize;
+};
+
+
+class InternalFrameConstants : public AllStatic {
+ public:
+  // FP-relative.
+  static const int kCodeOffset = StandardFrameConstants::kExpressionsOffset;
+};
+
+
+inline Object* JavaScriptFrame::function_slot_object() const {
+  const int offset = JavaScriptFrameConstants::kFunctionOffset;
+  return Memory::Object_at(fp() + offset);
+}
+
+
+inline void StackHandler::SetFp(Address slot, Address fp) {
+  Memory::Address_at(slot) = fp;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_FRAMES_ARM64_H_
diff --git a/src/arm64/full-codegen-arm64.cc b/src/arm64/full-codegen-arm64.cc
new file mode 100644
index 0000000..25a9efd
--- /dev/null
+++ b/src/arm64/full-codegen-arm64.cc
@@ -0,0 +1,5006 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/code-factory.h"
+#include "src/code-stubs.h"
+#include "src/codegen.h"
+#include "src/compiler.h"
+#include "src/debug.h"
+#include "src/full-codegen.h"
+#include "src/ic/ic.h"
+#include "src/isolate-inl.h"
+#include "src/parser.h"
+#include "src/scopes.h"
+
+#include "src/arm64/code-stubs-arm64.h"
+#include "src/arm64/macro-assembler-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM(masm_)
+
+class JumpPatchSite BASE_EMBEDDED {
+ public:
+  explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm), reg_(NoReg) {
+#ifdef DEBUG
+    info_emitted_ = false;
+#endif
+  }
+
+  ~JumpPatchSite() {
+    if (patch_site_.is_bound()) {
+      DCHECK(info_emitted_);
+    } else {
+      DCHECK(reg_.IsNone());
+    }
+  }
+
+  void EmitJumpIfNotSmi(Register reg, Label* target) {
+    // This code will be patched by PatchInlinedSmiCode, in ic-arm64.cc.
+    InstructionAccurateScope scope(masm_, 1);
+    DCHECK(!info_emitted_);
+    DCHECK(reg.Is64Bits());
+    DCHECK(!reg.Is(csp));
+    reg_ = reg;
+    __ bind(&patch_site_);
+    __ tbz(xzr, 0, target);   // Always taken before patched.
+  }
+
+  void EmitJumpIfSmi(Register reg, Label* target) {
+    // This code will be patched by PatchInlinedSmiCode, in ic-arm64.cc.
+    InstructionAccurateScope scope(masm_, 1);
+    DCHECK(!info_emitted_);
+    DCHECK(reg.Is64Bits());
+    DCHECK(!reg.Is(csp));
+    reg_ = reg;
+    __ bind(&patch_site_);
+    __ tbnz(xzr, 0, target);  // Never taken before patched.
+  }
+
+  void EmitJumpIfEitherNotSmi(Register reg1, Register reg2, Label* target) {
+    UseScratchRegisterScope temps(masm_);
+    Register temp = temps.AcquireX();
+    __ Orr(temp, reg1, reg2);
+    EmitJumpIfNotSmi(temp, target);
+  }
+
+  void EmitPatchInfo() {
+    Assembler::BlockPoolsScope scope(masm_);
+    InlineSmiCheckInfo::Emit(masm_, reg_, &patch_site_);
+#ifdef DEBUG
+    info_emitted_ = true;
+#endif
+  }
+
+ private:
+  MacroAssembler* masm_;
+  Label patch_site_;
+  Register reg_;
+#ifdef DEBUG
+  bool info_emitted_;
+#endif
+};
+
+
+// Generate code for a JS function. On entry to the function the receiver
+// and arguments have been pushed on the stack left to right. The actual
+// argument count matches the formal parameter count expected by the
+// function.
+//
+// The live registers are:
+//   - x1: the JS function object being called (i.e. ourselves).
+//   - cp: our context.
+//   - fp: our caller's frame pointer.
+//   - jssp: stack pointer.
+//   - lr: return address.
+//
+// The function builds a JS frame. See JavaScriptFrameConstants in
+// frames-arm.h for its layout.
+void FullCodeGenerator::Generate() {
+  CompilationInfo* info = info_;
+  handler_table_ =
+      isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
+
+  profiling_counter_ = isolate()->factory()->NewCell(
+      Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
+  SetFunctionPosition(function());
+  Comment cmnt(masm_, "[ Function compiled by full code generator");
+
+  ProfileEntryHookStub::MaybeCallEntryHook(masm_);
+
+#ifdef DEBUG
+  if (strlen(FLAG_stop_at) > 0 &&
+      info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
+    __ Debug("stop-at", __LINE__, BREAK);
+  }
+#endif
+
+  // Sloppy mode functions and builtins need to replace the receiver with the
+  // global proxy when called as functions (without an explicit receiver
+  // object).
+  if (info->strict_mode() == SLOPPY && !info->is_native()) {
+    Label ok;
+    int receiver_offset = info->scope()->num_parameters() * kXRegSize;
+    __ Peek(x10, receiver_offset);
+    __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
+
+    __ Ldr(x10, GlobalObjectMemOperand());
+    __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
+    __ Poke(x10, receiver_offset);
+
+    __ Bind(&ok);
+  }
+
+
+  // Open a frame scope to indicate that there is a frame on the stack.
+  // The MANUAL indicates that the scope shouldn't actually generate code
+  // to set up the frame because we do it manually below.
+  FrameScope frame_scope(masm_, StackFrame::MANUAL);
+
+  // This call emits the following sequence in a way that can be patched for
+  // code ageing support:
+  //  Push(lr, fp, cp, x1);
+  //  Add(fp, jssp, 2 * kPointerSize);
+  info->set_prologue_offset(masm_->pc_offset());
+  __ Prologue(info->IsCodePreAgingActive());
+  info->AddNoFrameRange(0, masm_->pc_offset());
+
+  // Reserve space on the stack for locals.
+  { Comment cmnt(masm_, "[ Allocate locals");
+    int locals_count = info->scope()->num_stack_slots();
+    // Generators allocate locals, if any, in context slots.
+    DCHECK(!info->function()->is_generator() || locals_count == 0);
+
+    if (locals_count > 0) {
+      if (locals_count >= 128) {
+        Label ok;
+        DCHECK(jssp.Is(__ StackPointer()));
+        __ Sub(x10, jssp, locals_count * kPointerSize);
+        __ CompareRoot(x10, Heap::kRealStackLimitRootIndex);
+        __ B(hs, &ok);
+        __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
+        __ Bind(&ok);
+      }
+      __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
+      if (FLAG_optimize_for_size) {
+        __ PushMultipleTimes(x10 , locals_count);
+      } else {
+        const int kMaxPushes = 32;
+        if (locals_count >= kMaxPushes) {
+          int loop_iterations = locals_count / kMaxPushes;
+          __ Mov(x3, loop_iterations);
+          Label loop_header;
+          __ Bind(&loop_header);
+          // Do pushes.
+          __ PushMultipleTimes(x10 , kMaxPushes);
+          __ Subs(x3, x3, 1);
+          __ B(ne, &loop_header);
+        }
+        int remaining = locals_count % kMaxPushes;
+        // Emit the remaining pushes.
+        __ PushMultipleTimes(x10 , remaining);
+      }
+    }
+  }
+
+  bool function_in_register_x1 = true;
+
+  int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+  if (heap_slots > 0) {
+    // Argument to NewContext is the function, which is still in x1.
+    Comment cmnt(masm_, "[ Allocate context");
+    bool need_write_barrier = true;
+    if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
+      __ Mov(x10, Operand(info->scope()->GetScopeInfo()));
+      __ Push(x1, x10);
+      __ CallRuntime(Runtime::kNewGlobalContext, 2);
+    } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), heap_slots);
+      __ CallStub(&stub);
+      // Result of FastNewContextStub is always in new space.
+      need_write_barrier = false;
+    } else {
+      __ Push(x1);
+      __ CallRuntime(Runtime::kNewFunctionContext, 1);
+    }
+    function_in_register_x1 = false;
+    // Context is returned in x0.  It replaces the context passed to us.
+    // It's saved in the stack and kept live in cp.
+    __ Mov(cp, x0);
+    __ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    int num_parameters = info->scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Variable* var = scope()->parameter(i);
+      if (var->IsContextSlot()) {
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+            (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ Ldr(x10, MemOperand(fp, parameter_offset));
+        // Store it in the context.
+        MemOperand target = ContextMemOperand(cp, var->index());
+        __ Str(x10, target);
+
+        // Update the write barrier.
+        if (need_write_barrier) {
+          __ RecordWriteContextSlot(
+              cp, target.offset(), x10, x11, kLRHasBeenSaved, kDontSaveFPRegs);
+        } else if (FLAG_debug_code) {
+          Label done;
+          __ JumpIfInNewSpace(cp, &done);
+          __ Abort(kExpectedNewSpaceObject);
+          __ bind(&done);
+        }
+      }
+    }
+  }
+
+  Variable* arguments = scope()->arguments();
+  if (arguments != NULL) {
+    // Function uses arguments object.
+    Comment cmnt(masm_, "[ Allocate arguments object");
+    if (!function_in_register_x1) {
+      // Load this again, if it's used by the local context below.
+      __ Ldr(x3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+    } else {
+      __ Mov(x3, x1);
+    }
+    // Receiver is just before the parameters on the caller's stack.
+    int num_parameters = info->scope()->num_parameters();
+    int offset = num_parameters * kPointerSize;
+    __ Add(x2, fp, StandardFrameConstants::kCallerSPOffset + offset);
+    __ Mov(x1, Smi::FromInt(num_parameters));
+    __ Push(x3, x2, x1);
+
+    // Arguments to ArgumentsAccessStub:
+    //   function, receiver address, parameter count.
+    // The stub will rewrite receiver and parameter count if the previous
+    // stack frame was an arguments adapter frame.
+    ArgumentsAccessStub::Type type;
+    if (strict_mode() == STRICT) {
+      type = ArgumentsAccessStub::NEW_STRICT;
+    } else if (function()->has_duplicate_parameters()) {
+      type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
+    } else {
+      type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
+    }
+    ArgumentsAccessStub stub(isolate(), type);
+    __ CallStub(&stub);
+
+    SetVar(arguments, x0, x1, x2);
+  }
+
+  if (FLAG_trace) {
+    __ CallRuntime(Runtime::kTraceEnter, 0);
+  }
+
+
+  // Visit the declarations and body unless there is an illegal
+  // redeclaration.
+  if (scope()->HasIllegalRedeclaration()) {
+    Comment cmnt(masm_, "[ Declarations");
+    scope()->VisitIllegalRedeclaration(this);
+
+  } else {
+    PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
+    { Comment cmnt(masm_, "[ Declarations");
+      if (scope()->is_function_scope() && scope()->function() != NULL) {
+        VariableDeclaration* function = scope()->function();
+        DCHECK(function->proxy()->var()->mode() == CONST ||
+               function->proxy()->var()->mode() == CONST_LEGACY);
+        DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
+        VisitVariableDeclaration(function);
+      }
+      VisitDeclarations(scope()->declarations());
+    }
+  }
+
+  { Comment cmnt(masm_, "[ Stack check");
+    PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
+    Label ok;
+    DCHECK(jssp.Is(__ StackPointer()));
+    __ CompareRoot(jssp, Heap::kStackLimitRootIndex);
+    __ B(hs, &ok);
+    PredictableCodeSizeScope predictable(masm_,
+                                         Assembler::kCallSizeWithRelocation);
+    __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
+    __ Bind(&ok);
+  }
+
+  { Comment cmnt(masm_, "[ Body");
+    DCHECK(loop_depth() == 0);
+    VisitStatements(function()->body());
+    DCHECK(loop_depth() == 0);
+  }
+
+  // Always emit a 'return undefined' in case control fell off the end of
+  // the body.
+  { Comment cmnt(masm_, "[ return <undefined>;");
+    __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
+  }
+  EmitReturnSequence();
+
+  // Force emission of the pools, so they don't get emitted in the middle
+  // of the back edge table.
+  masm()->CheckVeneerPool(true, false);
+  masm()->CheckConstPool(true, false);
+}
+
+
+void FullCodeGenerator::ClearAccumulator() {
+  __ Mov(x0, Smi::FromInt(0));
+}
+
+
+void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
+  __ Mov(x2, Operand(profiling_counter_));
+  __ Ldr(x3, FieldMemOperand(x2, Cell::kValueOffset));
+  __ Subs(x3, x3, Smi::FromInt(delta));
+  __ Str(x3, FieldMemOperand(x2, Cell::kValueOffset));
+}
+
+
+void FullCodeGenerator::EmitProfilingCounterReset() {
+  int reset_value = FLAG_interrupt_budget;
+  if (info_->is_debug()) {
+    // Detect debug break requests as soon as possible.
+    reset_value = FLAG_interrupt_budget >> 4;
+  }
+  __ Mov(x2, Operand(profiling_counter_));
+  __ Mov(x3, Smi::FromInt(reset_value));
+  __ Str(x3, FieldMemOperand(x2, Cell::kValueOffset));
+}
+
+
+void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
+                                                Label* back_edge_target) {
+  DCHECK(jssp.Is(__ StackPointer()));
+  Comment cmnt(masm_, "[ Back edge bookkeeping");
+  // Block literal pools whilst emitting back edge code.
+  Assembler::BlockPoolsScope block_const_pool(masm_);
+  Label ok;
+
+  DCHECK(back_edge_target->is_bound());
+  // We want to do a round rather than a floor of distance/kCodeSizeMultiplier
+  // to reduce the absolute error due to the integer division. To do that,
+  // we add kCodeSizeMultiplier/2 to the distance (equivalent to adding 0.5 to
+  // the result).
+  int distance =
+    masm_->SizeOfCodeGeneratedSince(back_edge_target) + kCodeSizeMultiplier / 2;
+  int weight = Min(kMaxBackEdgeWeight,
+                   Max(1, distance / kCodeSizeMultiplier));
+  EmitProfilingCounterDecrement(weight);
+  __ B(pl, &ok);
+  __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
+
+  // Record a mapping of this PC offset to the OSR id.  This is used to find
+  // the AST id from the unoptimized code in order to use it as a key into
+  // the deoptimization input data found in the optimized code.
+  RecordBackEdge(stmt->OsrEntryId());
+
+  EmitProfilingCounterReset();
+
+  __ Bind(&ok);
+  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
+  // Record a mapping of the OSR id to this PC.  This is used if the OSR
+  // entry becomes the target of a bailout.  We don't expect it to be, but
+  // we want it to work if it is.
+  PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
+}
+
+
+void FullCodeGenerator::EmitReturnSequence() {
+  Comment cmnt(masm_, "[ Return sequence");
+
+  if (return_label_.is_bound()) {
+    __ B(&return_label_);
+
+  } else {
+    __ Bind(&return_label_);
+    if (FLAG_trace) {
+      // Push the return value on the stack as the parameter.
+      // Runtime::TraceExit returns its parameter in x0.
+      __ Push(result_register());
+      __ CallRuntime(Runtime::kTraceExit, 1);
+      DCHECK(x0.Is(result_register()));
+    }
+    // Pretend that the exit is a backwards jump to the entry.
+    int weight = 1;
+    if (info_->ShouldSelfOptimize()) {
+      weight = FLAG_interrupt_budget / FLAG_self_opt_count;
+    } else {
+      int distance = masm_->pc_offset() + kCodeSizeMultiplier / 2;
+      weight = Min(kMaxBackEdgeWeight,
+                   Max(1, distance / kCodeSizeMultiplier));
+    }
+    EmitProfilingCounterDecrement(weight);
+    Label ok;
+    __ B(pl, &ok);
+    __ Push(x0);
+    __ Call(isolate()->builtins()->InterruptCheck(),
+            RelocInfo::CODE_TARGET);
+    __ Pop(x0);
+    EmitProfilingCounterReset();
+    __ Bind(&ok);
+
+    // Make sure that the constant pool is not emitted inside of the return
+    // sequence. This sequence can get patched when the debugger is used. See
+    // debug-arm64.cc:BreakLocationIterator::SetDebugBreakAtReturn().
+    {
+      InstructionAccurateScope scope(masm_,
+                                     Assembler::kJSRetSequenceInstructions);
+      CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
+      __ RecordJSReturn();
+      // This code is generated using Assembler methods rather than Macro
+      // Assembler methods because it will be patched later on, and so the size
+      // of the generated code must be consistent.
+      const Register& current_sp = __ StackPointer();
+      // Nothing ensures 16 bytes alignment here.
+      DCHECK(!current_sp.Is(csp));
+      __ mov(current_sp, fp);
+      int no_frame_start = masm_->pc_offset();
+      __ ldp(fp, lr, MemOperand(current_sp, 2 * kXRegSize, PostIndex));
+      // Drop the arguments and receiver and return.
+      // TODO(all): This implementation is overkill as it supports 2**31+1
+      // arguments, consider how to improve it without creating a security
+      // hole.
+      __ ldr_pcrel(ip0, (3 * kInstructionSize) >> kLoadLiteralScaleLog2);
+      __ add(current_sp, current_sp, ip0);
+      __ ret();
+      __ dc64(kXRegSize * (info_->scope()->num_parameters() + 1));
+      info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+    }
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  codegen()->GetVar(result_register(), var);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  codegen()->GetVar(result_register(), var);
+  __ Push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Variable* var) const {
+  DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+  // For simplicity we always test the accumulator register.
+  codegen()->GetVar(result_register(), var);
+  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
+  codegen()->DoTest(this);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
+  // Root values have no side effects.
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Heap::RootListIndex index) const {
+  __ LoadRoot(result_register(), index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+    Heap::RootListIndex index) const {
+  __ LoadRoot(result_register(), index);
+  __ Push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(), true, true_label_,
+                                          false_label_);
+  if (index == Heap::kUndefinedValueRootIndex ||
+      index == Heap::kNullValueRootIndex ||
+      index == Heap::kFalseValueRootIndex) {
+    if (false_label_ != fall_through_) __ B(false_label_);
+  } else if (index == Heap::kTrueValueRootIndex) {
+    if (true_label_ != fall_through_) __ B(true_label_);
+  } else {
+    __ LoadRoot(result_register(), index);
+    codegen()->DoTest(this);
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Handle<Object> lit) const {
+  __ Mov(result_register(), Operand(lit));
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
+  // Immediates cannot be pushed directly.
+  __ Mov(result_register(), Operand(lit));
+  __ Push(result_register());
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(),
+                                          true,
+                                          true_label_,
+                                          false_label_);
+  DCHECK(!lit->IsUndetectableObject());  // There are no undetectable literals.
+  if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
+    if (false_label_ != fall_through_) __ B(false_label_);
+  } else if (lit->IsTrue() || lit->IsJSObject()) {
+    if (true_label_ != fall_through_) __ B(true_label_);
+  } else if (lit->IsString()) {
+    if (String::cast(*lit)->length() == 0) {
+      if (false_label_ != fall_through_) __ B(false_label_);
+    } else {
+      if (true_label_ != fall_through_) __ B(true_label_);
+    }
+  } else if (lit->IsSmi()) {
+    if (Smi::cast(*lit)->value() == 0) {
+      if (false_label_ != fall_through_) __ B(false_label_);
+    } else {
+      if (true_label_ != fall_through_) __ B(true_label_);
+    }
+  } else {
+    // For simplicity we always test the accumulator register.
+    __ Mov(result_register(), Operand(lit));
+    codegen()->DoTest(this);
+  }
+}
+
+
+void FullCodeGenerator::EffectContext::DropAndPlug(int count,
+                                                   Register reg) const {
+  DCHECK(count > 0);
+  __ Drop(count);
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
+    int count,
+    Register reg) const {
+  DCHECK(count > 0);
+  __ Drop(count);
+  __ Move(result_register(), reg);
+}
+
+
+void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
+                                                       Register reg) const {
+  DCHECK(count > 0);
+  if (count > 1) __ Drop(count - 1);
+  __ Poke(reg, 0);
+}
+
+
+void FullCodeGenerator::TestContext::DropAndPlug(int count,
+                                                 Register reg) const {
+  DCHECK(count > 0);
+  // For simplicity we always test the accumulator register.
+  __ Drop(count);
+  __ Mov(result_register(), reg);
+  codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
+  codegen()->DoTest(this);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
+                                            Label* materialize_false) const {
+  DCHECK(materialize_true == materialize_false);
+  __ Bind(materialize_true);
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(
+    Label* materialize_true,
+    Label* materialize_false) const {
+  Label done;
+  __ Bind(materialize_true);
+  __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
+  __ B(&done);
+  __ Bind(materialize_false);
+  __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
+  __ Bind(&done);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(
+    Label* materialize_true,
+    Label* materialize_false) const {
+  Label done;
+  __ Bind(materialize_true);
+  __ LoadRoot(x10, Heap::kTrueValueRootIndex);
+  __ B(&done);
+  __ Bind(materialize_false);
+  __ LoadRoot(x10, Heap::kFalseValueRootIndex);
+  __ Bind(&done);
+  __ Push(x10);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
+                                          Label* materialize_false) const {
+  DCHECK(materialize_true == true_label_);
+  DCHECK(materialize_false == false_label_);
+}
+
+
+void FullCodeGenerator::EffectContext::Plug(bool flag) const {
+}
+
+
+void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
+  Heap::RootListIndex value_root_index =
+      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+  __ LoadRoot(result_register(), value_root_index);
+}
+
+
+void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
+  Heap::RootListIndex value_root_index =
+      flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
+  __ LoadRoot(x10, value_root_index);
+  __ Push(x10);
+}
+
+
+void FullCodeGenerator::TestContext::Plug(bool flag) const {
+  codegen()->PrepareForBailoutBeforeSplit(condition(),
+                                          true,
+                                          true_label_,
+                                          false_label_);
+  if (flag) {
+    if (true_label_ != fall_through_) {
+      __ B(true_label_);
+    }
+  } else {
+    if (false_label_ != fall_through_) {
+      __ B(false_label_);
+    }
+  }
+}
+
+
+void FullCodeGenerator::DoTest(Expression* condition,
+                               Label* if_true,
+                               Label* if_false,
+                               Label* fall_through) {
+  Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
+  CallIC(ic, condition->test_id());
+  __ CompareAndSplit(result_register(), 0, ne, if_true, if_false, fall_through);
+}
+
+
+// If (cond), branch to if_true.
+// If (!cond), branch to if_false.
+// fall_through is used as an optimization in cases where only one branch
+// instruction is necessary.
+void FullCodeGenerator::Split(Condition cond,
+                              Label* if_true,
+                              Label* if_false,
+                              Label* fall_through) {
+  if (if_false == fall_through) {
+    __ B(cond, if_true);
+  } else if (if_true == fall_through) {
+    DCHECK(if_false != fall_through);
+    __ B(NegateCondition(cond), if_false);
+  } else {
+    __ B(cond, if_true);
+    __ B(if_false);
+  }
+}
+
+
+MemOperand FullCodeGenerator::StackOperand(Variable* var) {
+  // Offset is negative because higher indexes are at lower addresses.
+  int offset = -var->index() * kXRegSize;
+  // Adjust by a (parameter or local) base offset.
+  if (var->IsParameter()) {
+    offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
+  } else {
+    offset += JavaScriptFrameConstants::kLocal0Offset;
+  }
+  return MemOperand(fp, offset);
+}
+
+
+MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
+  DCHECK(var->IsContextSlot() || var->IsStackAllocated());
+  if (var->IsContextSlot()) {
+    int context_chain_length = scope()->ContextChainLength(var->scope());
+    __ LoadContext(scratch, context_chain_length);
+    return ContextMemOperand(scratch, var->index());
+  } else {
+    return StackOperand(var);
+  }
+}
+
+
+void FullCodeGenerator::GetVar(Register dest, Variable* var) {
+  // Use destination as scratch.
+  MemOperand location = VarOperand(var, dest);
+  __ Ldr(dest, location);
+}
+
+
+void FullCodeGenerator::SetVar(Variable* var,
+                               Register src,
+                               Register scratch0,
+                               Register scratch1) {
+  DCHECK(var->IsContextSlot() || var->IsStackAllocated());
+  DCHECK(!AreAliased(src, scratch0, scratch1));
+  MemOperand location = VarOperand(var, scratch0);
+  __ Str(src, location);
+
+  // Emit the write barrier code if the location is in the heap.
+  if (var->IsContextSlot()) {
+    // scratch0 contains the correct context.
+    __ RecordWriteContextSlot(scratch0,
+                              location.offset(),
+                              src,
+                              scratch1,
+                              kLRHasBeenSaved,
+                              kDontSaveFPRegs);
+  }
+}
+
+
+void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
+                                                     bool should_normalize,
+                                                     Label* if_true,
+                                                     Label* if_false) {
+  // Only prepare for bailouts before splits if we're in a test
+  // context. Otherwise, we let the Visit function deal with the
+  // preparation to avoid preparing with the same AST id twice.
+  if (!context()->IsTest() || !info_->IsOptimizable()) return;
+
+  // TODO(all): Investigate to see if there is something to work on here.
+  Label skip;
+  if (should_normalize) {
+    __ B(&skip);
+  }
+  PrepareForBailout(expr, TOS_REG);
+  if (should_normalize) {
+    __ CompareRoot(x0, Heap::kTrueValueRootIndex);
+    Split(eq, if_true, if_false, NULL);
+    __ Bind(&skip);
+  }
+}
+
+
+void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
+  // The variable in the declaration always resides in the current function
+  // context.
+  DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
+  if (generate_debug_code_) {
+    // Check that we're not inside a with or catch context.
+    __ Ldr(x1, FieldMemOperand(cp, HeapObject::kMapOffset));
+    __ CompareRoot(x1, Heap::kWithContextMapRootIndex);
+    __ Check(ne, kDeclarationInWithContext);
+    __ CompareRoot(x1, Heap::kCatchContextMapRootIndex);
+    __ Check(ne, kDeclarationInCatchContext);
+  }
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(
+    VariableDeclaration* declaration) {
+  // If it was not possible to allocate the variable at compile time, we
+  // need to "declare" it at runtime to make sure it actually exists in the
+  // local context.
+  VariableProxy* proxy = declaration->proxy();
+  VariableMode mode = declaration->mode();
+  Variable* variable = proxy->var();
+  bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
+
+  switch (variable->location()) {
+    case Variable::UNALLOCATED:
+      globals_->Add(variable->name(), zone());
+      globals_->Add(variable->binding_needs_init()
+                        ? isolate()->factory()->the_hole_value()
+                        : isolate()->factory()->undefined_value(),
+                    zone());
+      break;
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+      if (hole_init) {
+        Comment cmnt(masm_, "[ VariableDeclaration");
+        __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
+        __ Str(x10, StackOperand(variable));
+      }
+      break;
+
+    case Variable::CONTEXT:
+      if (hole_init) {
+        Comment cmnt(masm_, "[ VariableDeclaration");
+        EmitDebugCheckDeclarationContext(variable);
+        __ LoadRoot(x10, Heap::kTheHoleValueRootIndex);
+        __ Str(x10, ContextMemOperand(cp, variable->index()));
+        // No write barrier since the_hole_value is in old space.
+        PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+      }
+      break;
+
+    case Variable::LOOKUP: {
+      Comment cmnt(masm_, "[ VariableDeclaration");
+      __ Mov(x2, Operand(variable->name()));
+      // Declaration nodes are always introduced in one of four modes.
+      DCHECK(IsDeclaredVariableMode(mode));
+      PropertyAttributes attr = IsImmutableVariableMode(mode) ? READ_ONLY
+                                                              : NONE;
+      __ Mov(x1, Smi::FromInt(attr));
+      // Push initial value, if any.
+      // Note: For variables we must not push an initial value (such as
+      // 'undefined') because we may have a (legal) redeclaration and we
+      // must not destroy the current value.
+      if (hole_init) {
+        __ LoadRoot(x0, Heap::kTheHoleValueRootIndex);
+        __ Push(cp, x2, x1, x0);
+      } else {
+        // Pushing 0 (xzr) indicates no initial value.
+        __ Push(cp, x2, x1, xzr);
+      }
+      __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitFunctionDeclaration(
+    FunctionDeclaration* declaration) {
+  VariableProxy* proxy = declaration->proxy();
+  Variable* variable = proxy->var();
+  switch (variable->location()) {
+    case Variable::UNALLOCATED: {
+      globals_->Add(variable->name(), zone());
+      Handle<SharedFunctionInfo> function =
+          Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
+      // Check for stack overflow exception.
+      if (function.is_null()) return SetStackOverflow();
+      globals_->Add(function, zone());
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL: {
+      Comment cmnt(masm_, "[ Function Declaration");
+      VisitForAccumulatorValue(declaration->fun());
+      __ Str(result_register(), StackOperand(variable));
+      break;
+    }
+
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, "[ Function Declaration");
+      EmitDebugCheckDeclarationContext(variable);
+      VisitForAccumulatorValue(declaration->fun());
+      __ Str(result_register(), ContextMemOperand(cp, variable->index()));
+      int offset = Context::SlotOffset(variable->index());
+      // We know that we have written a function, which is not a smi.
+      __ RecordWriteContextSlot(cp,
+                                offset,
+                                result_register(),
+                                x2,
+                                kLRHasBeenSaved,
+                                kDontSaveFPRegs,
+                                EMIT_REMEMBERED_SET,
+                                OMIT_SMI_CHECK);
+      PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
+      break;
+    }
+
+    case Variable::LOOKUP: {
+      Comment cmnt(masm_, "[ Function Declaration");
+      __ Mov(x2, Operand(variable->name()));
+      __ Mov(x1, Smi::FromInt(NONE));
+      __ Push(cp, x2, x1);
+      // Push initial value for function declaration.
+      VisitForStackValue(declaration->fun());
+      __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
+  Variable* variable = declaration->proxy()->var();
+  DCHECK(variable->location() == Variable::CONTEXT);
+  DCHECK(variable->interface()->IsFrozen());
+
+  Comment cmnt(masm_, "[ ModuleDeclaration");
+  EmitDebugCheckDeclarationContext(variable);
+
+  // Load instance object.
+  __ LoadContext(x1, scope_->ContextChainLength(scope_->GlobalScope()));
+  __ Ldr(x1, ContextMemOperand(x1, variable->interface()->Index()));
+  __ Ldr(x1, ContextMemOperand(x1, Context::EXTENSION_INDEX));
+
+  // Assign it.
+  __ Str(x1, ContextMemOperand(cp, variable->index()));
+  // We know that we have written a module, which is not a smi.
+  __ RecordWriteContextSlot(cp,
+                            Context::SlotOffset(variable->index()),
+                            x1,
+                            x3,
+                            kLRHasBeenSaved,
+                            kDontSaveFPRegs,
+                            EMIT_REMEMBERED_SET,
+                            OMIT_SMI_CHECK);
+  PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
+
+  // Traverse info body.
+  Visit(declaration->module());
+}
+
+
+void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
+  VariableProxy* proxy = declaration->proxy();
+  Variable* variable = proxy->var();
+  switch (variable->location()) {
+    case Variable::UNALLOCATED:
+      // TODO(rossberg)
+      break;
+
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, "[ ImportDeclaration");
+      EmitDebugCheckDeclarationContext(variable);
+      // TODO(rossberg)
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+    case Variable::LOOKUP:
+      UNREACHABLE();
+  }
+}
+
+
+void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
+  // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+  // Call the runtime to declare the globals.
+  __ Mov(x11, Operand(pairs));
+  Register flags = xzr;
+  if (Smi::FromInt(DeclareGlobalsFlags())) {
+    flags = x10;
+  __ Mov(flags, Smi::FromInt(DeclareGlobalsFlags()));
+  }
+  __ Push(cp, x11, flags);
+  __ CallRuntime(Runtime::kDeclareGlobals, 3);
+  // Return value is ignored.
+}
+
+
+void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
+  // Call the runtime to declare the modules.
+  __ Push(descriptions);
+  __ CallRuntime(Runtime::kDeclareModules, 1);
+  // Return value is ignored.
+}
+
+
+void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
+  ASM_LOCATION("FullCodeGenerator::VisitSwitchStatement");
+  Comment cmnt(masm_, "[ SwitchStatement");
+  Breakable nested_statement(this, stmt);
+  SetStatementPosition(stmt);
+
+  // Keep the switch value on the stack until a case matches.
+  VisitForStackValue(stmt->tag());
+  PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
+
+  ZoneList<CaseClause*>* clauses = stmt->cases();
+  CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
+
+  Label next_test;  // Recycled for each test.
+  // Compile all the tests with branches to their bodies.
+  for (int i = 0; i < clauses->length(); i++) {
+    CaseClause* clause = clauses->at(i);
+    clause->body_target()->Unuse();
+
+    // The default is not a test, but remember it as final fall through.
+    if (clause->is_default()) {
+      default_clause = clause;
+      continue;
+    }
+
+    Comment cmnt(masm_, "[ Case comparison");
+    __ Bind(&next_test);
+    next_test.Unuse();
+
+    // Compile the label expression.
+    VisitForAccumulatorValue(clause->label());
+
+    // Perform the comparison as if via '==='.
+    __ Peek(x1, 0);   // Switch value.
+
+    JumpPatchSite patch_site(masm_);
+    if (ShouldInlineSmiCase(Token::EQ_STRICT)) {
+      Label slow_case;
+      patch_site.EmitJumpIfEitherNotSmi(x0, x1, &slow_case);
+      __ Cmp(x1, x0);
+      __ B(ne, &next_test);
+      __ Drop(1);  // Switch value is no longer needed.
+      __ B(clause->body_target());
+      __ Bind(&slow_case);
+    }
+
+    // Record position before stub call for type feedback.
+    SetSourcePosition(clause->position());
+    Handle<Code> ic =
+        CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
+    CallIC(ic, clause->CompareId());
+    patch_site.EmitPatchInfo();
+
+    Label skip;
+    __ B(&skip);
+    PrepareForBailout(clause, TOS_REG);
+    __ JumpIfNotRoot(x0, Heap::kTrueValueRootIndex, &next_test);
+    __ Drop(1);
+    __ B(clause->body_target());
+    __ Bind(&skip);
+
+    __ Cbnz(x0, &next_test);
+    __ Drop(1);  // Switch value is no longer needed.
+    __ B(clause->body_target());
+  }
+
+  // Discard the test value and jump to the default if present, otherwise to
+  // the end of the statement.
+  __ Bind(&next_test);
+  __ Drop(1);  // Switch value is no longer needed.
+  if (default_clause == NULL) {
+    __ B(nested_statement.break_label());
+  } else {
+    __ B(default_clause->body_target());
+  }
+
+  // Compile all the case bodies.
+  for (int i = 0; i < clauses->length(); i++) {
+    Comment cmnt(masm_, "[ Case body");
+    CaseClause* clause = clauses->at(i);
+    __ Bind(clause->body_target());
+    PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
+    VisitStatements(clause->statements());
+  }
+
+  __ Bind(nested_statement.break_label());
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+}
+
+
+void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
+  ASM_LOCATION("FullCodeGenerator::VisitForInStatement");
+  Comment cmnt(masm_, "[ ForInStatement");
+  int slot = stmt->ForInFeedbackSlot();
+  // TODO(all): This visitor probably needs better comments and a revisit.
+  SetStatementPosition(stmt);
+
+  Label loop, exit;
+  ForIn loop_statement(this, stmt);
+  increment_loop_depth();
+
+  // Get the object to enumerate over. If the object is null or undefined, skip
+  // over the loop.  See ECMA-262 version 5, section 12.6.4.
+  VisitForAccumulatorValue(stmt->enumerable());
+  __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, &exit);
+  Register null_value = x15;
+  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
+  __ Cmp(x0, null_value);
+  __ B(eq, &exit);
+
+  PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
+
+  // Convert the object to a JS object.
+  Label convert, done_convert;
+  __ JumpIfSmi(x0, &convert);
+  __ JumpIfObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE, &done_convert, ge);
+  __ Bind(&convert);
+  __ Push(x0);
+  __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
+  __ Bind(&done_convert);
+  __ Push(x0);
+
+  // Check for proxies.
+  Label call_runtime;
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  __ JumpIfObjectType(x0, x10, x11, LAST_JS_PROXY_TYPE, &call_runtime, le);
+
+  // Check cache validity in generated code. This is a fast case for
+  // the JSObject::IsSimpleEnum cache validity checks. If we cannot
+  // guarantee cache validity, call the runtime system to check cache
+  // validity or get the property names in a fixed array.
+  __ CheckEnumCache(x0, null_value, x10, x11, x12, x13, &call_runtime);
+
+  // The enum cache is valid.  Load the map of the object being
+  // iterated over and use the cache for the iteration.
+  Label use_cache;
+  __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ B(&use_cache);
+
+  // Get the set of properties to enumerate.
+  __ Bind(&call_runtime);
+  __ Push(x0);  // Duplicate the enumerable object on the stack.
+  __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
+
+  // If we got a map from the runtime call, we can do a fast
+  // modification check. Otherwise, we got a fixed array, and we have
+  // to do a slow check.
+  Label fixed_array, no_descriptors;
+  __ Ldr(x2, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ JumpIfNotRoot(x2, Heap::kMetaMapRootIndex, &fixed_array);
+
+  // We got a map in register x0. Get the enumeration cache from it.
+  __ Bind(&use_cache);
+
+  __ EnumLengthUntagged(x1, x0);
+  __ Cbz(x1, &no_descriptors);
+
+  __ LoadInstanceDescriptors(x0, x2);
+  __ Ldr(x2, FieldMemOperand(x2, DescriptorArray::kEnumCacheOffset));
+  __ Ldr(x2,
+         FieldMemOperand(x2, DescriptorArray::kEnumCacheBridgeCacheOffset));
+
+  // Set up the four remaining stack slots.
+  __ SmiTag(x1);
+  // Map, enumeration cache, enum cache length, zero (both last as smis).
+  __ Push(x0, x2, x1, xzr);
+  __ B(&loop);
+
+  __ Bind(&no_descriptors);
+  __ Drop(1);
+  __ B(&exit);
+
+  // We got a fixed array in register x0. Iterate through that.
+  __ Bind(&fixed_array);
+
+  __ LoadObject(x1, FeedbackVector());
+  __ Mov(x10, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
+  __ Str(x10, FieldMemOperand(x1, FixedArray::OffsetOfElementAt(slot)));
+
+  __ Mov(x1, Smi::FromInt(1));  // Smi indicates slow check.
+  __ Peek(x10, 0);  // Get enumerated object.
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  // TODO(all): similar check was done already. Can we avoid it here?
+  __ CompareObjectType(x10, x11, x12, LAST_JS_PROXY_TYPE);
+  DCHECK(Smi::FromInt(0) == 0);
+  __ CzeroX(x1, le);  // Zero indicates proxy.
+  __ Ldr(x2, FieldMemOperand(x0, FixedArray::kLengthOffset));
+  // Smi and array, fixed array length (as smi) and initial index.
+  __ Push(x1, x0, x2, xzr);
+
+  // Generate code for doing the condition check.
+  PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
+  __ Bind(&loop);
+  // Load the current count to x0, load the length to x1.
+  __ PeekPair(x0, x1, 0);
+  __ Cmp(x0, x1);  // Compare to the array length.
+  __ B(hs, loop_statement.break_label());
+
+  // Get the current entry of the array into register r3.
+  __ Peek(x10, 2 * kXRegSize);
+  __ Add(x10, x10, Operand::UntagSmiAndScale(x0, kPointerSizeLog2));
+  __ Ldr(x3, MemOperand(x10, FixedArray::kHeaderSize - kHeapObjectTag));
+
+  // Get the expected map from the stack or a smi in the
+  // permanent slow case into register x10.
+  __ Peek(x2, 3 * kXRegSize);
+
+  // Check if the expected map still matches that of the enumerable.
+  // If not, we may have to filter the key.
+  Label update_each;
+  __ Peek(x1, 4 * kXRegSize);
+  __ Ldr(x11, FieldMemOperand(x1, HeapObject::kMapOffset));
+  __ Cmp(x11, x2);
+  __ B(eq, &update_each);
+
+  // For proxies, no filtering is done.
+  // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
+  STATIC_ASSERT(kSmiTag == 0);
+  __ Cbz(x2, &update_each);
+
+  // Convert the entry to a string or (smi) 0 if it isn't a property
+  // any more. If the property has been removed while iterating, we
+  // just skip it.
+  __ Push(x1, x3);
+  __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
+  __ Mov(x3, x0);
+  __ Cbz(x0, loop_statement.continue_label());
+
+  // Update the 'each' property or variable from the possibly filtered
+  // entry in register x3.
+  __ Bind(&update_each);
+  __ Mov(result_register(), x3);
+  // Perform the assignment as if via '='.
+  { EffectContext context(this);
+    EmitAssignment(stmt->each());
+  }
+
+  // Generate code for the body of the loop.
+  Visit(stmt->body());
+
+  // Generate code for going to the next element by incrementing
+  // the index (smi) stored on top of the stack.
+  __ Bind(loop_statement.continue_label());
+  // TODO(all): We could use a callee saved register to avoid popping.
+  __ Pop(x0);
+  __ Add(x0, x0, Smi::FromInt(1));
+  __ Push(x0);
+
+  EmitBackEdgeBookkeeping(stmt, &loop);
+  __ B(&loop);
+
+  // Remove the pointers stored on the stack.
+  __ Bind(loop_statement.break_label());
+  __ Drop(5);
+
+  // Exit and decrement the loop depth.
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+  __ Bind(&exit);
+  decrement_loop_depth();
+}
+
+
+void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
+  Comment cmnt(masm_, "[ ForOfStatement");
+  SetStatementPosition(stmt);
+
+  Iteration loop_statement(this, stmt);
+  increment_loop_depth();
+
+  // var iterator = iterable[Symbol.iterator]();
+  VisitForEffect(stmt->assign_iterator());
+
+  // Loop entry.
+  __ Bind(loop_statement.continue_label());
+
+  // result = iterator.next()
+  VisitForEffect(stmt->next_result());
+
+  // if (result.done) break;
+  Label result_not_done;
+  VisitForControl(stmt->result_done(),
+                  loop_statement.break_label(),
+                  &result_not_done,
+                  &result_not_done);
+  __ Bind(&result_not_done);
+
+  // each = result.value
+  VisitForEffect(stmt->assign_each());
+
+  // Generate code for the body of the loop.
+  Visit(stmt->body());
+
+  // Check stack before looping.
+  PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
+  EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
+  __ B(loop_statement.continue_label());
+
+  // Exit and decrement the loop depth.
+  PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
+  __ Bind(loop_statement.break_label());
+  decrement_loop_depth();
+}
+
+
+void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
+                                       bool pretenure) {
+  // Use the fast case closure allocation code that allocates in new space for
+  // nested functions that don't need literals cloning. If we're running with
+  // the --always-opt or the --prepare-always-opt flag, we need to use the
+  // runtime function so that the new function we are creating here gets a
+  // chance to have its code optimized and doesn't just get a copy of the
+  // existing unoptimized code.
+  if (!FLAG_always_opt &&
+      !FLAG_prepare_always_opt &&
+      !pretenure &&
+      scope()->is_function_scope() &&
+      info->num_literals() == 0) {
+    FastNewClosureStub stub(isolate(), info->strict_mode(), info->kind());
+    __ Mov(x2, Operand(info));
+    __ CallStub(&stub);
+  } else {
+    __ Mov(x11, Operand(info));
+    __ LoadRoot(x10, pretenure ? Heap::kTrueValueRootIndex
+                               : Heap::kFalseValueRootIndex);
+    __ Push(cp, x11, x10);
+    __ CallRuntime(Runtime::kNewClosure, 3);
+  }
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
+  Comment cmnt(masm_, "[ VariableProxy");
+  EmitVariableLoad(expr);
+}
+
+
+void FullCodeGenerator::EmitLoadHomeObject(SuperReference* expr) {
+  Comment cnmt(masm_, "[ SuperReference ");
+
+  __ ldr(LoadDescriptor::ReceiverRegister(),
+         MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+
+  Handle<Symbol> home_object_symbol(isolate()->heap()->home_object_symbol());
+  __ Mov(LoadDescriptor::NameRegister(), Operand(home_object_symbol));
+
+  CallLoadIC(NOT_CONTEXTUAL, expr->HomeObjectFeedbackId());
+
+  __ Mov(x10, Operand(isolate()->factory()->undefined_value()));
+  __ cmp(x0, x10);
+  Label done;
+  __ b(&done, ne);
+  __ CallRuntime(Runtime::kThrowNonMethodError, 0);
+  __ bind(&done);
+}
+
+
+void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
+                                                      TypeofState typeof_state,
+                                                      Label* slow) {
+  Register current = cp;
+  Register next = x10;
+  Register temp = x11;
+
+  Scope* s = scope();
+  while (s != NULL) {
+    if (s->num_heap_slots() > 0) {
+      if (s->calls_sloppy_eval()) {
+        // Check that extension is NULL.
+        __ Ldr(temp, ContextMemOperand(current, Context::EXTENSION_INDEX));
+        __ Cbnz(temp, slow);
+      }
+      // Load next context in chain.
+      __ Ldr(next, ContextMemOperand(current, Context::PREVIOUS_INDEX));
+      // Walk the rest of the chain without clobbering cp.
+      current = next;
+    }
+    // If no outer scope calls eval, we do not need to check more
+    // context extensions.
+    if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
+    s = s->outer_scope();
+  }
+
+  if (s->is_eval_scope()) {
+    Label loop, fast;
+    __ Mov(next, current);
+
+    __ Bind(&loop);
+    // Terminate at native context.
+    __ Ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
+    __ JumpIfRoot(temp, Heap::kNativeContextMapRootIndex, &fast);
+    // Check that extension is NULL.
+    __ Ldr(temp, ContextMemOperand(next, Context::EXTENSION_INDEX));
+    __ Cbnz(temp, slow);
+    // Load next context in chain.
+    __ Ldr(next, ContextMemOperand(next, Context::PREVIOUS_INDEX));
+    __ B(&loop);
+    __ Bind(&fast);
+  }
+
+  __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+  __ Mov(LoadDescriptor::NameRegister(), Operand(proxy->var()->name()));
+  if (FLAG_vector_ics) {
+    __ Mov(VectorLoadICDescriptor::SlotRegister(),
+           Smi::FromInt(proxy->VariableFeedbackSlot()));
+  }
+
+  ContextualMode mode = (typeof_state == INSIDE_TYPEOF) ? NOT_CONTEXTUAL
+                                                        : CONTEXTUAL;
+  CallLoadIC(mode);
+}
+
+
+MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
+                                                                Label* slow) {
+  DCHECK(var->IsContextSlot());
+  Register context = cp;
+  Register next = x10;
+  Register temp = x11;
+
+  for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
+    if (s->num_heap_slots() > 0) {
+      if (s->calls_sloppy_eval()) {
+        // Check that extension is NULL.
+        __ Ldr(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
+        __ Cbnz(temp, slow);
+      }
+      __ Ldr(next, ContextMemOperand(context, Context::PREVIOUS_INDEX));
+      // Walk the rest of the chain without clobbering cp.
+      context = next;
+    }
+  }
+  // Check that last extension is NULL.
+  __ Ldr(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
+  __ Cbnz(temp, slow);
+
+  // This function is used only for loads, not stores, so it's safe to
+  // return an cp-based operand (the write barrier cannot be allowed to
+  // destroy the cp register).
+  return ContextMemOperand(context, var->index());
+}
+
+
+void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
+                                                  TypeofState typeof_state,
+                                                  Label* slow,
+                                                  Label* done) {
+  // Generate fast-case code for variables that might be shadowed by
+  // eval-introduced variables.  Eval is used a lot without
+  // introducing variables.  In those cases, we do not want to
+  // perform a runtime call for all variables in the scope
+  // containing the eval.
+  Variable* var = proxy->var();
+  if (var->mode() == DYNAMIC_GLOBAL) {
+    EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
+    __ B(done);
+  } else if (var->mode() == DYNAMIC_LOCAL) {
+    Variable* local = var->local_if_not_shadowed();
+    __ Ldr(x0, ContextSlotOperandCheckExtensions(local, slow));
+    if (local->mode() == LET || local->mode() == CONST ||
+        local->mode() == CONST_LEGACY) {
+      __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, done);
+      if (local->mode() == CONST_LEGACY) {
+        __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
+      } else {  // LET || CONST
+        __ Mov(x0, Operand(var->name()));
+        __ Push(x0);
+        __ CallRuntime(Runtime::kThrowReferenceError, 1);
+      }
+    }
+    __ B(done);
+  }
+}
+
+
+void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
+  // Record position before possible IC call.
+  SetSourcePosition(proxy->position());
+  Variable* var = proxy->var();
+
+  // Three cases: global variables, lookup variables, and all other types of
+  // variables.
+  switch (var->location()) {
+    case Variable::UNALLOCATED: {
+      Comment cmnt(masm_, "Global variable");
+      __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+      __ Mov(LoadDescriptor::NameRegister(), Operand(var->name()));
+      if (FLAG_vector_ics) {
+        __ Mov(VectorLoadICDescriptor::SlotRegister(),
+               Smi::FromInt(proxy->VariableFeedbackSlot()));
+      }
+      CallLoadIC(CONTEXTUAL);
+      context()->Plug(x0);
+      break;
+    }
+
+    case Variable::PARAMETER:
+    case Variable::LOCAL:
+    case Variable::CONTEXT: {
+      Comment cmnt(masm_, var->IsContextSlot()
+                              ? "Context variable"
+                              : "Stack variable");
+      if (var->binding_needs_init()) {
+        // var->scope() may be NULL when the proxy is located in eval code and
+        // refers to a potential outside binding. Currently those bindings are
+        // always looked up dynamically, i.e. in that case
+        //     var->location() == LOOKUP.
+        // always holds.
+        DCHECK(var->scope() != NULL);
+
+        // Check if the binding really needs an initialization check. The check
+        // can be skipped in the following situation: we have a LET or CONST
+        // binding in harmony mode, both the Variable and the VariableProxy have
+        // the same declaration scope (i.e. they are both in global code, in the
+        // same function or in the same eval code) and the VariableProxy is in
+        // the source physically located after the initializer of the variable.
+        //
+        // We cannot skip any initialization checks for CONST in non-harmony
+        // mode because const variables may be declared but never initialized:
+        //   if (false) { const x; }; var y = x;
+        //
+        // The condition on the declaration scopes is a conservative check for
+        // nested functions that access a binding and are called before the
+        // binding is initialized:
+        //   function() { f(); let x = 1; function f() { x = 2; } }
+        //
+        bool skip_init_check;
+        if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
+          skip_init_check = false;
+        } else {
+          // Check that we always have valid source position.
+          DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
+          DCHECK(proxy->position() != RelocInfo::kNoPosition);
+          skip_init_check = var->mode() != CONST_LEGACY &&
+              var->initializer_position() < proxy->position();
+        }
+
+        if (!skip_init_check) {
+          // Let and const need a read barrier.
+          GetVar(x0, var);
+          Label done;
+          __ JumpIfNotRoot(x0, Heap::kTheHoleValueRootIndex, &done);
+          if (var->mode() == LET || var->mode() == CONST) {
+            // Throw a reference error when using an uninitialized let/const
+            // binding in harmony mode.
+            __ Mov(x0, Operand(var->name()));
+            __ Push(x0);
+            __ CallRuntime(Runtime::kThrowReferenceError, 1);
+            __ Bind(&done);
+          } else {
+            // Uninitalized const bindings outside of harmony mode are unholed.
+            DCHECK(var->mode() == CONST_LEGACY);
+            __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
+            __ Bind(&done);
+          }
+          context()->Plug(x0);
+          break;
+        }
+      }
+      context()->Plug(var);
+      break;
+    }
+
+    case Variable::LOOKUP: {
+      Label done, slow;
+      // Generate code for loading from variables potentially shadowed by
+      // eval-introduced variables.
+      EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
+      __ Bind(&slow);
+      Comment cmnt(masm_, "Lookup variable");
+      __ Mov(x1, Operand(var->name()));
+      __ Push(cp, x1);  // Context and name.
+      __ CallRuntime(Runtime::kLoadLookupSlot, 2);
+      __ Bind(&done);
+      context()->Plug(x0);
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
+  Comment cmnt(masm_, "[ RegExpLiteral");
+  Label materialized;
+  // Registers will be used as follows:
+  // x5 = materialized value (RegExp literal)
+  // x4 = JS function, literals array
+  // x3 = literal index
+  // x2 = RegExp pattern
+  // x1 = RegExp flags
+  // x0 = RegExp literal clone
+  __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Ldr(x4, FieldMemOperand(x10, JSFunction::kLiteralsOffset));
+  int literal_offset =
+      FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
+  __ Ldr(x5, FieldMemOperand(x4, literal_offset));
+  __ JumpIfNotRoot(x5, Heap::kUndefinedValueRootIndex, &materialized);
+
+  // Create regexp literal using runtime function.
+  // Result will be in x0.
+  __ Mov(x3, Smi::FromInt(expr->literal_index()));
+  __ Mov(x2, Operand(expr->pattern()));
+  __ Mov(x1, Operand(expr->flags()));
+  __ Push(x4, x3, x2, x1);
+  __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
+  __ Mov(x5, x0);
+
+  __ Bind(&materialized);
+  int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
+  Label allocated, runtime_allocate;
+  __ Allocate(size, x0, x2, x3, &runtime_allocate, TAG_OBJECT);
+  __ B(&allocated);
+
+  __ Bind(&runtime_allocate);
+  __ Mov(x10, Smi::FromInt(size));
+  __ Push(x5, x10);
+  __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
+  __ Pop(x5);
+
+  __ Bind(&allocated);
+  // After this, registers are used as follows:
+  // x0: Newly allocated regexp.
+  // x5: Materialized regexp.
+  // x10, x11, x12: temps.
+  __ CopyFields(x0, x5, CPURegList(x10, x11, x12), size / kPointerSize);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitAccessor(Expression* expression) {
+  if (expression == NULL) {
+    __ LoadRoot(x10, Heap::kNullValueRootIndex);
+    __ Push(x10);
+  } else {
+    VisitForStackValue(expression);
+  }
+}
+
+
+void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
+  Comment cmnt(masm_, "[ ObjectLiteral");
+
+  expr->BuildConstantProperties(isolate());
+  Handle<FixedArray> constant_properties = expr->constant_properties();
+  __ Ldr(x3, MemOperand(fp,  JavaScriptFrameConstants::kFunctionOffset));
+  __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset));
+  __ Mov(x2, Smi::FromInt(expr->literal_index()));
+  __ Mov(x1, Operand(constant_properties));
+  int flags = expr->fast_elements()
+      ? ObjectLiteral::kFastElements
+      : ObjectLiteral::kNoFlags;
+  flags |= expr->has_function()
+      ? ObjectLiteral::kHasFunction
+      : ObjectLiteral::kNoFlags;
+  __ Mov(x0, Smi::FromInt(flags));
+  int properties_count = constant_properties->length() / 2;
+  const int max_cloned_properties =
+      FastCloneShallowObjectStub::kMaximumClonedProperties;
+  if (expr->may_store_doubles() || expr->depth() > 1 ||
+      masm()->serializer_enabled() || flags != ObjectLiteral::kFastElements ||
+      properties_count > max_cloned_properties) {
+    __ Push(x3, x2, x1, x0);
+    __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
+  } else {
+    FastCloneShallowObjectStub stub(isolate(), properties_count);
+    __ CallStub(&stub);
+  }
+
+  // If result_saved is true the result is on top of the stack.  If
+  // result_saved is false the result is in x0.
+  bool result_saved = false;
+
+  // Mark all computed expressions that are bound to a key that
+  // is shadowed by a later occurrence of the same key. For the
+  // marked expressions, no store code is emitted.
+  expr->CalculateEmitStore(zone());
+
+  AccessorTable accessor_table(zone());
+  for (int i = 0; i < expr->properties()->length(); i++) {
+    ObjectLiteral::Property* property = expr->properties()->at(i);
+    if (property->IsCompileTimeValue()) continue;
+
+    Literal* key = property->key();
+    Expression* value = property->value();
+    if (!result_saved) {
+      __ Push(x0);  // Save result on stack
+      result_saved = true;
+    }
+    switch (property->kind()) {
+      case ObjectLiteral::Property::CONSTANT:
+        UNREACHABLE();
+      case ObjectLiteral::Property::MATERIALIZED_LITERAL:
+        DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
+        // Fall through.
+      case ObjectLiteral::Property::COMPUTED:
+        if (key->value()->IsInternalizedString()) {
+          if (property->emit_store()) {
+            VisitForAccumulatorValue(value);
+            DCHECK(StoreDescriptor::ValueRegister().is(x0));
+            __ Mov(StoreDescriptor::NameRegister(), Operand(key->value()));
+            __ Peek(StoreDescriptor::ReceiverRegister(), 0);
+            CallStoreIC(key->LiteralFeedbackId());
+            PrepareForBailoutForId(key->id(), NO_REGISTERS);
+          } else {
+            VisitForEffect(value);
+          }
+          break;
+        }
+        if (property->emit_store()) {
+          // Duplicate receiver on stack.
+          __ Peek(x0, 0);
+          __ Push(x0);
+          VisitForStackValue(key);
+          VisitForStackValue(value);
+          __ Mov(x0, Smi::FromInt(SLOPPY));  // Strict mode
+          __ Push(x0);
+          __ CallRuntime(Runtime::kSetProperty, 4);
+        } else {
+          VisitForEffect(key);
+          VisitForEffect(value);
+        }
+        break;
+      case ObjectLiteral::Property::PROTOTYPE:
+        if (property->emit_store()) {
+          // Duplicate receiver on stack.
+          __ Peek(x0, 0);
+          __ Push(x0);
+          VisitForStackValue(value);
+          __ CallRuntime(Runtime::kSetPrototype, 2);
+        } else {
+          VisitForEffect(value);
+        }
+        break;
+      case ObjectLiteral::Property::GETTER:
+        accessor_table.lookup(key)->second->getter = value;
+        break;
+      case ObjectLiteral::Property::SETTER:
+        accessor_table.lookup(key)->second->setter = value;
+        break;
+    }
+  }
+
+  // Emit code to define accessors, using only a single call to the runtime for
+  // each pair of corresponding getters and setters.
+  for (AccessorTable::Iterator it = accessor_table.begin();
+       it != accessor_table.end();
+       ++it) {
+      __ Peek(x10, 0);  // Duplicate receiver.
+      __ Push(x10);
+      VisitForStackValue(it->first);
+      EmitAccessor(it->second->getter);
+      EmitAccessor(it->second->setter);
+      __ Mov(x10, Smi::FromInt(NONE));
+      __ Push(x10);
+      __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
+  }
+
+  if (expr->has_function()) {
+    DCHECK(result_saved);
+    __ Peek(x0, 0);
+    __ Push(x0);
+    __ CallRuntime(Runtime::kToFastProperties, 1);
+  }
+
+  if (result_saved) {
+    context()->PlugTOS();
+  } else {
+    context()->Plug(x0);
+  }
+}
+
+
+void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
+  Comment cmnt(masm_, "[ ArrayLiteral");
+
+  expr->BuildConstantElements(isolate());
+  int flags = (expr->depth() == 1) ? ArrayLiteral::kShallowElements
+                                   : ArrayLiteral::kNoFlags;
+
+  ZoneList<Expression*>* subexprs = expr->values();
+  int length = subexprs->length();
+  Handle<FixedArray> constant_elements = expr->constant_elements();
+  DCHECK_EQ(2, constant_elements->length());
+  ElementsKind constant_elements_kind =
+      static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
+  bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
+  Handle<FixedArrayBase> constant_elements_values(
+      FixedArrayBase::cast(constant_elements->get(1)));
+
+  AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
+  if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
+    // If the only customer of allocation sites is transitioning, then
+    // we can turn it off if we don't have anywhere else to transition to.
+    allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
+  }
+
+  __ Ldr(x3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  __ Ldr(x3, FieldMemOperand(x3, JSFunction::kLiteralsOffset));
+  __ Mov(x2, Smi::FromInt(expr->literal_index()));
+  __ Mov(x1, Operand(constant_elements));
+  if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) {
+    __ Mov(x0, Smi::FromInt(flags));
+    __ Push(x3, x2, x1, x0);
+    __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
+  } else {
+    FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
+    __ CallStub(&stub);
+  }
+
+  bool result_saved = false;  // Is the result saved to the stack?
+
+  // Emit code to evaluate all the non-constant subexpressions and to store
+  // them into the newly cloned array.
+  for (int i = 0; i < length; i++) {
+    Expression* subexpr = subexprs->at(i);
+    // If the subexpression is a literal or a simple materialized literal it
+    // is already set in the cloned array.
+    if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
+
+    if (!result_saved) {
+      __ Mov(x1, Smi::FromInt(expr->literal_index()));
+      __ Push(x0, x1);
+      result_saved = true;
+    }
+    VisitForAccumulatorValue(subexpr);
+
+    if (IsFastObjectElementsKind(constant_elements_kind)) {
+      int offset = FixedArray::kHeaderSize + (i * kPointerSize);
+      __ Peek(x6, kPointerSize);  // Copy of array literal.
+      __ Ldr(x1, FieldMemOperand(x6, JSObject::kElementsOffset));
+      __ Str(result_register(), FieldMemOperand(x1, offset));
+      // Update the write barrier for the array store.
+      __ RecordWriteField(x1, offset, result_register(), x10,
+                          kLRHasBeenSaved, kDontSaveFPRegs,
+                          EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
+    } else {
+      __ Mov(x3, Smi::FromInt(i));
+      StoreArrayLiteralElementStub stub(isolate());
+      __ CallStub(&stub);
+    }
+
+    PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
+  }
+
+  if (result_saved) {
+    __ Drop(1);   // literal index
+    context()->PlugTOS();
+  } else {
+    context()->Plug(x0);
+  }
+}
+
+
+void FullCodeGenerator::VisitAssignment(Assignment* expr) {
+  DCHECK(expr->target()->IsValidReferenceExpression());
+
+  Comment cmnt(masm_, "[ Assignment");
+
+  // Left-hand side can only be a property, a global or a (parameter or local)
+  // slot.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* property = expr->target()->AsProperty();
+  if (property != NULL) {
+    assign_type = (property->key()->IsPropertyName())
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
+  }
+
+  // Evaluate LHS expression.
+  switch (assign_type) {
+    case VARIABLE:
+      // Nothing to do here.
+      break;
+    case NAMED_PROPERTY:
+      if (expr->is_compound()) {
+        // We need the receiver both on the stack and in the register.
+        VisitForStackValue(property->obj());
+        __ Peek(LoadDescriptor::ReceiverRegister(), 0);
+      } else {
+        VisitForStackValue(property->obj());
+      }
+      break;
+    case KEYED_PROPERTY:
+      if (expr->is_compound()) {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+        __ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
+        __ Peek(LoadDescriptor::NameRegister(), 0);
+      } else {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+      }
+      break;
+  }
+
+  // For compound assignments we need another deoptimization point after the
+  // variable/property load.
+  if (expr->is_compound()) {
+    { AccumulatorValueContext context(this);
+      switch (assign_type) {
+        case VARIABLE:
+          EmitVariableLoad(expr->target()->AsVariableProxy());
+          PrepareForBailout(expr->target(), TOS_REG);
+          break;
+        case NAMED_PROPERTY:
+          EmitNamedPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+        case KEYED_PROPERTY:
+          EmitKeyedPropertyLoad(property);
+          PrepareForBailoutForId(property->LoadId(), TOS_REG);
+          break;
+      }
+    }
+
+    Token::Value op = expr->binary_op();
+    __ Push(x0);  // Left operand goes on the stack.
+    VisitForAccumulatorValue(expr->value());
+
+    OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
+        ? OVERWRITE_RIGHT
+        : NO_OVERWRITE;
+    SetSourcePosition(expr->position() + 1);
+    AccumulatorValueContext context(this);
+    if (ShouldInlineSmiCase(op)) {
+      EmitInlineSmiBinaryOp(expr->binary_operation(),
+                            op,
+                            mode,
+                            expr->target(),
+                            expr->value());
+    } else {
+      EmitBinaryOp(expr->binary_operation(), op, mode);
+    }
+
+    // Deoptimization point in case the binary operation may have side effects.
+    PrepareForBailout(expr->binary_operation(), TOS_REG);
+  } else {
+    VisitForAccumulatorValue(expr->value());
+  }
+
+  // Record source position before possible IC call.
+  SetSourcePosition(expr->position());
+
+  // Store the value.
+  switch (assign_type) {
+    case VARIABLE:
+      EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
+                             expr->op());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      context()->Plug(x0);
+      break;
+    case NAMED_PROPERTY:
+      EmitNamedPropertyAssignment(expr);
+      break;
+    case KEYED_PROPERTY:
+      EmitKeyedPropertyAssignment(expr);
+      break;
+  }
+}
+
+
+void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!prop->IsSuperAccess());
+
+  __ Mov(LoadDescriptor::NameRegister(), Operand(key->value()));
+  if (FLAG_vector_ics) {
+    __ Mov(VectorLoadICDescriptor::SlotRegister(),
+           Smi::FromInt(prop->PropertyFeedbackSlot()));
+    CallLoadIC(NOT_CONTEXTUAL);
+  } else {
+    CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
+  }
+}
+
+
+void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) {
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!key->value()->IsSmi());
+  DCHECK(prop->IsSuperAccess());
+
+  SuperReference* super_ref = prop->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(x0);
+  VisitForStackValue(super_ref->this_var());
+  __ Push(key->value());
+  __ CallRuntime(Runtime::kLoadFromSuper, 3);
+}
+
+
+void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
+  SetSourcePosition(prop->position());
+  // Call keyed load IC. It has arguments key and receiver in r0 and r1.
+  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  if (FLAG_vector_ics) {
+    __ Mov(VectorLoadICDescriptor::SlotRegister(),
+           Smi::FromInt(prop->PropertyFeedbackSlot()));
+    CallIC(ic);
+  } else {
+    CallIC(ic, prop->PropertyFeedbackId());
+  }
+}
+
+
+void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
+                                              Token::Value op,
+                                              OverwriteMode mode,
+                                              Expression* left_expr,
+                                              Expression* right_expr) {
+  Label done, both_smis, stub_call;
+
+  // Get the arguments.
+  Register left = x1;
+  Register right = x0;
+  Register result = x0;
+  __ Pop(left);
+
+  // Perform combined smi check on both operands.
+  __ Orr(x10, left, right);
+  JumpPatchSite patch_site(masm_);
+  patch_site.EmitJumpIfSmi(x10, &both_smis);
+
+  __ Bind(&stub_call);
+
+  Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
+  {
+    Assembler::BlockPoolsScope scope(masm_);
+    CallIC(code, expr->BinaryOperationFeedbackId());
+    patch_site.EmitPatchInfo();
+  }
+  __ B(&done);
+
+  __ Bind(&both_smis);
+  // Smi case. This code works in the same way as the smi-smi case in the type
+  // recording binary operation stub, see
+  // BinaryOpStub::GenerateSmiSmiOperation for comments.
+  // TODO(all): That doesn't exist any more. Where are the comments?
+  //
+  // The set of operations that needs to be supported here is controlled by
+  // FullCodeGenerator::ShouldInlineSmiCase().
+  switch (op) {
+    case Token::SAR:
+      __ Ubfx(right, right, kSmiShift, 5);
+      __ Asr(result, left, right);
+      __ Bic(result, result, kSmiShiftMask);
+      break;
+    case Token::SHL:
+      __ Ubfx(right, right, kSmiShift, 5);
+      __ Lsl(result, left, right);
+      break;
+    case Token::SHR:
+      // If `left >>> right` >= 0x80000000, the result is not representable in a
+      // signed 32-bit smi.
+      __ Ubfx(right, right, kSmiShift, 5);
+      __ Lsr(x10, left, right);
+      __ Tbnz(x10, kXSignBit, &stub_call);
+      __ Bic(result, x10, kSmiShiftMask);
+      break;
+    case Token::ADD:
+      __ Adds(x10, left, right);
+      __ B(vs, &stub_call);
+      __ Mov(result, x10);
+      break;
+    case Token::SUB:
+      __ Subs(x10, left, right);
+      __ B(vs, &stub_call);
+      __ Mov(result, x10);
+      break;
+    case Token::MUL: {
+      Label not_minus_zero, done;
+      STATIC_ASSERT(static_cast<unsigned>(kSmiShift) == (kXRegSizeInBits / 2));
+      STATIC_ASSERT(kSmiTag == 0);
+      __ Smulh(x10, left, right);
+      __ Cbnz(x10, &not_minus_zero);
+      __ Eor(x11, left, right);
+      __ Tbnz(x11, kXSignBit, &stub_call);
+      __ Mov(result, x10);
+      __ B(&done);
+      __ Bind(&not_minus_zero);
+      __ Cls(x11, x10);
+      __ Cmp(x11, kXRegSizeInBits - kSmiShift);
+      __ B(lt, &stub_call);
+      __ SmiTag(result, x10);
+      __ Bind(&done);
+      break;
+    }
+    case Token::BIT_OR:
+      __ Orr(result, left, right);
+      break;
+    case Token::BIT_AND:
+      __ And(result, left, right);
+      break;
+    case Token::BIT_XOR:
+      __ Eor(result, left, right);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  __ Bind(&done);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
+                                     Token::Value op,
+                                     OverwriteMode mode) {
+  __ Pop(x1);
+  Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op, mode).code();
+  JumpPatchSite patch_site(masm_);    // Unbound, signals no inlined smi code.
+  {
+    Assembler::BlockPoolsScope scope(masm_);
+    CallIC(code, expr->BinaryOperationFeedbackId());
+    patch_site.EmitPatchInfo();
+  }
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitAssignment(Expression* expr) {
+  DCHECK(expr->IsValidReferenceExpression());
+
+  // Left-hand side can only be a property, a global or a (parameter or local)
+  // slot.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* prop = expr->AsProperty();
+  if (prop != NULL) {
+    assign_type = (prop->key()->IsPropertyName())
+        ? NAMED_PROPERTY
+        : KEYED_PROPERTY;
+  }
+
+  switch (assign_type) {
+    case VARIABLE: {
+      Variable* var = expr->AsVariableProxy()->var();
+      EffectContext context(this);
+      EmitVariableAssignment(var, Token::ASSIGN);
+      break;
+    }
+    case NAMED_PROPERTY: {
+      __ Push(x0);  // Preserve value.
+      VisitForAccumulatorValue(prop->obj());
+      // TODO(all): We could introduce a VisitForRegValue(reg, expr) to avoid
+      // this copy.
+      __ Mov(StoreDescriptor::ReceiverRegister(), x0);
+      __ Pop(StoreDescriptor::ValueRegister());  // Restore value.
+      __ Mov(StoreDescriptor::NameRegister(),
+             Operand(prop->key()->AsLiteral()->value()));
+      CallStoreIC();
+      break;
+    }
+    case KEYED_PROPERTY: {
+      __ Push(x0);  // Preserve value.
+      VisitForStackValue(prop->obj());
+      VisitForAccumulatorValue(prop->key());
+      __ Mov(StoreDescriptor::NameRegister(), x0);
+      __ Pop(StoreDescriptor::ReceiverRegister(),
+             StoreDescriptor::ValueRegister());
+      Handle<Code> ic =
+          CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+      CallIC(ic);
+      break;
+    }
+  }
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
+    Variable* var, MemOperand location) {
+  __ Str(result_register(), location);
+  if (var->IsContextSlot()) {
+    // RecordWrite may destroy all its register arguments.
+    __ Mov(x10, result_register());
+    int offset = Context::SlotOffset(var->index());
+    __ RecordWriteContextSlot(
+        x1, offset, x10, x11, kLRHasBeenSaved, kDontSaveFPRegs);
+  }
+}
+
+
+void FullCodeGenerator::EmitVariableAssignment(Variable* var,
+                                               Token::Value op) {
+  ASM_LOCATION("FullCodeGenerator::EmitVariableAssignment");
+  if (var->IsUnallocated()) {
+    // Global var, const, or let.
+    __ Mov(StoreDescriptor::NameRegister(), Operand(var->name()));
+    __ Ldr(StoreDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+    CallStoreIC();
+
+  } else if (op == Token::INIT_CONST_LEGACY) {
+    // Const initializers need a write barrier.
+    DCHECK(!var->IsParameter());  // No const parameters.
+    if (var->IsLookupSlot()) {
+      __ Mov(x1, Operand(var->name()));
+      __ Push(x0, cp, x1);
+      __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
+    } else {
+      DCHECK(var->IsStackLocal() || var->IsContextSlot());
+      Label skip;
+      MemOperand location = VarOperand(var, x1);
+      __ Ldr(x10, location);
+      __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &skip);
+      EmitStoreToStackLocalOrContextSlot(var, location);
+      __ Bind(&skip);
+    }
+
+  } else if (var->mode() == LET && op != Token::INIT_LET) {
+    // Non-initializing assignment to let variable needs a write barrier.
+    DCHECK(!var->IsLookupSlot());
+    DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+    Label assign;
+    MemOperand location = VarOperand(var, x1);
+    __ Ldr(x10, location);
+    __ JumpIfNotRoot(x10, Heap::kTheHoleValueRootIndex, &assign);
+    __ Mov(x10, Operand(var->name()));
+    __ Push(x10);
+    __ CallRuntime(Runtime::kThrowReferenceError, 1);
+    // Perform the assignment.
+    __ Bind(&assign);
+    EmitStoreToStackLocalOrContextSlot(var, location);
+
+  } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
+    if (var->IsLookupSlot()) {
+      // Assignment to var.
+      __ Mov(x11, Operand(var->name()));
+      __ Mov(x10, Smi::FromInt(strict_mode()));
+      // jssp[0]  : mode.
+      // jssp[8]  : name.
+      // jssp[16] : context.
+      // jssp[24] : value.
+      __ Push(x0, cp, x11, x10);
+      __ CallRuntime(Runtime::kStoreLookupSlot, 4);
+    } else {
+      // Assignment to var or initializing assignment to let/const in harmony
+      // mode.
+      DCHECK(var->IsStackAllocated() || var->IsContextSlot());
+      MemOperand location = VarOperand(var, x1);
+      if (FLAG_debug_code && op == Token::INIT_LET) {
+        __ Ldr(x10, location);
+        __ CompareRoot(x10, Heap::kTheHoleValueRootIndex);
+        __ Check(eq, kLetBindingReInitialization);
+      }
+      EmitStoreToStackLocalOrContextSlot(var, location);
+    }
+  }
+  // Non-initializing assignments to consts are ignored.
+}
+
+
+void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitNamedPropertyAssignment");
+  // Assignment to a property, using a named store IC.
+  Property* prop = expr->target()->AsProperty();
+  DCHECK(prop != NULL);
+  DCHECK(prop->key()->IsLiteral());
+
+  // Record source code position before IC call.
+  SetSourcePosition(expr->position());
+  __ Mov(StoreDescriptor::NameRegister(),
+         Operand(prop->key()->AsLiteral()->value()));
+  __ Pop(StoreDescriptor::ReceiverRegister());
+  CallStoreIC(expr->AssignmentFeedbackId());
+
+  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitKeyedPropertyAssignment");
+  // Assignment to a property, using a keyed store IC.
+
+  // Record source code position before IC call.
+  SetSourcePosition(expr->position());
+  // TODO(all): Could we pass this in registers rather than on the stack?
+  __ Pop(StoreDescriptor::NameRegister(), StoreDescriptor::ReceiverRegister());
+  DCHECK(StoreDescriptor::ValueRegister().is(x0));
+
+  Handle<Code> ic = CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+  CallIC(ic, expr->AssignmentFeedbackId());
+
+  PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::VisitProperty(Property* expr) {
+  Comment cmnt(masm_, "[ Property");
+  Expression* key = expr->key();
+
+  if (key->IsPropertyName()) {
+    if (!expr->IsSuperAccess()) {
+      VisitForAccumulatorValue(expr->obj());
+      __ Move(LoadDescriptor::ReceiverRegister(), x0);
+      EmitNamedPropertyLoad(expr);
+    } else {
+      EmitNamedSuperPropertyLoad(expr);
+    }
+    PrepareForBailoutForId(expr->LoadId(), TOS_REG);
+    context()->Plug(x0);
+  } else {
+    VisitForStackValue(expr->obj());
+    VisitForAccumulatorValue(expr->key());
+    __ Move(LoadDescriptor::NameRegister(), x0);
+    __ Pop(LoadDescriptor::ReceiverRegister());
+    EmitKeyedPropertyLoad(expr);
+    context()->Plug(x0);
+  }
+}
+
+
+void FullCodeGenerator::CallIC(Handle<Code> code,
+                               TypeFeedbackId ast_id) {
+  ic_total_count_++;
+  // All calls must have a predictable size in full-codegen code to ensure that
+  // the debugger can patch them correctly.
+  __ Call(code, RelocInfo::CODE_TARGET, ast_id);
+}
+
+
+// Code common for calls using the IC.
+void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+
+  CallICState::CallType call_type =
+      callee->IsVariableProxy() ? CallICState::FUNCTION : CallICState::METHOD;
+
+  // Get the target function.
+  if (call_type == CallICState::FUNCTION) {
+    { StackValueContext context(this);
+      EmitVariableLoad(callee->AsVariableProxy());
+      PrepareForBailout(callee, NO_REGISTERS);
+    }
+    // Push undefined as receiver. This is patched in the method prologue if it
+    // is a sloppy mode method.
+    __ Push(isolate()->factory()->undefined_value());
+  } else {
+    // Load the function from the receiver.
+    DCHECK(callee->IsProperty());
+    DCHECK(!callee->AsProperty()->IsSuperAccess());
+    __ Peek(LoadDescriptor::ReceiverRegister(), 0);
+    EmitNamedPropertyLoad(callee->AsProperty());
+    PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
+    // Push the target function under the receiver.
+    __ Pop(x10);
+    __ Push(x0, x10);
+  }
+
+  EmitCall(expr, call_type);
+}
+
+
+void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
+  Expression* callee = expr->expression();
+  DCHECK(callee->IsProperty());
+  Property* prop = callee->AsProperty();
+  DCHECK(prop->IsSuperAccess());
+
+  SetSourcePosition(prop->position());
+  Literal* key = prop->key()->AsLiteral();
+  DCHECK(!key->value()->IsSmi());
+
+  // Load the function from the receiver.
+  const Register scratch = x10;
+  SuperReference* super_ref = callee->AsProperty()->obj()->AsSuperReference();
+  EmitLoadHomeObject(super_ref);
+  __ Push(x0);
+  VisitForAccumulatorValue(super_ref->this_var());
+  __ Push(x0);
+  __ Peek(scratch, kPointerSize);
+  __ Push(scratch, x0);
+  __ Push(key->value());
+
+  // Stack here:
+  //  - home_object
+  //  - this (receiver)
+  //  - home_object <-- LoadFromSuper will pop here and below.
+  //  - this (receiver)
+  //  - key
+  __ CallRuntime(Runtime::kLoadFromSuper, 3);
+
+  // Replace home_object with target function.
+  __ Poke(x0, kPointerSize);
+
+  // Stack here:
+  // - target function
+  // - this (receiver)
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
+// Code common for calls using the IC.
+void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
+                                                Expression* key) {
+  // Load the key.
+  VisitForAccumulatorValue(key);
+
+  Expression* callee = expr->expression();
+
+  // Load the function from the receiver.
+  DCHECK(callee->IsProperty());
+  __ Peek(LoadDescriptor::ReceiverRegister(), 0);
+  __ Move(LoadDescriptor::NameRegister(), x0);
+  EmitKeyedPropertyLoad(callee->AsProperty());
+  PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
+
+  // Push the target function under the receiver.
+  __ Pop(x10);
+  __ Push(x0, x10);
+
+  EmitCall(expr, CallICState::METHOD);
+}
+
+
+void FullCodeGenerator::EmitCall(Call* expr, CallICState::CallType call_type) {
+  // Load the arguments.
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+  { PreservePositionScope scope(masm()->positions_recorder());
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+  }
+  // Record source position of the IC call.
+  SetSourcePosition(expr->position());
+
+  Handle<Code> ic = CallIC::initialize_stub(
+      isolate(), arg_count, call_type);
+  __ Mov(x3, Smi::FromInt(expr->CallFeedbackSlot()));
+  __ Peek(x1, (arg_count + 1) * kXRegSize);
+  // Don't assign a type feedback id to the IC, since type feedback is provided
+  // by the vector above.
+  CallIC(ic);
+
+  RecordJSReturnSite(expr);
+  // Restore context register.
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  context()->DropAndPlug(1, x0);
+}
+
+
+void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
+  ASM_LOCATION("FullCodeGenerator::EmitResolvePossiblyDirectEval");
+  // Prepare to push a copy of the first argument or undefined if it doesn't
+  // exist.
+  if (arg_count > 0) {
+    __ Peek(x9, arg_count * kXRegSize);
+  } else {
+    __ LoadRoot(x9, Heap::kUndefinedValueRootIndex);
+  }
+
+  __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  // Prepare to push the receiver of the enclosing function.
+  int receiver_offset = 2 + info_->scope()->num_parameters();
+  __ Ldr(x11, MemOperand(fp, receiver_offset * kPointerSize));
+
+  // Prepare to push the language mode.
+  __ Mov(x12, Smi::FromInt(strict_mode()));
+  // Prepare to push the start position of the scope the calls resides in.
+  __ Mov(x13, Smi::FromInt(scope()->start_position()));
+
+  // Push.
+  __ Push(x9, x10, x11, x12, x13);
+
+  // Do the runtime call.
+  __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 6);
+}
+
+
+void FullCodeGenerator::VisitCall(Call* expr) {
+#ifdef DEBUG
+  // We want to verify that RecordJSReturnSite gets called on all paths
+  // through this function.  Avoid early returns.
+  expr->return_is_recorded_ = false;
+#endif
+
+  Comment cmnt(masm_, "[ Call");
+  Expression* callee = expr->expression();
+  Call::CallType call_type = expr->GetCallType(isolate());
+
+  if (call_type == Call::POSSIBLY_EVAL_CALL) {
+    // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
+    // to resolve the function we need to call and the receiver of the
+    // call.  Then we call the resolved function using the given
+    // arguments.
+    ZoneList<Expression*>* args = expr->arguments();
+    int arg_count = args->length();
+
+    {
+      PreservePositionScope pos_scope(masm()->positions_recorder());
+      VisitForStackValue(callee);
+      __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
+      __ Push(x10);  // Reserved receiver slot.
+
+      // Push the arguments.
+      for (int i = 0; i < arg_count; i++) {
+        VisitForStackValue(args->at(i));
+      }
+
+      // Push a copy of the function (found below the arguments) and
+      // resolve eval.
+      __ Peek(x10, (arg_count + 1) * kPointerSize);
+      __ Push(x10);
+      EmitResolvePossiblyDirectEval(arg_count);
+
+      // The runtime call returns a pair of values in x0 (function) and
+      // x1 (receiver). Touch up the stack with the right values.
+      __ PokePair(x1, x0, arg_count * kPointerSize);
+    }
+
+    // Record source position for debugger.
+    SetSourcePosition(expr->position());
+
+    // Call the evaluated function.
+    CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
+    __ Peek(x1, (arg_count + 1) * kXRegSize);
+    __ CallStub(&stub);
+    RecordJSReturnSite(expr);
+    // Restore context register.
+    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    context()->DropAndPlug(1, x0);
+
+  } else if (call_type == Call::GLOBAL_CALL) {
+    EmitCallWithLoadIC(expr);
+
+  } else if (call_type == Call::LOOKUP_SLOT_CALL) {
+    // Call to a lookup slot (dynamically introduced variable).
+    VariableProxy* proxy = callee->AsVariableProxy();
+    Label slow, done;
+
+    { PreservePositionScope scope(masm()->positions_recorder());
+      // Generate code for loading from variables potentially shadowed
+      // by eval-introduced variables.
+      EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
+    }
+
+    __ Bind(&slow);
+    // Call the runtime to find the function to call (returned in x0)
+    // and the object holding it (returned in x1).
+    __ Mov(x10, Operand(proxy->name()));
+    __ Push(context_register(), x10);
+    __ CallRuntime(Runtime::kLoadLookupSlot, 2);
+    __ Push(x0, x1);  // Receiver, function.
+
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      Label call;
+      __ B(&call);
+      __ Bind(&done);
+      // Push function.
+      // The receiver is implicitly the global receiver. Indicate this
+      // by passing the undefined to the call function stub.
+      __ LoadRoot(x1, Heap::kUndefinedValueRootIndex);
+      __ Push(x0, x1);
+      __ Bind(&call);
+    }
+
+    // The receiver is either the global receiver or an object found
+    // by LoadContextSlot.
+    EmitCall(expr);
+  } else if (call_type == Call::PROPERTY_CALL) {
+    Property* property = callee->AsProperty();
+    bool is_named_call = property->key()->IsPropertyName();
+    // super.x() is handled in EmitCallWithLoadIC.
+    if (property->IsSuperAccess() && is_named_call) {
+      EmitSuperCallWithLoadIC(expr);
+    } else {
+      {
+        PreservePositionScope scope(masm()->positions_recorder());
+        VisitForStackValue(property->obj());
+      }
+      if (is_named_call) {
+        EmitCallWithLoadIC(expr);
+      } else {
+        EmitKeyedCallWithLoadIC(expr, property->key());
+      }
+    }
+  } else {
+    DCHECK(call_type == Call::OTHER_CALL);
+    // Call to an arbitrary expression not handled specially above.
+    { PreservePositionScope scope(masm()->positions_recorder());
+      VisitForStackValue(callee);
+    }
+    __ LoadRoot(x1, Heap::kUndefinedValueRootIndex);
+    __ Push(x1);
+    // Emit function call.
+    EmitCall(expr);
+  }
+
+#ifdef DEBUG
+  // RecordJSReturnSite should have been called.
+  DCHECK(expr->return_is_recorded_);
+#endif
+}
+
+
+void FullCodeGenerator::VisitCallNew(CallNew* expr) {
+  Comment cmnt(masm_, "[ CallNew");
+  // According to ECMA-262, section 11.2.2, page 44, the function
+  // expression in new calls must be evaluated before the
+  // arguments.
+
+  // Push constructor on the stack.  If it's not a function it's used as
+  // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
+  // ignored.
+  VisitForStackValue(expr->expression());
+
+  // Push the arguments ("left-to-right") on the stack.
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+  for (int i = 0; i < arg_count; i++) {
+    VisitForStackValue(args->at(i));
+  }
+
+  // Call the construct call builtin that handles allocation and
+  // constructor invocation.
+  SetSourcePosition(expr->position());
+
+  // Load function and argument count into x1 and x0.
+  __ Mov(x0, arg_count);
+  __ Peek(x1, arg_count * kXRegSize);
+
+  // Record call targets in unoptimized code.
+  if (FLAG_pretenuring_call_new) {
+    EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
+    DCHECK(expr->AllocationSiteFeedbackSlot() ==
+           expr->CallNewFeedbackSlot() + 1);
+  }
+
+  __ LoadObject(x2, FeedbackVector());
+  __ Mov(x3, Smi::FromInt(expr->CallNewFeedbackSlot()));
+
+  CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
+  __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
+  PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  __ TestAndSplit(x0, kSmiTagMask, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  uint64_t sign_mask = V8_UINT64_C(1) << (kSmiShift + kSmiValueSize - 1);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  __ TestAndSplit(x0, kSmiTagMask | sign_mask, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ JumpIfRoot(x0, Heap::kNullValueRootIndex, if_true);
+  __ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
+  // Undetectable objects behave like undefined when tested with typeof.
+  __ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
+  __ Tbnz(x11, Map::kIsUndetectable, if_false);
+  __ Ldrb(x12, FieldMemOperand(x10, Map::kInstanceTypeOffset));
+  __ Cmp(x12, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+  __ B(lt, if_false);
+  __ Cmp(x12, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(le, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ CompareObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ge, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitIsUndetectableObject");
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ Ldr(x10, FieldMemOperand(x0, HeapObject::kMapOffset));
+  __ Ldrb(x11, FieldMemOperand(x10, Map::kBitFieldOffset));
+  __ Tst(x11, 1 << Map::kIsUndetectable);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(ne, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
+    CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false, skip_lookup;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  Register object = x0;
+  __ AssertNotSmi(object);
+
+  Register map = x10;
+  Register bitfield2 = x11;
+  __ Ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  __ Ldrb(bitfield2, FieldMemOperand(map, Map::kBitField2Offset));
+  __ Tbnz(bitfield2, Map::kStringWrapperSafeForDefaultValueOf, &skip_lookup);
+
+  // Check for fast case object. Generate false result for slow case object.
+  Register props = x12;
+  Register props_map = x12;
+  Register hash_table_map = x13;
+  __ Ldr(props, FieldMemOperand(object, JSObject::kPropertiesOffset));
+  __ Ldr(props_map, FieldMemOperand(props, HeapObject::kMapOffset));
+  __ LoadRoot(hash_table_map, Heap::kHashTableMapRootIndex);
+  __ Cmp(props_map, hash_table_map);
+  __ B(eq, if_false);
+
+  // Look for valueOf name in the descriptor array, and indicate false if found.
+  // Since we omit an enumeration index check, if it is added via a transition
+  // that shares its descriptor array, this is a false positive.
+  Label loop, done;
+
+  // Skip loop if no descriptors are valid.
+  Register descriptors = x12;
+  Register descriptors_length = x13;
+  __ NumberOfOwnDescriptors(descriptors_length, map);
+  __ Cbz(descriptors_length, &done);
+
+  __ LoadInstanceDescriptors(map, descriptors);
+
+  // Calculate the end of the descriptor array.
+  Register descriptors_end = x14;
+  __ Mov(x15, DescriptorArray::kDescriptorSize);
+  __ Mul(descriptors_length, descriptors_length, x15);
+  // Calculate location of the first key name.
+  __ Add(descriptors, descriptors,
+         DescriptorArray::kFirstOffset - kHeapObjectTag);
+  // Calculate the end of the descriptor array.
+  __ Add(descriptors_end, descriptors,
+         Operand(descriptors_length, LSL, kPointerSizeLog2));
+
+  // Loop through all the keys in the descriptor array. If one of these is the
+  // string "valueOf" the result is false.
+  Register valueof_string = x1;
+  int descriptor_size = DescriptorArray::kDescriptorSize * kPointerSize;
+  __ Mov(valueof_string, Operand(isolate()->factory()->value_of_string()));
+  __ Bind(&loop);
+  __ Ldr(x15, MemOperand(descriptors, descriptor_size, PostIndex));
+  __ Cmp(x15, valueof_string);
+  __ B(eq, if_false);
+  __ Cmp(descriptors, descriptors_end);
+  __ B(ne, &loop);
+
+  __ Bind(&done);
+
+  // Set the bit in the map to indicate that there is no local valueOf field.
+  __ Ldrb(x2, FieldMemOperand(map, Map::kBitField2Offset));
+  __ Orr(x2, x2, 1 << Map::kStringWrapperSafeForDefaultValueOf);
+  __ Strb(x2, FieldMemOperand(map, Map::kBitField2Offset));
+
+  __ Bind(&skip_lookup);
+
+  // If a valueOf property is not found on the object check that its prototype
+  // is the unmodified String prototype. If not result is false.
+  Register prototype = x1;
+  Register global_idx = x2;
+  Register native_context = x2;
+  Register string_proto = x3;
+  Register proto_map = x4;
+  __ Ldr(prototype, FieldMemOperand(map, Map::kPrototypeOffset));
+  __ JumpIfSmi(prototype, if_false);
+  __ Ldr(proto_map, FieldMemOperand(prototype, HeapObject::kMapOffset));
+  __ Ldr(global_idx, GlobalObjectMemOperand());
+  __ Ldr(native_context,
+         FieldMemOperand(global_idx, GlobalObject::kNativeContextOffset));
+  __ Ldr(string_proto,
+         ContextMemOperand(native_context,
+                           Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
+  __ Cmp(proto_map, string_proto);
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ CompareObjectType(x0, x10, x11, JS_FUNCTION_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  // Only a HeapNumber can be -0.0, so return false if we have something else.
+  __ JumpIfNotHeapNumber(x0, if_false, DO_SMI_CHECK);
+
+  // Test the bit pattern.
+  __ Ldr(x10, FieldMemOperand(x0, HeapNumber::kValueOffset));
+  __ Cmp(x10, 1);   // Set V on 0x8000000000000000.
+
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(vs, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ CompareObjectType(x0, x10, x11, JS_ARRAY_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ JumpIfSmi(x0, if_false);
+  __ CompareObjectType(x0, x10, x11, JS_REGEXP_TYPE);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+
+void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  // Get the frame pointer for the calling frame.
+  __ Ldr(x2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  Label check_frame_marker;
+  __ Ldr(x1, MemOperand(x2, StandardFrameConstants::kContextOffset));
+  __ Cmp(x1, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ B(ne, &check_frame_marker);
+  __ Ldr(x2, MemOperand(x2, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ Bind(&check_frame_marker);
+  __ Ldr(x1, MemOperand(x2, StandardFrameConstants::kMarkerOffset));
+  __ Cmp(x1, Smi::FromInt(StackFrame::CONSTRUCT));
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+
+  // Load the two objects into registers and perform the comparison.
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ Pop(x1);
+  __ Cmp(x0, x1);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  // ArgumentsAccessStub expects the key in x1.
+  VisitForAccumulatorValue(args->at(0));
+  __ Mov(x1, x0);
+  __ Mov(x0, Smi::FromInt(info_->scope()->num_parameters()));
+  ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+  Label exit;
+  // Get the number of formal parameters.
+  __ Mov(x0, Smi::FromInt(info_->scope()->num_parameters()));
+
+  // Check if the calling frame is an arguments adaptor frame.
+  __ Ldr(x12, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ Ldr(x13, MemOperand(x12, StandardFrameConstants::kContextOffset));
+  __ Cmp(x13, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ B(ne, &exit);
+
+  // Arguments adaptor case: Read the arguments length from the
+  // adaptor frame.
+  __ Ldr(x0, MemOperand(x12, ArgumentsAdaptorFrameConstants::kLengthOffset));
+
+  __ Bind(&exit);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitClassOf");
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  Label done, null, function, non_function_constructor;
+
+  VisitForAccumulatorValue(args->at(0));
+
+  // If the object is a smi, we return null.
+  __ JumpIfSmi(x0, &null);
+
+  // Check that the object is a JS object but take special care of JS
+  // functions to make sure they have 'Function' as their class.
+  // Assume that there are only two callable types, and one of them is at
+  // either end of the type range for JS object types. Saves extra comparisons.
+  STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+  __ CompareObjectType(x0, x10, x11, FIRST_SPEC_OBJECT_TYPE);
+  // x10: object's map.
+  // x11: object's type.
+  __ B(lt, &null);
+  STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                FIRST_SPEC_OBJECT_TYPE + 1);
+  __ B(eq, &function);
+
+  __ Cmp(x11, LAST_SPEC_OBJECT_TYPE);
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                LAST_SPEC_OBJECT_TYPE - 1);
+  __ B(eq, &function);
+  // Assume that there is no larger type.
+  STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
+
+  // Check if the constructor in the map is a JS function.
+  __ Ldr(x12, FieldMemOperand(x10, Map::kConstructorOffset));
+  __ JumpIfNotObjectType(x12, x13, x14, JS_FUNCTION_TYPE,
+                         &non_function_constructor);
+
+  // x12 now contains the constructor function. Grab the
+  // instance class name from there.
+  __ Ldr(x13, FieldMemOperand(x12, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(x0,
+         FieldMemOperand(x13, SharedFunctionInfo::kInstanceClassNameOffset));
+  __ B(&done);
+
+  // Functions have class 'Function'.
+  __ Bind(&function);
+  __ LoadRoot(x0, Heap::kFunction_stringRootIndex);
+  __ B(&done);
+
+  // Objects with a non-function constructor have class 'Object'.
+  __ Bind(&non_function_constructor);
+  __ LoadRoot(x0, Heap::kObject_stringRootIndex);
+  __ B(&done);
+
+  // Non-JS objects have class null.
+  __ Bind(&null);
+  __ LoadRoot(x0, Heap::kNullValueRootIndex);
+
+  // All done.
+  __ Bind(&done);
+
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
+  // Load the arguments on the stack and call the stub.
+  SubStringStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 3);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForStackValue(args->at(2));
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
+  // Load the arguments on the stack and call the stub.
+  RegExpExecStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 4);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForStackValue(args->at(2));
+  VisitForStackValue(args->at(3));
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitValueOf");
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+  Label done;
+  // If the object is a smi return the object.
+  __ JumpIfSmi(x0, &done);
+  // If the object is not a value type, return the object.
+  __ JumpIfNotObjectType(x0, x10, x11, JS_VALUE_TYPE, &done);
+  __ Ldr(x0, FieldMemOperand(x0, JSValue::kValueOffset));
+
+  __ Bind(&done);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  DCHECK_NE(NULL, args->at(1)->AsLiteral());
+  Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
+
+  VisitForAccumulatorValue(args->at(0));  // Load the object.
+
+  Label runtime, done, not_date_object;
+  Register object = x0;
+  Register result = x0;
+  Register stamp_addr = x10;
+  Register stamp_cache = x11;
+
+  __ JumpIfSmi(object, &not_date_object);
+  __ JumpIfNotObjectType(object, x10, x10, JS_DATE_TYPE, &not_date_object);
+
+  if (index->value() == 0) {
+    __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
+    __ B(&done);
+  } else {
+    if (index->value() < JSDate::kFirstUncachedField) {
+      ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+      __ Mov(x10, stamp);
+      __ Ldr(stamp_addr, MemOperand(x10));
+      __ Ldr(stamp_cache, FieldMemOperand(object, JSDate::kCacheStampOffset));
+      __ Cmp(stamp_addr, stamp_cache);
+      __ B(ne, &runtime);
+      __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset +
+                                             kPointerSize * index->value()));
+      __ B(&done);
+    }
+
+    __ Bind(&runtime);
+    __ Mov(x1, index);
+    __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+    __ B(&done);
+  }
+
+  __ Bind(&not_date_object);
+  __ CallRuntime(Runtime::kThrowNotDateError, 0);
+  __ Bind(&done);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(3, args->length());
+
+  Register string = x0;
+  Register index = x1;
+  Register value = x2;
+  Register scratch = x10;
+
+  VisitForStackValue(args->at(0));        // index
+  VisitForStackValue(args->at(1));        // value
+  VisitForAccumulatorValue(args->at(2));  // string
+  __ Pop(value, index);
+
+  if (FLAG_debug_code) {
+    __ AssertSmi(value, kNonSmiValue);
+    __ AssertSmi(index, kNonSmiIndex);
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, kIndexIsSmi, scratch,
+                                 one_byte_seq_type);
+  }
+
+  __ Add(scratch, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ SmiUntag(value);
+  __ SmiUntag(index);
+  __ Strb(value, MemOperand(scratch, index));
+  context()->Plug(string);
+}
+
+
+void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(3, args->length());
+
+  Register string = x0;
+  Register index = x1;
+  Register value = x2;
+  Register scratch = x10;
+
+  VisitForStackValue(args->at(0));        // index
+  VisitForStackValue(args->at(1));        // value
+  VisitForAccumulatorValue(args->at(2));  // string
+  __ Pop(value, index);
+
+  if (FLAG_debug_code) {
+    __ AssertSmi(value, kNonSmiValue);
+    __ AssertSmi(index, kNonSmiIndex);
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    __ EmitSeqStringSetCharCheck(string, index, kIndexIsSmi, scratch,
+                                 two_byte_seq_type);
+  }
+
+  __ Add(scratch, string, SeqTwoByteString::kHeaderSize - kHeapObjectTag);
+  __ SmiUntag(value);
+  __ SmiUntag(index);
+  __ Strh(value, MemOperand(scratch, index, LSL, 1));
+  context()->Plug(string);
+}
+
+
+void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
+  // Load the arguments on the stack and call the MathPow stub.
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  MathPowStub stub(isolate(), MathPowStub::ON_STACK);
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(0));  // Load the object.
+  VisitForAccumulatorValue(args->at(1));  // Load the value.
+  __ Pop(x1);
+  // x0 = value.
+  // x1 = object.
+
+  Label done;
+  // If the object is a smi, return the value.
+  __ JumpIfSmi(x1, &done);
+
+  // If the object is not a value type, return the value.
+  __ JumpIfNotObjectType(x1, x10, x11, JS_VALUE_TYPE, &done);
+
+  // Store the value.
+  __ Str(x0, FieldMemOperand(x1, JSValue::kValueOffset));
+  // Update the write barrier. Save the value as it will be
+  // overwritten by the write barrier code and is needed afterward.
+  __ Mov(x10, x0);
+  __ RecordWriteField(
+      x1, JSValue::kValueOffset, x10, x11, kLRHasBeenSaved, kDontSaveFPRegs);
+
+  __ Bind(&done);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(args->length(), 1);
+
+  // Load the argument into x0 and call the stub.
+  VisitForAccumulatorValue(args->at(0));
+
+  NumberToStringStub stub(isolate());
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+
+  VisitForAccumulatorValue(args->at(0));
+
+  Label done;
+  Register code = x0;
+  Register result = x1;
+
+  StringCharFromCodeGenerator generator(code, result);
+  generator.GenerateFast(masm_);
+  __ B(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ Bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Register object = x1;
+  Register index = x0;
+  Register result = x3;
+
+  __ Pop(object);
+
+  Label need_conversion;
+  Label index_out_of_range;
+  Label done;
+  StringCharCodeAtGenerator generator(object,
+                                      index,
+                                      result,
+                                      &need_conversion,
+                                      &need_conversion,
+                                      &index_out_of_range,
+                                      STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm_);
+  __ B(&done);
+
+  __ Bind(&index_out_of_range);
+  // When the index is out of range, the spec requires us to return NaN.
+  __ LoadRoot(result, Heap::kNanValueRootIndex);
+  __ B(&done);
+
+  __ Bind(&need_conversion);
+  // Load the undefined value into the result register, which will
+  // trigger conversion.
+  __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+  __ B(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ Bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  Register object = x1;
+  Register index = x0;
+  Register result = x0;
+
+  __ Pop(object);
+
+  Label need_conversion;
+  Label index_out_of_range;
+  Label done;
+  StringCharAtGenerator generator(object,
+                                  index,
+                                  x3,
+                                  result,
+                                  &need_conversion,
+                                  &need_conversion,
+                                  &index_out_of_range,
+                                  STRING_INDEX_IS_NUMBER);
+  generator.GenerateFast(masm_);
+  __ B(&done);
+
+  __ Bind(&index_out_of_range);
+  // When the index is out of range, the spec requires us to return
+  // the empty string.
+  __ LoadRoot(result, Heap::kempty_stringRootIndex);
+  __ B(&done);
+
+  __ Bind(&need_conversion);
+  // Move smi zero into the result register, which will trigger conversion.
+  __ Mov(result, Smi::FromInt(0));
+  __ B(&done);
+
+  NopRuntimeCallHelper call_helper;
+  generator.GenerateSlow(masm_, call_helper);
+
+  __ Bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitStringAdd");
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+
+  VisitForStackValue(args->at(0));
+  VisitForAccumulatorValue(args->at(1));
+
+  __ Pop(x1);
+  StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
+  __ CallStub(&stub);
+
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+
+  StringCompareStub stub(isolate());
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitCallFunction");
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() >= 2);
+
+  int arg_count = args->length() - 2;  // 2 ~ receiver and function.
+  for (int i = 0; i < arg_count + 1; i++) {
+    VisitForStackValue(args->at(i));
+  }
+  VisitForAccumulatorValue(args->last());  // Function.
+
+  Label runtime, done;
+  // Check for non-function argument (including proxy).
+  __ JumpIfSmi(x0, &runtime);
+  __ JumpIfNotObjectType(x0, x1, x1, JS_FUNCTION_TYPE, &runtime);
+
+  // InvokeFunction requires the function in x1. Move it in there.
+  __ Mov(x1, x0);
+  ParameterCount count(arg_count);
+  __ InvokeFunction(x1, count, CALL_FUNCTION, NullCallWrapper());
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ B(&done);
+
+  __ Bind(&runtime);
+  __ Push(x0);
+  __ CallRuntime(Runtime::kCall, args->length());
+  __ Bind(&done);
+
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
+  RegExpConstructResultStub stub(isolate());
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 3);
+  VisitForStackValue(args->at(0));
+  VisitForStackValue(args->at(1));
+  VisitForAccumulatorValue(args->at(2));
+  __ Pop(x1, x2);
+  __ CallStub(&stub);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK_EQ(2, args->length());
+  DCHECK_NE(NULL, args->at(0)->AsLiteral());
+  int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
+
+  Handle<FixedArray> jsfunction_result_caches(
+      isolate()->native_context()->jsfunction_result_caches());
+  if (jsfunction_result_caches->length() <= cache_id) {
+    __ Abort(kAttemptToUseUndefinedCache);
+    __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
+    context()->Plug(x0);
+    return;
+  }
+
+  VisitForAccumulatorValue(args->at(1));
+
+  Register key = x0;
+  Register cache = x1;
+  __ Ldr(cache, GlobalObjectMemOperand());
+  __ Ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
+  __ Ldr(cache, ContextMemOperand(cache,
+                                  Context::JSFUNCTION_RESULT_CACHES_INDEX));
+  __ Ldr(cache,
+         FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
+
+  Label done;
+  __ Ldrsw(x2, UntagSmiFieldMemOperand(cache,
+                                       JSFunctionResultCache::kFingerOffset));
+  __ Add(x3, cache, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Add(x3, x3, Operand(x2, LSL, kPointerSizeLog2));
+
+  // Load the key and data from the cache.
+  __ Ldp(x2, x3, MemOperand(x3));
+
+  __ Cmp(key, x2);
+  __ CmovX(x0, x3, eq);
+  __ B(eq, &done);
+
+  // Call runtime to perform the lookup.
+  __ Push(cache, key);
+  __ CallRuntime(Runtime::kGetFromCache, 2);
+
+  __ Bind(&done);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  VisitForAccumulatorValue(args->at(0));
+
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  __ Ldr(x10, FieldMemOperand(x0, String::kHashFieldOffset));
+  __ Tst(x10, String::kContainsCachedArrayIndexMask);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+  Split(eq, if_true, if_false, fall_through);
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 1);
+  VisitForAccumulatorValue(args->at(0));
+
+  __ AssertString(x0);
+
+  __ Ldr(x10, FieldMemOperand(x0, String::kHashFieldOffset));
+  __ IndexFromHash(x10, x0);
+
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) {
+  ASM_LOCATION("FullCodeGenerator::EmitFastOneByteArrayJoin");
+
+  ZoneList<Expression*>* args = expr->arguments();
+  DCHECK(args->length() == 2);
+  VisitForStackValue(args->at(1));
+  VisitForAccumulatorValue(args->at(0));
+
+  Register array = x0;
+  Register result = x0;
+  Register elements = x1;
+  Register element = x2;
+  Register separator = x3;
+  Register array_length = x4;
+  Register result_pos = x5;
+  Register map = x6;
+  Register string_length = x10;
+  Register elements_end = x11;
+  Register string = x12;
+  Register scratch1 = x13;
+  Register scratch2 = x14;
+  Register scratch3 = x7;
+  Register separator_length = x15;
+
+  Label bailout, done, one_char_separator, long_separator,
+      non_trivial_array, not_size_one_array, loop,
+      empty_separator_loop, one_char_separator_loop,
+      one_char_separator_loop_entry, long_separator_loop;
+
+  // The separator operand is on the stack.
+  __ Pop(separator);
+
+  // Check that the array is a JSArray.
+  __ JumpIfSmi(array, &bailout);
+  __ JumpIfNotObjectType(array, map, scratch1, JS_ARRAY_TYPE, &bailout);
+
+  // Check that the array has fast elements.
+  __ CheckFastElements(map, scratch1, &bailout);
+
+  // If the array has length zero, return the empty string.
+  // Load and untag the length of the array.
+  // It is an unsigned value, so we can skip sign extension.
+  // We assume little endianness.
+  __ Ldrsw(array_length,
+           UntagSmiFieldMemOperand(array, JSArray::kLengthOffset));
+  __ Cbnz(array_length, &non_trivial_array);
+  __ LoadRoot(result, Heap::kempty_stringRootIndex);
+  __ B(&done);
+
+  __ Bind(&non_trivial_array);
+  // Get the FixedArray containing array's elements.
+  __ Ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
+
+  // Check that all array elements are sequential one-byte strings, and
+  // accumulate the sum of their lengths.
+  __ Mov(string_length, 0);
+  __ Add(element, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
+  // Loop condition: while (element < elements_end).
+  // Live values in registers:
+  //   elements: Fixed array of strings.
+  //   array_length: Length of the fixed array of strings (not smi)
+  //   separator: Separator string
+  //   string_length: Accumulated sum of string lengths (not smi).
+  //   element: Current array element.
+  //   elements_end: Array end.
+  if (FLAG_debug_code) {
+    __ Cmp(array_length, 0);
+    __ Assert(gt, kNoEmptyArraysHereInEmitFastOneByteArrayJoin);
+  }
+  __ Bind(&loop);
+  __ Ldr(string, MemOperand(element, kPointerSize, PostIndex));
+  __ JumpIfSmi(string, &bailout);
+  __ Ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
+  __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
+  __ Ldrsw(scratch1,
+           UntagSmiFieldMemOperand(string, SeqOneByteString::kLengthOffset));
+  __ Adds(string_length, string_length, scratch1);
+  __ B(vs, &bailout);
+  __ Cmp(element, elements_end);
+  __ B(lt, &loop);
+
+  // If array_length is 1, return elements[0], a string.
+  __ Cmp(array_length, 1);
+  __ B(ne, &not_size_one_array);
+  __ Ldr(result, FieldMemOperand(elements, FixedArray::kHeaderSize));
+  __ B(&done);
+
+  __ Bind(&not_size_one_array);
+
+  // Live values in registers:
+  //   separator: Separator string
+  //   array_length: Length of the array (not smi).
+  //   string_length: Sum of string lengths (not smi).
+  //   elements: FixedArray of strings.
+
+  // Check that the separator is a flat one-byte string.
+  __ JumpIfSmi(separator, &bailout);
+  __ Ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
+  __ Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  __ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
+
+  // Add (separator length times array_length) - separator length to the
+  // string_length to get the length of the result string.
+  // Load the separator length as untagged.
+  // We assume little endianness, and that the length is positive.
+  __ Ldrsw(separator_length,
+           UntagSmiFieldMemOperand(separator,
+                                   SeqOneByteString::kLengthOffset));
+  __ Sub(string_length, string_length, separator_length);
+  __ Umaddl(string_length, array_length.W(), separator_length.W(),
+            string_length);
+
+  // Get first element in the array.
+  __ Add(element, elements, FixedArray::kHeaderSize - kHeapObjectTag);
+  // Live values in registers:
+  //   element: First array element
+  //   separator: Separator string
+  //   string_length: Length of result string (not smi)
+  //   array_length: Length of the array (not smi).
+  __ AllocateOneByteString(result, string_length, scratch1, scratch2, scratch3,
+                           &bailout);
+
+  // Prepare for looping. Set up elements_end to end of the array. Set
+  // result_pos to the position of the result where to write the first
+  // character.
+  // TODO(all): useless unless AllocateOneByteString trashes the register.
+  __ Add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
+  __ Add(result_pos, result, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+
+  // Check the length of the separator.
+  __ Cmp(separator_length, 1);
+  __ B(eq, &one_char_separator);
+  __ B(gt, &long_separator);
+
+  // Empty separator case
+  __ Bind(&empty_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+
+  // Copy next array element to the result.
+  __ Ldr(string, MemOperand(element, kPointerSize, PostIndex));
+  __ Ldrsw(string_length,
+           UntagSmiFieldMemOperand(string, String::kLengthOffset));
+  __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ CopyBytes(result_pos, string, string_length, scratch1);
+  __ Cmp(element, elements_end);
+  __ B(lt, &empty_separator_loop);  // End while (element < elements_end).
+  __ B(&done);
+
+  // One-character separator case
+  __ Bind(&one_char_separator);
+  // Replace separator with its one-byte character value.
+  __ Ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize));
+  // Jump into the loop after the code that copies the separator, so the first
+  // element is not preceded by a separator
+  __ B(&one_char_separator_loop_entry);
+
+  __ Bind(&one_char_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+  //   separator: Single separator one-byte char (in lower byte).
+
+  // Copy the separator character to the result.
+  __ Strb(separator, MemOperand(result_pos, 1, PostIndex));
+
+  // Copy next array element to the result.
+  __ Bind(&one_char_separator_loop_entry);
+  __ Ldr(string, MemOperand(element, kPointerSize, PostIndex));
+  __ Ldrsw(string_length,
+           UntagSmiFieldMemOperand(string, String::kLengthOffset));
+  __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ CopyBytes(result_pos, string, string_length, scratch1);
+  __ Cmp(element, elements_end);
+  __ B(lt, &one_char_separator_loop);  // End while (element < elements_end).
+  __ B(&done);
+
+  // Long separator case (separator is more than one character). Entry is at the
+  // label long_separator below.
+  __ Bind(&long_separator_loop);
+  // Live values in registers:
+  //   result_pos: the position to which we are currently copying characters.
+  //   element: Current array element.
+  //   elements_end: Array end.
+  //   separator: Separator string.
+
+  // Copy the separator to the result.
+  // TODO(all): hoist next two instructions.
+  __ Ldrsw(string_length,
+           UntagSmiFieldMemOperand(separator, String::kLengthOffset));
+  __ Add(string, separator, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ CopyBytes(result_pos, string, string_length, scratch1);
+
+  __ Bind(&long_separator);
+  __ Ldr(string, MemOperand(element, kPointerSize, PostIndex));
+  __ Ldrsw(string_length,
+           UntagSmiFieldMemOperand(string, String::kLengthOffset));
+  __ Add(string, string, SeqOneByteString::kHeaderSize - kHeapObjectTag);
+  __ CopyBytes(result_pos, string, string_length, scratch1);
+  __ Cmp(element, elements_end);
+  __ B(lt, &long_separator_loop);  // End while (element < elements_end).
+  __ B(&done);
+
+  __ Bind(&bailout);
+  // Returning undefined will force slower code to handle it.
+  __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+  __ Bind(&done);
+  context()->Plug(result);
+}
+
+
+void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
+  DCHECK(expr->arguments()->length() == 0);
+  ExternalReference debug_is_active =
+      ExternalReference::debug_is_active_address(isolate());
+  __ Mov(x10, debug_is_active);
+  __ Ldrb(x0, MemOperand(x10));
+  __ SmiTag(x0);
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
+  if (expr->function() != NULL &&
+      expr->function()->intrinsic_type == Runtime::INLINE) {
+    Comment cmnt(masm_, "[ InlineRuntimeCall");
+    EmitInlineRuntimeCall(expr);
+    return;
+  }
+
+  Comment cmnt(masm_, "[ CallRunTime");
+  ZoneList<Expression*>* args = expr->arguments();
+  int arg_count = args->length();
+
+  if (expr->is_jsruntime()) {
+    // Push the builtins object as the receiver.
+    __ Ldr(x10, GlobalObjectMemOperand());
+    __ Ldr(LoadDescriptor::ReceiverRegister(),
+           FieldMemOperand(x10, GlobalObject::kBuiltinsOffset));
+    __ Push(LoadDescriptor::ReceiverRegister());
+
+    // Load the function from the receiver.
+    Handle<String> name = expr->name();
+    __ Mov(LoadDescriptor::NameRegister(), Operand(name));
+    if (FLAG_vector_ics) {
+      __ Mov(VectorLoadICDescriptor::SlotRegister(),
+             Smi::FromInt(expr->CallRuntimeFeedbackSlot()));
+      CallLoadIC(NOT_CONTEXTUAL);
+    } else {
+      CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
+    }
+
+    // Push the target function under the receiver.
+    __ Pop(x10);
+    __ Push(x0, x10);
+
+    int arg_count = args->length();
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+
+    // Record source position of the IC call.
+    SetSourcePosition(expr->position());
+    CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
+    __ Peek(x1, (arg_count + 1) * kPointerSize);
+    __ CallStub(&stub);
+
+    // Restore context register.
+    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+    context()->DropAndPlug(1, x0);
+  } else {
+    // Push the arguments ("left-to-right").
+    for (int i = 0; i < arg_count; i++) {
+      VisitForStackValue(args->at(i));
+    }
+
+    // Call the C runtime function.
+    __ CallRuntime(expr->function(), arg_count);
+    context()->Plug(x0);
+  }
+}
+
+
+void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
+  switch (expr->op()) {
+    case Token::DELETE: {
+      Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
+      Property* property = expr->expression()->AsProperty();
+      VariableProxy* proxy = expr->expression()->AsVariableProxy();
+
+      if (property != NULL) {
+        VisitForStackValue(property->obj());
+        VisitForStackValue(property->key());
+        __ Mov(x10, Smi::FromInt(strict_mode()));
+        __ Push(x10);
+        __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+        context()->Plug(x0);
+      } else if (proxy != NULL) {
+        Variable* var = proxy->var();
+        // Delete of an unqualified identifier is disallowed in strict mode
+        // but "delete this" is allowed.
+        DCHECK(strict_mode() == SLOPPY || var->is_this());
+        if (var->IsUnallocated()) {
+          __ Ldr(x12, GlobalObjectMemOperand());
+          __ Mov(x11, Operand(var->name()));
+          __ Mov(x10, Smi::FromInt(SLOPPY));
+          __ Push(x12, x11, x10);
+          __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
+          context()->Plug(x0);
+        } else if (var->IsStackAllocated() || var->IsContextSlot()) {
+          // Result of deleting non-global, non-dynamic variables is false.
+          // The subexpression does not have side effects.
+          context()->Plug(var->is_this());
+        } else {
+          // Non-global variable.  Call the runtime to try to delete from the
+          // context where the variable was introduced.
+          __ Mov(x2, Operand(var->name()));
+          __ Push(context_register(), x2);
+          __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
+          context()->Plug(x0);
+        }
+      } else {
+        // Result of deleting non-property, non-variable reference is true.
+        // The subexpression may have side effects.
+        VisitForEffect(expr->expression());
+        context()->Plug(true);
+      }
+      break;
+      break;
+    }
+    case Token::VOID: {
+      Comment cmnt(masm_, "[ UnaryOperation (VOID)");
+      VisitForEffect(expr->expression());
+      context()->Plug(Heap::kUndefinedValueRootIndex);
+      break;
+    }
+    case Token::NOT: {
+      Comment cmnt(masm_, "[ UnaryOperation (NOT)");
+      if (context()->IsEffect()) {
+        // Unary NOT has no side effects so it's only necessary to visit the
+        // subexpression.  Match the optimizing compiler by not branching.
+        VisitForEffect(expr->expression());
+      } else if (context()->IsTest()) {
+        const TestContext* test = TestContext::cast(context());
+        // The labels are swapped for the recursive call.
+        VisitForControl(expr->expression(),
+                        test->false_label(),
+                        test->true_label(),
+                        test->fall_through());
+        context()->Plug(test->true_label(), test->false_label());
+      } else {
+        DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
+        // TODO(jbramley): This could be much more efficient using (for
+        // example) the CSEL instruction.
+        Label materialize_true, materialize_false, done;
+        VisitForControl(expr->expression(),
+                        &materialize_false,
+                        &materialize_true,
+                        &materialize_true);
+
+        __ Bind(&materialize_true);
+        PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
+        __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
+        __ B(&done);
+
+        __ Bind(&materialize_false);
+        PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
+        __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
+        __ B(&done);
+
+        __ Bind(&done);
+        if (context()->IsStackValue()) {
+          __ Push(result_register());
+        }
+      }
+      break;
+    }
+    case Token::TYPEOF: {
+      Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
+      {
+        StackValueContext context(this);
+        VisitForTypeofValue(expr->expression());
+      }
+      __ CallRuntime(Runtime::kTypeof, 1);
+      context()->Plug(x0);
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
+  DCHECK(expr->expression()->IsValidReferenceExpression());
+
+  Comment cmnt(masm_, "[ CountOperation");
+  SetSourcePosition(expr->position());
+
+  // Expression can only be a property, a global or a (parameter or local)
+  // slot.
+  enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
+  LhsKind assign_type = VARIABLE;
+  Property* prop = expr->expression()->AsProperty();
+  // In case of a property we use the uninitialized expression context
+  // of the key to detect a named property.
+  if (prop != NULL) {
+    assign_type =
+        (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
+  }
+
+  // Evaluate expression and get value.
+  if (assign_type == VARIABLE) {
+    DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
+    AccumulatorValueContext context(this);
+    EmitVariableLoad(expr->expression()->AsVariableProxy());
+  } else {
+    // Reserve space for result of postfix operation.
+    if (expr->is_postfix() && !context()->IsEffect()) {
+      __ Push(xzr);
+    }
+    if (assign_type == NAMED_PROPERTY) {
+      // Put the object both on the stack and in the register.
+      VisitForStackValue(prop->obj());
+      __ Peek(LoadDescriptor::ReceiverRegister(), 0);
+      EmitNamedPropertyLoad(prop);
+    } else {
+      // KEYED_PROPERTY
+      VisitForStackValue(prop->obj());
+      VisitForStackValue(prop->key());
+      __ Peek(LoadDescriptor::ReceiverRegister(), 1 * kPointerSize);
+      __ Peek(LoadDescriptor::NameRegister(), 0);
+      EmitKeyedPropertyLoad(prop);
+    }
+  }
+
+  // We need a second deoptimization point after loading the value
+  // in case evaluating the property load my have a side effect.
+  if (assign_type == VARIABLE) {
+    PrepareForBailout(expr->expression(), TOS_REG);
+  } else {
+    PrepareForBailoutForId(prop->LoadId(), TOS_REG);
+  }
+
+  // Inline smi case if we are in a loop.
+  Label stub_call, done;
+  JumpPatchSite patch_site(masm_);
+
+  int count_value = expr->op() == Token::INC ? 1 : -1;
+  if (ShouldInlineSmiCase(expr->op())) {
+    Label slow;
+    patch_site.EmitJumpIfNotSmi(x0, &slow);
+
+    // Save result for postfix expressions.
+    if (expr->is_postfix()) {
+      if (!context()->IsEffect()) {
+        // Save the result on the stack. If we have a named or keyed property we
+        // store the result under the receiver that is currently on top of the
+        // stack.
+        switch (assign_type) {
+          case VARIABLE:
+            __ Push(x0);
+            break;
+          case NAMED_PROPERTY:
+            __ Poke(x0, kPointerSize);
+            break;
+          case KEYED_PROPERTY:
+            __ Poke(x0, kPointerSize * 2);
+            break;
+        }
+      }
+    }
+
+    __ Adds(x0, x0, Smi::FromInt(count_value));
+    __ B(vc, &done);
+    // Call stub. Undo operation first.
+    __ Sub(x0, x0, Smi::FromInt(count_value));
+    __ B(&stub_call);
+    __ Bind(&slow);
+  }
+  ToNumberStub convert_stub(isolate());
+  __ CallStub(&convert_stub);
+
+  // Save result for postfix expressions.
+  if (expr->is_postfix()) {
+    if (!context()->IsEffect()) {
+      // Save the result on the stack. If we have a named or keyed property
+      // we store the result under the receiver that is currently on top
+      // of the stack.
+      switch (assign_type) {
+        case VARIABLE:
+          __ Push(x0);
+          break;
+        case NAMED_PROPERTY:
+          __ Poke(x0, kXRegSize);
+          break;
+        case KEYED_PROPERTY:
+          __ Poke(x0, 2 * kXRegSize);
+          break;
+      }
+    }
+  }
+
+  __ Bind(&stub_call);
+  __ Mov(x1, x0);
+  __ Mov(x0, Smi::FromInt(count_value));
+
+  // Record position before stub call.
+  SetSourcePosition(expr->position());
+
+  {
+    Assembler::BlockPoolsScope scope(masm_);
+    Handle<Code> code =
+        CodeFactory::BinaryOpIC(isolate(), Token::ADD, NO_OVERWRITE).code();
+    CallIC(code, expr->CountBinOpFeedbackId());
+    patch_site.EmitPatchInfo();
+  }
+  __ Bind(&done);
+
+  // Store the value returned in x0.
+  switch (assign_type) {
+    case VARIABLE:
+      if (expr->is_postfix()) {
+        { EffectContext context(this);
+          EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                                 Token::ASSIGN);
+          PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+          context.Plug(x0);
+        }
+        // For all contexts except EffectConstant We have the result on
+        // top of the stack.
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
+                               Token::ASSIGN);
+        PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+        context()->Plug(x0);
+      }
+      break;
+    case NAMED_PROPERTY: {
+      __ Mov(StoreDescriptor::NameRegister(),
+             Operand(prop->key()->AsLiteral()->value()));
+      __ Pop(StoreDescriptor::ReceiverRegister());
+      CallStoreIC(expr->CountStoreFeedbackId());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(x0);
+      }
+      break;
+    }
+    case KEYED_PROPERTY: {
+      __ Pop(StoreDescriptor::NameRegister());
+      __ Pop(StoreDescriptor::ReceiverRegister());
+      Handle<Code> ic =
+          CodeFactory::KeyedStoreIC(isolate(), strict_mode()).code();
+      CallIC(ic, expr->CountStoreFeedbackId());
+      PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
+      if (expr->is_postfix()) {
+        if (!context()->IsEffect()) {
+          context()->PlugTOS();
+        }
+      } else {
+        context()->Plug(x0);
+      }
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
+  DCHECK(!context()->IsEffect());
+  DCHECK(!context()->IsTest());
+  VariableProxy* proxy = expr->AsVariableProxy();
+  if (proxy != NULL && proxy->var()->IsUnallocated()) {
+    Comment cmnt(masm_, "Global variable");
+    __ Ldr(LoadDescriptor::ReceiverRegister(), GlobalObjectMemOperand());
+    __ Mov(LoadDescriptor::NameRegister(), Operand(proxy->name()));
+    if (FLAG_vector_ics) {
+      __ Mov(VectorLoadICDescriptor::SlotRegister(),
+             Smi::FromInt(proxy->VariableFeedbackSlot()));
+    }
+    // Use a regular load, not a contextual load, to avoid a reference
+    // error.
+    CallLoadIC(NOT_CONTEXTUAL);
+    PrepareForBailout(expr, TOS_REG);
+    context()->Plug(x0);
+  } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
+    Label done, slow;
+
+    // Generate code for loading from variables potentially shadowed
+    // by eval-introduced variables.
+    EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
+
+    __ Bind(&slow);
+    __ Mov(x0, Operand(proxy->name()));
+    __ Push(cp, x0);
+    __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
+    PrepareForBailout(expr, TOS_REG);
+    __ Bind(&done);
+
+    context()->Plug(x0);
+  } else {
+    // This expression cannot throw a reference error at the top level.
+    VisitInDuplicateContext(expr);
+  }
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
+                                                 Expression* sub_expr,
+                                                 Handle<String> check) {
+  ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof");
+  Comment cmnt(masm_, "[ EmitLiteralCompareTypeof");
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  { AccumulatorValueContext context(this);
+    VisitForTypeofValue(sub_expr);
+  }
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+
+  Factory* factory = isolate()->factory();
+  if (String::Equals(check, factory->number_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof number_string");
+    __ JumpIfSmi(x0, if_true);
+    __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset));
+    __ CompareRoot(x0, Heap::kHeapNumberMapRootIndex);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->string_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof string_string");
+    __ JumpIfSmi(x0, if_false);
+    // Check for undetectable objects => false.
+    __ JumpIfObjectType(x0, x0, x1, FIRST_NONSTRING_TYPE, if_false, ge);
+    __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset));
+    __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_true, if_false,
+                    fall_through);
+  } else if (String::Equals(check, factory->symbol_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof symbol_string");
+    __ JumpIfSmi(x0, if_false);
+    __ CompareObjectType(x0, x0, x1, SYMBOL_TYPE);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->boolean_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof boolean_string");
+    __ JumpIfRoot(x0, Heap::kTrueValueRootIndex, if_true);
+    __ CompareRoot(x0, Heap::kFalseValueRootIndex);
+    Split(eq, if_true, if_false, fall_through);
+  } else if (String::Equals(check, factory->undefined_string())) {
+    ASM_LOCATION(
+        "FullCodeGenerator::EmitLiteralCompareTypeof undefined_string");
+    __ JumpIfRoot(x0, Heap::kUndefinedValueRootIndex, if_true);
+    __ JumpIfSmi(x0, if_false);
+    // Check for undetectable objects => true.
+    __ Ldr(x0, FieldMemOperand(x0, HeapObject::kMapOffset));
+    __ Ldrb(x1, FieldMemOperand(x0, Map::kBitFieldOffset));
+    __ TestAndSplit(x1, 1 << Map::kIsUndetectable, if_false, if_true,
+                    fall_through);
+  } else if (String::Equals(check, factory->function_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof function_string");
+    __ JumpIfSmi(x0, if_false);
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    __ JumpIfObjectType(x0, x10, x11, JS_FUNCTION_TYPE, if_true);
+    __ CompareAndSplit(x11, JS_FUNCTION_PROXY_TYPE, eq, if_true, if_false,
+                       fall_through);
+
+  } else if (String::Equals(check, factory->object_string())) {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof object_string");
+    __ JumpIfSmi(x0, if_false);
+    __ JumpIfRoot(x0, Heap::kNullValueRootIndex, if_true);
+    // Check for JS objects => true.
+    Register map = x10;
+    __ JumpIfObjectType(x0, map, x11, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE,
+                        if_false, lt);
+    __ CompareInstanceType(map, x11, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
+    __ B(gt, if_false);
+    // Check for undetectable objects => false.
+    __ Ldrb(x10, FieldMemOperand(map, Map::kBitFieldOffset));
+
+    __ TestAndSplit(x10, 1 << Map::kIsUndetectable, if_true, if_false,
+                    fall_through);
+
+  } else {
+    ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareTypeof other");
+    if (if_false != fall_through) __ B(if_false);
+  }
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
+  Comment cmnt(masm_, "[ CompareOperation");
+  SetSourcePosition(expr->position());
+
+  // Try to generate an optimized comparison with a literal value.
+  // TODO(jbramley): This only checks common values like NaN or undefined.
+  // Should it also handle ARM64 immediate operands?
+  if (TryLiteralCompare(expr)) {
+    return;
+  }
+
+  // Assign labels according to context()->PrepareTest.
+  Label materialize_true;
+  Label materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  Token::Value op = expr->op();
+  VisitForStackValue(expr->left());
+  switch (op) {
+    case Token::IN:
+      VisitForStackValue(expr->right());
+      __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
+      PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
+      __ CompareRoot(x0, Heap::kTrueValueRootIndex);
+      Split(eq, if_true, if_false, fall_through);
+      break;
+
+    case Token::INSTANCEOF: {
+      VisitForStackValue(expr->right());
+      InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
+      __ CallStub(&stub);
+      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+      // The stub returns 0 for true.
+      __ CompareAndSplit(x0, 0, eq, if_true, if_false, fall_through);
+      break;
+    }
+
+    default: {
+      VisitForAccumulatorValue(expr->right());
+      Condition cond = CompareIC::ComputeCondition(op);
+
+      // Pop the stack value.
+      __ Pop(x1);
+
+      JumpPatchSite patch_site(masm_);
+      if (ShouldInlineSmiCase(op)) {
+        Label slow_case;
+        patch_site.EmitJumpIfEitherNotSmi(x0, x1, &slow_case);
+        __ Cmp(x1, x0);
+        Split(cond, if_true, if_false, NULL);
+        __ Bind(&slow_case);
+      }
+
+      // Record position and call the compare IC.
+      SetSourcePosition(expr->position());
+      Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+      CallIC(ic, expr->CompareOperationFeedbackId());
+      patch_site.EmitPatchInfo();
+      PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+      __ CompareAndSplit(x0, 0, cond, if_true, if_false, fall_through);
+    }
+  }
+
+  // Convert the result of the comparison into one expected for this
+  // expression's context.
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
+                                              Expression* sub_expr,
+                                              NilValue nil) {
+  ASM_LOCATION("FullCodeGenerator::EmitLiteralCompareNil");
+  Label materialize_true, materialize_false;
+  Label* if_true = NULL;
+  Label* if_false = NULL;
+  Label* fall_through = NULL;
+  context()->PrepareTest(&materialize_true, &materialize_false,
+                         &if_true, &if_false, &fall_through);
+
+  VisitForAccumulatorValue(sub_expr);
+  PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
+
+  if (expr->op() == Token::EQ_STRICT) {
+    Heap::RootListIndex nil_value = nil == kNullValue ?
+        Heap::kNullValueRootIndex :
+        Heap::kUndefinedValueRootIndex;
+    __ CompareRoot(x0, nil_value);
+    Split(eq, if_true, if_false, fall_through);
+  } else {
+    Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
+    CallIC(ic, expr->CompareOperationFeedbackId());
+    __ CompareAndSplit(x0, 0, ne, if_true, if_false, fall_through);
+  }
+
+  context()->Plug(if_true, if_false);
+}
+
+
+void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
+  __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+  context()->Plug(x0);
+}
+
+
+void FullCodeGenerator::VisitYield(Yield* expr) {
+  Comment cmnt(masm_, "[ Yield");
+  // Evaluate yielded value first; the initial iterator definition depends on
+  // this. It stays on the stack while we update the iterator.
+  VisitForStackValue(expr->expression());
+
+  // TODO(jbramley): Tidy this up once the merge is done, using named registers
+  // and suchlike. The implementation changes a little by bleeding_edge so I
+  // don't want to spend too much time on it now.
+
+  switch (expr->yield_kind()) {
+    case Yield::kSuspend:
+      // Pop value from top-of-stack slot; box result into result register.
+      EmitCreateIteratorResult(false);
+      __ Push(result_register());
+      // Fall through.
+    case Yield::kInitial: {
+      Label suspend, continuation, post_runtime, resume;
+
+      __ B(&suspend);
+
+      // TODO(jbramley): This label is bound here because the following code
+      // looks at its pos(). Is it possible to do something more efficient here,
+      // perhaps using Adr?
+      __ Bind(&continuation);
+      __ B(&resume);
+
+      __ Bind(&suspend);
+      VisitForAccumulatorValue(expr->generator_object());
+      DCHECK((continuation.pos() > 0) && Smi::IsValid(continuation.pos()));
+      __ Mov(x1, Smi::FromInt(continuation.pos()));
+      __ Str(x1, FieldMemOperand(x0, JSGeneratorObject::kContinuationOffset));
+      __ Str(cp, FieldMemOperand(x0, JSGeneratorObject::kContextOffset));
+      __ Mov(x1, cp);
+      __ RecordWriteField(x0, JSGeneratorObject::kContextOffset, x1, x2,
+                          kLRHasBeenSaved, kDontSaveFPRegs);
+      __ Add(x1, fp, StandardFrameConstants::kExpressionsOffset);
+      __ Cmp(__ StackPointer(), x1);
+      __ B(eq, &post_runtime);
+      __ Push(x0);  // generator object
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ Bind(&post_runtime);
+      __ Pop(result_register());
+      EmitReturnSequence();
+
+      __ Bind(&resume);
+      context()->Plug(result_register());
+      break;
+    }
+
+    case Yield::kFinal: {
+      VisitForAccumulatorValue(expr->generator_object());
+      __ Mov(x1, Smi::FromInt(JSGeneratorObject::kGeneratorClosed));
+      __ Str(x1, FieldMemOperand(result_register(),
+                                 JSGeneratorObject::kContinuationOffset));
+      // Pop value from top-of-stack slot, box result into result register.
+      EmitCreateIteratorResult(true);
+      EmitUnwindBeforeReturn();
+      EmitReturnSequence();
+      break;
+    }
+
+    case Yield::kDelegating: {
+      VisitForStackValue(expr->generator_object());
+
+      // Initial stack layout is as follows:
+      // [sp + 1 * kPointerSize] iter
+      // [sp + 0 * kPointerSize] g
+
+      Label l_catch, l_try, l_suspend, l_continuation, l_resume;
+      Label l_next, l_call, l_loop;
+      Register load_receiver = LoadDescriptor::ReceiverRegister();
+      Register load_name = LoadDescriptor::NameRegister();
+
+      // Initial send value is undefined.
+      __ LoadRoot(x0, Heap::kUndefinedValueRootIndex);
+      __ B(&l_next);
+
+      // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
+      __ Bind(&l_catch);
+      handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
+      __ LoadRoot(load_name, Heap::kthrow_stringRootIndex);  // "throw"
+      __ Peek(x3, 1 * kPointerSize);                         // iter
+      __ Push(load_name, x3, x0);                       // "throw", iter, except
+      __ B(&l_call);
+
+      // try { received = %yield result }
+      // Shuffle the received result above a try handler and yield it without
+      // re-boxing.
+      __ Bind(&l_try);
+      __ Pop(x0);                                        // result
+      __ PushTryHandler(StackHandler::CATCH, expr->index());
+      const int handler_size = StackHandlerConstants::kSize;
+      __ Push(x0);                                       // result
+      __ B(&l_suspend);
+
+      // TODO(jbramley): This label is bound here because the following code
+      // looks at its pos(). Is it possible to do something more efficient here,
+      // perhaps using Adr?
+      __ Bind(&l_continuation);
+      __ B(&l_resume);
+
+      __ Bind(&l_suspend);
+      const int generator_object_depth = kPointerSize + handler_size;
+      __ Peek(x0, generator_object_depth);
+      __ Push(x0);                                       // g
+      DCHECK((l_continuation.pos() > 0) && Smi::IsValid(l_continuation.pos()));
+      __ Mov(x1, Smi::FromInt(l_continuation.pos()));
+      __ Str(x1, FieldMemOperand(x0, JSGeneratorObject::kContinuationOffset));
+      __ Str(cp, FieldMemOperand(x0, JSGeneratorObject::kContextOffset));
+      __ Mov(x1, cp);
+      __ RecordWriteField(x0, JSGeneratorObject::kContextOffset, x1, x2,
+                          kLRHasBeenSaved, kDontSaveFPRegs);
+      __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
+      __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ Pop(x0);                                        // result
+      EmitReturnSequence();
+      __ Bind(&l_resume);                                // received in x0
+      __ PopTryHandler();
+
+      // receiver = iter; f = 'next'; arg = received;
+      __ Bind(&l_next);
+
+      __ LoadRoot(load_name, Heap::knext_stringRootIndex);  // "next"
+      __ Peek(x3, 1 * kPointerSize);                        // iter
+      __ Push(load_name, x3, x0);                      // "next", iter, received
+
+      // result = receiver[f](arg);
+      __ Bind(&l_call);
+      __ Peek(load_receiver, 1 * kPointerSize);
+      __ Peek(load_name, 2 * kPointerSize);
+      if (FLAG_vector_ics) {
+        __ Mov(VectorLoadICDescriptor::SlotRegister(),
+               Smi::FromInt(expr->KeyedLoadFeedbackSlot()));
+      }
+      Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+      CallIC(ic, TypeFeedbackId::None());
+      __ Mov(x1, x0);
+      __ Poke(x1, 2 * kPointerSize);
+      CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
+      __ CallStub(&stub);
+
+      __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ Drop(1);  // The function is still on the stack; drop it.
+
+      // if (!result.done) goto l_try;
+      __ Bind(&l_loop);
+      __ Move(load_receiver, x0);
+
+      __ Push(load_receiver);                               // save result
+      __ LoadRoot(load_name, Heap::kdone_stringRootIndex);  // "done"
+      if (FLAG_vector_ics) {
+        __ Mov(VectorLoadICDescriptor::SlotRegister(),
+               Smi::FromInt(expr->DoneFeedbackSlot()));
+      }
+      CallLoadIC(NOT_CONTEXTUAL);                           // x0=result.done
+      // The ToBooleanStub argument (result.done) is in x0.
+      Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
+      CallIC(bool_ic);
+      __ Cbz(x0, &l_try);
+
+      // result.value
+      __ Pop(load_receiver);                                 // result
+      __ LoadRoot(load_name, Heap::kvalue_stringRootIndex);  // "value"
+      if (FLAG_vector_ics) {
+        __ Mov(VectorLoadICDescriptor::SlotRegister(),
+               Smi::FromInt(expr->ValueFeedbackSlot()));
+      }
+      CallLoadIC(NOT_CONTEXTUAL);                            // x0=result.value
+      context()->DropAndPlug(2, x0);                         // drop iter and g
+      break;
+    }
+  }
+}
+
+
+void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
+    Expression *value,
+    JSGeneratorObject::ResumeMode resume_mode) {
+  ASM_LOCATION("FullCodeGenerator::EmitGeneratorResume");
+  Register value_reg = x0;
+  Register generator_object = x1;
+  Register the_hole = x2;
+  Register operand_stack_size = w3;
+  Register function = x4;
+
+  // The value stays in x0, and is ultimately read by the resumed generator, as
+  // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
+  // is read to throw the value when the resumed generator is already closed. r1
+  // will hold the generator object until the activation has been resumed.
+  VisitForStackValue(generator);
+  VisitForAccumulatorValue(value);
+  __ Pop(generator_object);
+
+  // Check generator state.
+  Label wrong_state, closed_state, done;
+  __ Ldr(x10, FieldMemOperand(generator_object,
+                              JSGeneratorObject::kContinuationOffset));
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
+  STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
+  __ CompareAndBranch(x10, Smi::FromInt(0), eq, &closed_state);
+  __ CompareAndBranch(x10, Smi::FromInt(0), lt, &wrong_state);
+
+  // Load suspended function and context.
+  __ Ldr(cp, FieldMemOperand(generator_object,
+                             JSGeneratorObject::kContextOffset));
+  __ Ldr(function, FieldMemOperand(generator_object,
+                                   JSGeneratorObject::kFunctionOffset));
+
+  // Load receiver and store as the first argument.
+  __ Ldr(x10, FieldMemOperand(generator_object,
+                              JSGeneratorObject::kReceiverOffset));
+  __ Push(x10);
+
+  // Push holes for the rest of the arguments to the generator function.
+  __ Ldr(x10, FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+
+  // The number of arguments is stored as an int32_t, and -1 is a marker
+  // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign
+  // extension to correctly handle it. However, in this case, we operate on
+  // 32-bit W registers, so extension isn't required.
+  __ Ldr(w10, FieldMemOperand(x10,
+                              SharedFunctionInfo::kFormalParameterCountOffset));
+  __ LoadRoot(the_hole, Heap::kTheHoleValueRootIndex);
+  __ PushMultipleTimes(the_hole, w10);
+
+  // Enter a new JavaScript frame, and initialize its slots as they were when
+  // the generator was suspended.
+  Label resume_frame;
+  __ Bl(&resume_frame);
+  __ B(&done);
+
+  __ Bind(&resume_frame);
+  __ Push(lr,           // Return address.
+          fp,           // Caller's frame pointer.
+          cp,           // Callee's context.
+          function);    // Callee's JS Function.
+  __ Add(fp, __ StackPointer(), kPointerSize * 2);
+
+  // Load and untag the operand stack size.
+  __ Ldr(x10, FieldMemOperand(generator_object,
+                              JSGeneratorObject::kOperandStackOffset));
+  __ Ldr(operand_stack_size,
+         UntagSmiFieldMemOperand(x10, FixedArray::kLengthOffset));
+
+  // If we are sending a value and there is no operand stack, we can jump back
+  // in directly.
+  if (resume_mode == JSGeneratorObject::NEXT) {
+    Label slow_resume;
+    __ Cbnz(operand_stack_size, &slow_resume);
+    __ Ldr(x10, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+    __ Ldrsw(x11,
+             UntagSmiFieldMemOperand(generator_object,
+                                     JSGeneratorObject::kContinuationOffset));
+    __ Add(x10, x10, x11);
+    __ Mov(x12, Smi::FromInt(JSGeneratorObject::kGeneratorExecuting));
+    __ Str(x12, FieldMemOperand(generator_object,
+                                JSGeneratorObject::kContinuationOffset));
+    __ Br(x10);
+
+    __ Bind(&slow_resume);
+  }
+
+  // Otherwise, we push holes for the operand stack and call the runtime to fix
+  // up the stack and the handlers.
+  __ PushMultipleTimes(the_hole, operand_stack_size);
+
+  __ Mov(x10, Smi::FromInt(resume_mode));
+  __ Push(generator_object, result_register(), x10);
+  __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
+  // Not reached: the runtime call returns elsewhere.
+  __ Unreachable();
+
+  // Reach here when generator is closed.
+  __ Bind(&closed_state);
+  if (resume_mode == JSGeneratorObject::NEXT) {
+    // Return completed iterator result when generator is closed.
+    __ LoadRoot(x10, Heap::kUndefinedValueRootIndex);
+    __ Push(x10);
+    // Pop value from top-of-stack slot; box result into result register.
+    EmitCreateIteratorResult(true);
+  } else {
+    // Throw the provided value.
+    __ Push(value_reg);
+    __ CallRuntime(Runtime::kThrow, 1);
+  }
+  __ B(&done);
+
+  // Throw error if we attempt to operate on a running generator.
+  __ Bind(&wrong_state);
+  __ Push(generator_object);
+  __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
+
+  __ Bind(&done);
+  context()->Plug(result_register());
+}
+
+
+void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
+  Label gc_required;
+  Label allocated;
+
+  Handle<Map> map(isolate()->native_context()->iterator_result_map());
+
+  // Allocate and populate an object with this form: { value: VAL, done: DONE }
+
+  Register result = x0;
+  __ Allocate(map->instance_size(), result, x10, x11, &gc_required, TAG_OBJECT);
+  __ B(&allocated);
+
+  __ Bind(&gc_required);
+  __ Push(Smi::FromInt(map->instance_size()));
+  __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
+  __ Ldr(context_register(),
+         MemOperand(fp, StandardFrameConstants::kContextOffset));
+
+  __ Bind(&allocated);
+  Register map_reg = x1;
+  Register result_value = x2;
+  Register boolean_done = x3;
+  Register empty_fixed_array = x4;
+  Register untagged_result = x5;
+  __ Mov(map_reg, Operand(map));
+  __ Pop(result_value);
+  __ Mov(boolean_done, Operand(isolate()->factory()->ToBoolean(done)));
+  __ Mov(empty_fixed_array, Operand(isolate()->factory()->empty_fixed_array()));
+  DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
+  STATIC_ASSERT(JSObject::kPropertiesOffset + kPointerSize ==
+                JSObject::kElementsOffset);
+  STATIC_ASSERT(JSGeneratorObject::kResultValuePropertyOffset + kPointerSize ==
+                JSGeneratorObject::kResultDonePropertyOffset);
+  __ ObjectUntag(untagged_result, result);
+  __ Str(map_reg, MemOperand(untagged_result, HeapObject::kMapOffset));
+  __ Stp(empty_fixed_array, empty_fixed_array,
+         MemOperand(untagged_result, JSObject::kPropertiesOffset));
+  __ Stp(result_value, boolean_done,
+         MemOperand(untagged_result,
+                    JSGeneratorObject::kResultValuePropertyOffset));
+
+  // Only the value field needs a write barrier, as the other values are in the
+  // root set.
+  __ RecordWriteField(result, JSGeneratorObject::kResultValuePropertyOffset,
+                      x10, x11, kLRHasBeenSaved, kDontSaveFPRegs);
+}
+
+
+// TODO(all): I don't like this method.
+// It seems to me that in too many places x0 is used in place of this.
+// Also, this function is not suitable for all places where x0 should be
+// abstracted (eg. when used as an argument). But some places assume that the
+// first argument register is x0, and use this function instead.
+// Considering that most of the register allocation is hard-coded in the
+// FullCodeGen, that it is unlikely we will need to change it extensively, and
+// that abstracting the allocation through functions would not yield any
+// performance benefit, I think the existence of this function is debatable.
+Register FullCodeGenerator::result_register() {
+  return x0;
+}
+
+
+Register FullCodeGenerator::context_register() {
+  return cp;
+}
+
+
+void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
+  DCHECK(POINTER_SIZE_ALIGN(frame_offset) == frame_offset);
+  __ Str(value, MemOperand(fp, frame_offset));
+}
+
+
+void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
+  __ Ldr(dst, ContextMemOperand(cp, context_index));
+}
+
+
+void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
+  Scope* declaration_scope = scope()->DeclarationScope();
+  if (declaration_scope->is_global_scope() ||
+      declaration_scope->is_module_scope()) {
+    // Contexts nested in the native context have a canonical empty function
+    // as their closure, not the anonymous closure containing the global
+    // code.  Pass a smi sentinel and let the runtime look up the empty
+    // function.
+    DCHECK(kSmiTag == 0);
+    __ Push(xzr);
+  } else if (declaration_scope->is_eval_scope()) {
+    // Contexts created by a call to eval have the same closure as the
+    // context calling eval, not the anonymous closure containing the eval
+    // code.  Fetch it from the context.
+    __ Ldr(x10, ContextMemOperand(cp, Context::CLOSURE_INDEX));
+    __ Push(x10);
+  } else {
+    DCHECK(declaration_scope->is_function_scope());
+    __ Ldr(x10, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+    __ Push(x10);
+  }
+}
+
+
+void FullCodeGenerator::EnterFinallyBlock() {
+  ASM_LOCATION("FullCodeGenerator::EnterFinallyBlock");
+  DCHECK(!result_register().is(x10));
+  // Preserve the result register while executing finally block.
+  // Also cook the return address in lr to the stack (smi encoded Code* delta).
+  __ Sub(x10, lr, Operand(masm_->CodeObject()));
+  __ SmiTag(x10);
+  __ Push(result_register(), x10);
+
+  // Store pending message while executing finally block.
+  ExternalReference pending_message_obj =
+      ExternalReference::address_of_pending_message_obj(isolate());
+  __ Mov(x10, pending_message_obj);
+  __ Ldr(x10, MemOperand(x10));
+
+  ExternalReference has_pending_message =
+      ExternalReference::address_of_has_pending_message(isolate());
+  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
+  __ Mov(x11, has_pending_message);
+  __ Ldrb(x11, MemOperand(x11));
+  __ SmiTag(x11);
+
+  __ Push(x10, x11);
+
+  ExternalReference pending_message_script =
+      ExternalReference::address_of_pending_message_script(isolate());
+  __ Mov(x10, pending_message_script);
+  __ Ldr(x10, MemOperand(x10));
+  __ Push(x10);
+}
+
+
+void FullCodeGenerator::ExitFinallyBlock() {
+  ASM_LOCATION("FullCodeGenerator::ExitFinallyBlock");
+  DCHECK(!result_register().is(x10));
+
+  // Restore pending message from stack.
+  __ Pop(x10, x11, x12);
+  ExternalReference pending_message_script =
+      ExternalReference::address_of_pending_message_script(isolate());
+  __ Mov(x13, pending_message_script);
+  __ Str(x10, MemOperand(x13));
+
+  __ SmiUntag(x11);
+  ExternalReference has_pending_message =
+      ExternalReference::address_of_has_pending_message(isolate());
+  __ Mov(x13, has_pending_message);
+  STATIC_ASSERT(sizeof(bool) == 1);   // NOLINT(runtime/sizeof)
+  __ Strb(x11, MemOperand(x13));
+
+  ExternalReference pending_message_obj =
+      ExternalReference::address_of_pending_message_obj(isolate());
+  __ Mov(x13, pending_message_obj);
+  __ Str(x12, MemOperand(x13));
+
+  // Restore result register and cooked return address from the stack.
+  __ Pop(x10, result_register());
+
+  // Uncook the return address (see EnterFinallyBlock).
+  __ SmiUntag(x10);
+  __ Add(x11, x10, Operand(masm_->CodeObject()));
+  __ Br(x11);
+}
+
+
+#undef __
+
+
+void BackEdgeTable::PatchAt(Code* unoptimized_code,
+                            Address pc,
+                            BackEdgeState target_state,
+                            Code* replacement_code) {
+  // Turn the jump into a nop.
+  Address branch_address = pc - 3 * kInstructionSize;
+  PatchingAssembler patcher(branch_address, 1);
+
+  DCHECK(Instruction::Cast(branch_address)
+             ->IsNop(Assembler::INTERRUPT_CODE_NOP) ||
+         (Instruction::Cast(branch_address)->IsCondBranchImm() &&
+          Instruction::Cast(branch_address)->ImmPCOffset() ==
+              6 * kInstructionSize));
+
+  switch (target_state) {
+    case INTERRUPT:
+      //  <decrement profiling counter>
+      //  .. .. .. ..       b.pl ok
+      //  .. .. .. ..       ldr x16, pc+<interrupt stub address>
+      //  .. .. .. ..       blr x16
+      //  ... more instructions.
+      //  ok-label
+      // Jump offset is 6 instructions.
+      patcher.b(6, pl);
+      break;
+    case ON_STACK_REPLACEMENT:
+    case OSR_AFTER_STACK_CHECK:
+      //  <decrement profiling counter>
+      //  .. .. .. ..       mov x0, x0 (NOP)
+      //  .. .. .. ..       ldr x16, pc+<on-stack replacement address>
+      //  .. .. .. ..       blr x16
+      patcher.nop(Assembler::INTERRUPT_CODE_NOP);
+      break;
+  }
+
+  // Replace the call address.
+  Instruction* load = Instruction::Cast(pc)->preceding(2);
+  Address interrupt_address_pointer =
+      reinterpret_cast<Address>(load) + load->ImmPCOffset();
+  DCHECK((Memory::uint64_at(interrupt_address_pointer) ==
+          reinterpret_cast<uint64_t>(unoptimized_code->GetIsolate()
+                                         ->builtins()
+                                         ->OnStackReplacement()
+                                         ->entry())) ||
+         (Memory::uint64_at(interrupt_address_pointer) ==
+          reinterpret_cast<uint64_t>(unoptimized_code->GetIsolate()
+                                         ->builtins()
+                                         ->InterruptCheck()
+                                         ->entry())) ||
+         (Memory::uint64_at(interrupt_address_pointer) ==
+          reinterpret_cast<uint64_t>(unoptimized_code->GetIsolate()
+                                         ->builtins()
+                                         ->OsrAfterStackCheck()
+                                         ->entry())) ||
+         (Memory::uint64_at(interrupt_address_pointer) ==
+          reinterpret_cast<uint64_t>(unoptimized_code->GetIsolate()
+                                         ->builtins()
+                                         ->OnStackReplacement()
+                                         ->entry())));
+  Memory::uint64_at(interrupt_address_pointer) =
+      reinterpret_cast<uint64_t>(replacement_code->entry());
+
+  unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
+      unoptimized_code, reinterpret_cast<Address>(load), replacement_code);
+}
+
+
+BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
+    Isolate* isolate,
+    Code* unoptimized_code,
+    Address pc) {
+  // TODO(jbramley): There should be some extra assertions here (as in the ARM
+  // back-end), but this function is gone in bleeding_edge so it might not
+  // matter anyway.
+  Instruction* jump_or_nop = Instruction::Cast(pc)->preceding(3);
+
+  if (jump_or_nop->IsNop(Assembler::INTERRUPT_CODE_NOP)) {
+    Instruction* load = Instruction::Cast(pc)->preceding(2);
+    uint64_t entry = Memory::uint64_at(reinterpret_cast<Address>(load) +
+                                       load->ImmPCOffset());
+    if (entry == reinterpret_cast<uint64_t>(
+        isolate->builtins()->OnStackReplacement()->entry())) {
+      return ON_STACK_REPLACEMENT;
+    } else if (entry == reinterpret_cast<uint64_t>(
+        isolate->builtins()->OsrAfterStackCheck()->entry())) {
+      return OSR_AFTER_STACK_CHECK;
+    } else {
+      UNREACHABLE();
+    }
+  }
+
+  return INTERRUPT;
+}
+
+
+#define __ ACCESS_MASM(masm())
+
+
+FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
+    int* stack_depth,
+    int* context_length) {
+  ASM_LOCATION("FullCodeGenerator::TryFinally::Exit");
+  // The macros used here must preserve the result register.
+
+  // Because the handler block contains the context of the finally
+  // code, we can restore it directly from there for the finally code
+  // rather than iteratively unwinding contexts via their previous
+  // links.
+  __ Drop(*stack_depth);  // Down to the handler block.
+  if (*context_length > 0) {
+    // Restore the context to its dedicated register and the stack.
+    __ Peek(cp, StackHandlerConstants::kContextOffset);
+    __ Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  }
+  __ PopTryHandler();
+  __ Bl(finally_entry_);
+
+  *stack_depth = 0;
+  *context_length = 0;
+  return previous_;
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/instructions-arm64.cc b/src/arm64/instructions-arm64.cc
new file mode 100644
index 0000000..71094ba
--- /dev/null
+++ b/src/arm64/instructions-arm64.cc
@@ -0,0 +1,317 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#define ARM64_DEFINE_FP_STATICS
+
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/arm64/instructions-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+
+bool Instruction::IsLoad() const {
+  if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
+    return false;
+  }
+
+  if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
+    return Mask(LoadStorePairLBit) != 0;
+  } else {
+    LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask));
+    switch (op) {
+      case LDRB_w:
+      case LDRH_w:
+      case LDR_w:
+      case LDR_x:
+      case LDRSB_w:
+      case LDRSB_x:
+      case LDRSH_w:
+      case LDRSH_x:
+      case LDRSW_x:
+      case LDR_s:
+      case LDR_d: return true;
+      default: return false;
+    }
+  }
+}
+
+
+bool Instruction::IsStore() const {
+  if (Mask(LoadStoreAnyFMask) != LoadStoreAnyFixed) {
+    return false;
+  }
+
+  if (Mask(LoadStorePairAnyFMask) == LoadStorePairAnyFixed) {
+    return Mask(LoadStorePairLBit) == 0;
+  } else {
+    LoadStoreOp op = static_cast<LoadStoreOp>(Mask(LoadStoreOpMask));
+    switch (op) {
+      case STRB_w:
+      case STRH_w:
+      case STR_w:
+      case STR_x:
+      case STR_s:
+      case STR_d: return true;
+      default: return false;
+    }
+  }
+}
+
+
+static uint64_t RotateRight(uint64_t value,
+                            unsigned int rotate,
+                            unsigned int width) {
+  DCHECK(width <= 64);
+  rotate &= 63;
+  return ((value & ((1UL << rotate) - 1UL)) << (width - rotate)) |
+         (value >> rotate);
+}
+
+
+static uint64_t RepeatBitsAcrossReg(unsigned reg_size,
+                                    uint64_t value,
+                                    unsigned width) {
+  DCHECK((width == 2) || (width == 4) || (width == 8) || (width == 16) ||
+         (width == 32));
+  DCHECK((reg_size == kWRegSizeInBits) || (reg_size == kXRegSizeInBits));
+  uint64_t result = value & ((1UL << width) - 1UL);
+  for (unsigned i = width; i < reg_size; i *= 2) {
+    result |= (result << i);
+  }
+  return result;
+}
+
+
+// Logical immediates can't encode zero, so a return value of zero is used to
+// indicate a failure case. Specifically, where the constraints on imm_s are not
+// met.
+uint64_t Instruction::ImmLogical() {
+  unsigned reg_size = SixtyFourBits() ? kXRegSizeInBits : kWRegSizeInBits;
+  int64_t n = BitN();
+  int64_t imm_s = ImmSetBits();
+  int64_t imm_r = ImmRotate();
+
+  // An integer is constructed from the n, imm_s and imm_r bits according to
+  // the following table:
+  //
+  //  N   imms    immr    size        S             R
+  //  1  ssssss  rrrrrr    64    UInt(ssssss)  UInt(rrrrrr)
+  //  0  0sssss  xrrrrr    32    UInt(sssss)   UInt(rrrrr)
+  //  0  10ssss  xxrrrr    16    UInt(ssss)    UInt(rrrr)
+  //  0  110sss  xxxrrr     8    UInt(sss)     UInt(rrr)
+  //  0  1110ss  xxxxrr     4    UInt(ss)      UInt(rr)
+  //  0  11110s  xxxxxr     2    UInt(s)       UInt(r)
+  // (s bits must not be all set)
+  //
+  // A pattern is constructed of size bits, where the least significant S+1
+  // bits are set. The pattern is rotated right by R, and repeated across a
+  // 32 or 64-bit value, depending on destination register width.
+  //
+
+  if (n == 1) {
+    if (imm_s == 0x3F) {
+      return 0;
+    }
+    uint64_t bits = (1UL << (imm_s + 1)) - 1;
+    return RotateRight(bits, imm_r, 64);
+  } else {
+    if ((imm_s >> 1) == 0x1F) {
+      return 0;
+    }
+    for (int width = 0x20; width >= 0x2; width >>= 1) {
+      if ((imm_s & width) == 0) {
+        int mask = width - 1;
+        if ((imm_s & mask) == mask) {
+          return 0;
+        }
+        uint64_t bits = (1UL << ((imm_s & mask) + 1)) - 1;
+        return RepeatBitsAcrossReg(reg_size,
+                                   RotateRight(bits, imm_r & mask, width),
+                                   width);
+      }
+    }
+  }
+  UNREACHABLE();
+  return 0;
+}
+
+
+float Instruction::ImmFP32() {
+  //  ImmFP: abcdefgh (8 bits)
+  // Single: aBbb.bbbc.defg.h000.0000.0000.0000.0000 (32 bits)
+  // where B is b ^ 1
+  uint32_t bits = ImmFP();
+  uint32_t bit7 = (bits >> 7) & 0x1;
+  uint32_t bit6 = (bits >> 6) & 0x1;
+  uint32_t bit5_to_0 = bits & 0x3f;
+  uint32_t result = (bit7 << 31) | ((32 - bit6) << 25) | (bit5_to_0 << 19);
+
+  return rawbits_to_float(result);
+}
+
+
+double Instruction::ImmFP64() {
+  //  ImmFP: abcdefgh (8 bits)
+  // Double: aBbb.bbbb.bbcd.efgh.0000.0000.0000.0000
+  //         0000.0000.0000.0000.0000.0000.0000.0000 (64 bits)
+  // where B is b ^ 1
+  uint32_t bits = ImmFP();
+  uint64_t bit7 = (bits >> 7) & 0x1;
+  uint64_t bit6 = (bits >> 6) & 0x1;
+  uint64_t bit5_to_0 = bits & 0x3f;
+  uint64_t result = (bit7 << 63) | ((256 - bit6) << 54) | (bit5_to_0 << 48);
+
+  return rawbits_to_double(result);
+}
+
+
+LSDataSize CalcLSPairDataSize(LoadStorePairOp op) {
+  switch (op) {
+    case STP_x:
+    case LDP_x:
+    case STP_d:
+    case LDP_d: return LSDoubleWord;
+    default: return LSWord;
+  }
+}
+
+
+int64_t Instruction::ImmPCOffset() {
+  int64_t offset;
+  if (IsPCRelAddressing()) {
+    // PC-relative addressing. Only ADR is supported.
+    offset = ImmPCRel();
+  } else if (BranchType() != UnknownBranchType) {
+    // All PC-relative branches.
+    // Relative branch offsets are instruction-size-aligned.
+    offset = ImmBranch() << kInstructionSizeLog2;
+  } else {
+    // Load literal (offset from PC).
+    DCHECK(IsLdrLiteral());
+    // The offset is always shifted by 2 bits, even for loads to 64-bits
+    // registers.
+    offset = ImmLLiteral() << kInstructionSizeLog2;
+  }
+  return offset;
+}
+
+
+Instruction* Instruction::ImmPCOffsetTarget() {
+  return InstructionAtOffset(ImmPCOffset());
+}
+
+
+bool Instruction::IsValidImmPCOffset(ImmBranchType branch_type,
+                                     int32_t offset) {
+  return is_intn(offset, ImmBranchRangeBitwidth(branch_type));
+}
+
+
+bool Instruction::IsTargetInImmPCOffsetRange(Instruction* target) {
+  return IsValidImmPCOffset(BranchType(), DistanceTo(target));
+}
+
+
+void Instruction::SetImmPCOffsetTarget(Instruction* target) {
+  if (IsPCRelAddressing()) {
+    SetPCRelImmTarget(target);
+  } else if (BranchType() != UnknownBranchType) {
+    SetBranchImmTarget(target);
+  } else {
+    SetImmLLiteral(target);
+  }
+}
+
+
+void Instruction::SetPCRelImmTarget(Instruction* target) {
+  // ADRP is not supported, so 'this' must point to an ADR instruction.
+  DCHECK(IsAdr());
+
+  ptrdiff_t target_offset = DistanceTo(target);
+  Instr imm;
+  if (Instruction::IsValidPCRelOffset(target_offset)) {
+    imm = Assembler::ImmPCRelAddress(target_offset);
+    SetInstructionBits(Mask(~ImmPCRel_mask) | imm);
+  } else {
+    PatchingAssembler patcher(this,
+                              PatchingAssembler::kAdrFarPatchableNInstrs);
+    patcher.PatchAdrFar(target_offset);
+  }
+}
+
+
+void Instruction::SetBranchImmTarget(Instruction* target) {
+  DCHECK(IsAligned(DistanceTo(target), kInstructionSize));
+  Instr branch_imm = 0;
+  uint32_t imm_mask = 0;
+  ptrdiff_t offset = DistanceTo(target) >> kInstructionSizeLog2;
+  switch (BranchType()) {
+    case CondBranchType: {
+      branch_imm = Assembler::ImmCondBranch(offset);
+      imm_mask = ImmCondBranch_mask;
+      break;
+    }
+    case UncondBranchType: {
+      branch_imm = Assembler::ImmUncondBranch(offset);
+      imm_mask = ImmUncondBranch_mask;
+      break;
+    }
+    case CompareBranchType: {
+      branch_imm = Assembler::ImmCmpBranch(offset);
+      imm_mask = ImmCmpBranch_mask;
+      break;
+    }
+    case TestBranchType: {
+      branch_imm = Assembler::ImmTestBranch(offset);
+      imm_mask = ImmTestBranch_mask;
+      break;
+    }
+    default: UNREACHABLE();
+  }
+  SetInstructionBits(Mask(~imm_mask) | branch_imm);
+}
+
+
+void Instruction::SetImmLLiteral(Instruction* source) {
+  DCHECK(IsAligned(DistanceTo(source), kInstructionSize));
+  ptrdiff_t offset = DistanceTo(source) >> kLoadLiteralScaleLog2;
+  Instr imm = Assembler::ImmLLiteral(offset);
+  Instr mask = ImmLLiteral_mask;
+
+  SetInstructionBits(Mask(~mask) | imm);
+}
+
+
+// TODO(jbramley): We can't put this inline in the class because things like
+// xzr and Register are not defined in that header. Consider adding
+// instructions-arm64-inl.h to work around this.
+bool InstructionSequence::IsInlineData() const {
+  // Inline data is encoded as a single movz instruction which writes to xzr
+  // (x31).
+  return IsMovz() && SixtyFourBits() && (Rd() == xzr.code());
+  // TODO(all): If we extend ::InlineData() to support bigger data, we need
+  // to update this method too.
+}
+
+
+// TODO(jbramley): We can't put this inline in the class because things like
+// xzr and Register are not defined in that header. Consider adding
+// instructions-arm64-inl.h to work around this.
+uint64_t InstructionSequence::InlineData() const {
+  DCHECK(IsInlineData());
+  uint64_t payload = ImmMoveWide();
+  // TODO(all): If we extend ::InlineData() to support bigger data, we need
+  // to update this method too.
+  return payload;
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/instructions-arm64.h b/src/arm64/instructions-arm64.h
new file mode 100644
index 0000000..374e246
--- /dev/null
+++ b/src/arm64/instructions-arm64.h
@@ -0,0 +1,509 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_INSTRUCTIONS_ARM64_H_
+#define V8_ARM64_INSTRUCTIONS_ARM64_H_
+
+#include "src/arm64/constants-arm64.h"
+#include "src/arm64/utils-arm64.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+
+// ISA constants. --------------------------------------------------------------
+
+typedef uint32_t Instr;
+
+// The following macros initialize a float/double variable with a bit pattern
+// without using static initializers: If ARM64_DEFINE_FP_STATICS is defined, the
+// symbol is defined as uint32_t/uint64_t initialized with the desired bit
+// pattern. Otherwise, the same symbol is declared as an external float/double.
+#if defined(ARM64_DEFINE_FP_STATICS)
+#define DEFINE_FLOAT(name, value) extern const uint32_t name = value
+#define DEFINE_DOUBLE(name, value) extern const uint64_t name = value
+#else
+#define DEFINE_FLOAT(name, value) extern const float name
+#define DEFINE_DOUBLE(name, value) extern const double name
+#endif  // defined(ARM64_DEFINE_FP_STATICS)
+
+DEFINE_FLOAT(kFP32PositiveInfinity, 0x7f800000);
+DEFINE_FLOAT(kFP32NegativeInfinity, 0xff800000);
+DEFINE_DOUBLE(kFP64PositiveInfinity, 0x7ff0000000000000UL);
+DEFINE_DOUBLE(kFP64NegativeInfinity, 0xfff0000000000000UL);
+
+// This value is a signalling NaN as both a double and as a float (taking the
+// least-significant word).
+DEFINE_DOUBLE(kFP64SignallingNaN, 0x7ff000007f800001);
+DEFINE_FLOAT(kFP32SignallingNaN, 0x7f800001);
+
+// A similar value, but as a quiet NaN.
+DEFINE_DOUBLE(kFP64QuietNaN, 0x7ff800007fc00001);
+DEFINE_FLOAT(kFP32QuietNaN, 0x7fc00001);
+
+// The default NaN values (for FPCR.DN=1).
+DEFINE_DOUBLE(kFP64DefaultNaN, 0x7ff8000000000000UL);
+DEFINE_FLOAT(kFP32DefaultNaN, 0x7fc00000);
+
+#undef DEFINE_FLOAT
+#undef DEFINE_DOUBLE
+
+
+enum LSDataSize {
+  LSByte        = 0,
+  LSHalfword    = 1,
+  LSWord        = 2,
+  LSDoubleWord  = 3
+};
+
+LSDataSize CalcLSPairDataSize(LoadStorePairOp op);
+
+enum ImmBranchType {
+  UnknownBranchType = 0,
+  CondBranchType    = 1,
+  UncondBranchType  = 2,
+  CompareBranchType = 3,
+  TestBranchType    = 4
+};
+
+enum AddrMode {
+  Offset,
+  PreIndex,
+  PostIndex
+};
+
+enum FPRounding {
+  // The first four values are encodable directly by FPCR<RMode>.
+  FPTieEven = 0x0,
+  FPPositiveInfinity = 0x1,
+  FPNegativeInfinity = 0x2,
+  FPZero = 0x3,
+
+  // The final rounding mode is only available when explicitly specified by the
+  // instruction (such as with fcvta). It cannot be set in FPCR.
+  FPTieAway
+};
+
+enum Reg31Mode {
+  Reg31IsStackPointer,
+  Reg31IsZeroRegister
+};
+
+// Instructions. ---------------------------------------------------------------
+
+class Instruction {
+ public:
+  V8_INLINE Instr InstructionBits() const {
+    return *reinterpret_cast<const Instr*>(this);
+  }
+
+  V8_INLINE void SetInstructionBits(Instr new_instr) {
+    *reinterpret_cast<Instr*>(this) = new_instr;
+  }
+
+  int Bit(int pos) const {
+    return (InstructionBits() >> pos) & 1;
+  }
+
+  uint32_t Bits(int msb, int lsb) const {
+    return unsigned_bitextract_32(msb, lsb, InstructionBits());
+  }
+
+  int32_t SignedBits(int msb, int lsb) const {
+    int32_t bits = *(reinterpret_cast<const int32_t*>(this));
+    return signed_bitextract_32(msb, lsb, bits);
+  }
+
+  Instr Mask(uint32_t mask) const {
+    return InstructionBits() & mask;
+  }
+
+  V8_INLINE Instruction* following(int count = 1) {
+    return InstructionAtOffset(count * static_cast<int>(kInstructionSize));
+  }
+
+  V8_INLINE Instruction* preceding(int count = 1) {
+    return following(-count);
+  }
+
+  #define DEFINE_GETTER(Name, HighBit, LowBit, Func)             \
+  int64_t Name() const { return Func(HighBit, LowBit); }
+  INSTRUCTION_FIELDS_LIST(DEFINE_GETTER)
+  #undef DEFINE_GETTER
+
+  // ImmPCRel is a compound field (not present in INSTRUCTION_FIELDS_LIST),
+  // formed from ImmPCRelLo and ImmPCRelHi.
+  int ImmPCRel() const {
+    DCHECK(IsPCRelAddressing());
+    int const offset = ((ImmPCRelHi() << ImmPCRelLo_width) | ImmPCRelLo());
+    int const width = ImmPCRelLo_width + ImmPCRelHi_width;
+    return signed_bitextract_32(width - 1, 0, offset);
+  }
+
+  uint64_t ImmLogical();
+  float ImmFP32();
+  double ImmFP64();
+
+  LSDataSize SizeLSPair() const {
+    return CalcLSPairDataSize(
+        static_cast<LoadStorePairOp>(Mask(LoadStorePairMask)));
+  }
+
+  // Helpers.
+  bool IsCondBranchImm() const {
+    return Mask(ConditionalBranchFMask) == ConditionalBranchFixed;
+  }
+
+  bool IsUncondBranchImm() const {
+    return Mask(UnconditionalBranchFMask) == UnconditionalBranchFixed;
+  }
+
+  bool IsCompareBranch() const {
+    return Mask(CompareBranchFMask) == CompareBranchFixed;
+  }
+
+  bool IsTestBranch() const {
+    return Mask(TestBranchFMask) == TestBranchFixed;
+  }
+
+  bool IsImmBranch() const {
+    return BranchType() != UnknownBranchType;
+  }
+
+  bool IsLdrLiteral() const {
+    return Mask(LoadLiteralFMask) == LoadLiteralFixed;
+  }
+
+  bool IsLdrLiteralX() const {
+    return Mask(LoadLiteralMask) == LDR_x_lit;
+  }
+
+  bool IsPCRelAddressing() const {
+    return Mask(PCRelAddressingFMask) == PCRelAddressingFixed;
+  }
+
+  bool IsAdr() const {
+    return Mask(PCRelAddressingMask) == ADR;
+  }
+
+  bool IsLogicalImmediate() const {
+    return Mask(LogicalImmediateFMask) == LogicalImmediateFixed;
+  }
+
+  bool IsAddSubImmediate() const {
+    return Mask(AddSubImmediateFMask) == AddSubImmediateFixed;
+  }
+
+  bool IsAddSubShifted() const {
+    return Mask(AddSubShiftedFMask) == AddSubShiftedFixed;
+  }
+
+  bool IsAddSubExtended() const {
+    return Mask(AddSubExtendedFMask) == AddSubExtendedFixed;
+  }
+
+  // Match any loads or stores, including pairs.
+  bool IsLoadOrStore() const {
+    return Mask(LoadStoreAnyFMask) == LoadStoreAnyFixed;
+  }
+
+  // Match any loads, including pairs.
+  bool IsLoad() const;
+  // Match any stores, including pairs.
+  bool IsStore() const;
+
+  // Indicate whether Rd can be the stack pointer or the zero register. This
+  // does not check that the instruction actually has an Rd field.
+  Reg31Mode RdMode() const {
+    // The following instructions use csp or wsp as Rd:
+    //  Add/sub (immediate) when not setting the flags.
+    //  Add/sub (extended) when not setting the flags.
+    //  Logical (immediate) when not setting the flags.
+    // Otherwise, r31 is the zero register.
+    if (IsAddSubImmediate() || IsAddSubExtended()) {
+      if (Mask(AddSubSetFlagsBit)) {
+        return Reg31IsZeroRegister;
+      } else {
+        return Reg31IsStackPointer;
+      }
+    }
+    if (IsLogicalImmediate()) {
+      // Of the logical (immediate) instructions, only ANDS (and its aliases)
+      // can set the flags. The others can all write into csp.
+      // Note that some logical operations are not available to
+      // immediate-operand instructions, so we have to combine two masks here.
+      if (Mask(LogicalImmediateMask & LogicalOpMask) == ANDS) {
+        return Reg31IsZeroRegister;
+      } else {
+        return Reg31IsStackPointer;
+      }
+    }
+    return Reg31IsZeroRegister;
+  }
+
+  // Indicate whether Rn can be the stack pointer or the zero register. This
+  // does not check that the instruction actually has an Rn field.
+  Reg31Mode RnMode() const {
+    // The following instructions use csp or wsp as Rn:
+    //  All loads and stores.
+    //  Add/sub (immediate).
+    //  Add/sub (extended).
+    // Otherwise, r31 is the zero register.
+    if (IsLoadOrStore() || IsAddSubImmediate() || IsAddSubExtended()) {
+      return Reg31IsStackPointer;
+    }
+    return Reg31IsZeroRegister;
+  }
+
+  ImmBranchType BranchType() const {
+    if (IsCondBranchImm()) {
+      return CondBranchType;
+    } else if (IsUncondBranchImm()) {
+      return UncondBranchType;
+    } else if (IsCompareBranch()) {
+      return CompareBranchType;
+    } else if (IsTestBranch()) {
+      return TestBranchType;
+    } else {
+      return UnknownBranchType;
+    }
+  }
+
+  static int ImmBranchRangeBitwidth(ImmBranchType branch_type) {
+    switch (branch_type) {
+      case UncondBranchType:
+        return ImmUncondBranch_width;
+      case CondBranchType:
+        return ImmCondBranch_width;
+      case CompareBranchType:
+        return ImmCmpBranch_width;
+      case TestBranchType:
+        return ImmTestBranch_width;
+      default:
+        UNREACHABLE();
+        return 0;
+    }
+  }
+
+  // The range of the branch instruction, expressed as 'instr +- range'.
+  static int32_t ImmBranchRange(ImmBranchType branch_type) {
+    return
+      (1 << (ImmBranchRangeBitwidth(branch_type) + kInstructionSizeLog2)) / 2 -
+      kInstructionSize;
+  }
+
+  int ImmBranch() const {
+    switch (BranchType()) {
+      case CondBranchType: return ImmCondBranch();
+      case UncondBranchType: return ImmUncondBranch();
+      case CompareBranchType: return ImmCmpBranch();
+      case TestBranchType: return ImmTestBranch();
+      default: UNREACHABLE();
+    }
+    return 0;
+  }
+
+  bool IsBranchAndLinkToRegister() const {
+    return Mask(UnconditionalBranchToRegisterMask) == BLR;
+  }
+
+  bool IsMovz() const {
+    return (Mask(MoveWideImmediateMask) == MOVZ_x) ||
+           (Mask(MoveWideImmediateMask) == MOVZ_w);
+  }
+
+  bool IsMovk() const {
+    return (Mask(MoveWideImmediateMask) == MOVK_x) ||
+           (Mask(MoveWideImmediateMask) == MOVK_w);
+  }
+
+  bool IsMovn() const {
+    return (Mask(MoveWideImmediateMask) == MOVN_x) ||
+           (Mask(MoveWideImmediateMask) == MOVN_w);
+  }
+
+  bool IsNop(int n) {
+    // A marking nop is an instruction
+    //   mov r<n>,  r<n>
+    // which is encoded as
+    //   orr r<n>, xzr, r<n>
+    return (Mask(LogicalShiftedMask) == ORR_x) &&
+           (Rd() == Rm()) &&
+           (Rd() == n);
+  }
+
+  // Find the PC offset encoded in this instruction. 'this' may be a branch or
+  // a PC-relative addressing instruction.
+  // The offset returned is unscaled.
+  int64_t ImmPCOffset();
+
+  // Find the target of this instruction. 'this' may be a branch or a
+  // PC-relative addressing instruction.
+  Instruction* ImmPCOffsetTarget();
+
+  static bool IsValidImmPCOffset(ImmBranchType branch_type, int32_t offset);
+  bool IsTargetInImmPCOffsetRange(Instruction* target);
+  // Patch a PC-relative offset to refer to 'target'. 'this' may be a branch or
+  // a PC-relative addressing instruction.
+  void SetImmPCOffsetTarget(Instruction* target);
+  // Patch a literal load instruction to load from 'source'.
+  void SetImmLLiteral(Instruction* source);
+
+  uintptr_t LiteralAddress() {
+    int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
+    return reinterpret_cast<uintptr_t>(this) + offset;
+  }
+
+  enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
+
+  V8_INLINE Instruction* InstructionAtOffset(
+      int64_t offset,
+      CheckAlignment check = CHECK_ALIGNMENT) {
+    Address addr = reinterpret_cast<Address>(this) + offset;
+    // The FUZZ_disasm test relies on no check being done.
+    DCHECK(check == NO_CHECK || IsAddressAligned(addr, kInstructionSize));
+    return Cast(addr);
+  }
+
+  template<typename T> V8_INLINE static Instruction* Cast(T src) {
+    return reinterpret_cast<Instruction*>(src);
+  }
+
+  V8_INLINE ptrdiff_t DistanceTo(Instruction* target) {
+    return reinterpret_cast<Address>(target) - reinterpret_cast<Address>(this);
+  }
+
+
+  static const int ImmPCRelRangeBitwidth = 21;
+  static bool IsValidPCRelOffset(int offset) {
+    return is_int21(offset);
+  }
+  void SetPCRelImmTarget(Instruction* target);
+  void SetBranchImmTarget(Instruction* target);
+};
+
+
+// Where Instruction looks at instructions generated by the Assembler,
+// InstructionSequence looks at instructions sequences generated by the
+// MacroAssembler.
+class InstructionSequence : public Instruction {
+ public:
+  static InstructionSequence* At(Address address) {
+    return reinterpret_cast<InstructionSequence*>(address);
+  }
+
+  // Sequences generated by MacroAssembler::InlineData().
+  bool IsInlineData() const;
+  uint64_t InlineData() const;
+};
+
+
+// Simulator/Debugger debug instructions ---------------------------------------
+// Each debug marker is represented by a HLT instruction. The immediate comment
+// field in the instruction is used to identify the type of debug marker. Each
+// marker encodes arguments in a different way, as described below.
+
+// Indicate to the Debugger that the instruction is a redirected call.
+const Instr kImmExceptionIsRedirectedCall = 0xca11;
+
+// Represent unreachable code. This is used as a guard in parts of the code that
+// should not be reachable, such as in data encoded inline in the instructions.
+const Instr kImmExceptionIsUnreachable = 0xdebf;
+
+// A pseudo 'printf' instruction. The arguments will be passed to the platform
+// printf method.
+const Instr kImmExceptionIsPrintf = 0xdeb1;
+// Most parameters are stored in ARM64 registers as if the printf
+// pseudo-instruction was a call to the real printf method:
+//      x0: The format string.
+//   x1-x7: Optional arguments.
+//   d0-d7: Optional arguments.
+//
+// Also, the argument layout is described inline in the instructions:
+//  - arg_count: The number of arguments.
+//  - arg_pattern: A set of PrintfArgPattern values, packed into two-bit fields.
+//
+// Floating-point and integer arguments are passed in separate sets of registers
+// in AAPCS64 (even for varargs functions), so it is not possible to determine
+// the type of each argument without some information about the values that were
+// passed in. This information could be retrieved from the printf format string,
+// but the format string is not trivial to parse so we encode the relevant
+// information with the HLT instruction.
+const unsigned kPrintfArgCountOffset = 1 * kInstructionSize;
+const unsigned kPrintfArgPatternListOffset = 2 * kInstructionSize;
+const unsigned kPrintfLength = 3 * kInstructionSize;
+
+const unsigned kPrintfMaxArgCount = 4;
+
+// The argument pattern is a set of two-bit-fields, each with one of the
+// following values:
+enum PrintfArgPattern {
+  kPrintfArgW = 1,
+  kPrintfArgX = 2,
+  // There is no kPrintfArgS because floats are always converted to doubles in C
+  // varargs calls.
+  kPrintfArgD = 3
+};
+static const unsigned kPrintfArgPatternBits = 2;
+
+// A pseudo 'debug' instruction.
+const Instr kImmExceptionIsDebug = 0xdeb0;
+// Parameters are inlined in the code after a debug pseudo-instruction:
+// - Debug code.
+// - Debug parameters.
+// - Debug message string. This is a NULL-terminated ASCII string, padded to
+//   kInstructionSize so that subsequent instructions are correctly aligned.
+// - A kImmExceptionIsUnreachable marker, to catch accidental execution of the
+//   string data.
+const unsigned kDebugCodeOffset = 1 * kInstructionSize;
+const unsigned kDebugParamsOffset = 2 * kInstructionSize;
+const unsigned kDebugMessageOffset = 3 * kInstructionSize;
+
+// Debug parameters.
+// Used without a TRACE_ option, the Debugger will print the arguments only
+// once. Otherwise TRACE_ENABLE and TRACE_DISABLE will enable or disable tracing
+// before every instruction for the specified LOG_ parameters.
+//
+// TRACE_OVERRIDE enables the specified LOG_ parameters, and disabled any
+// others that were not specified.
+//
+// For example:
+//
+// __ debug("print registers and fp registers", 0, LOG_REGS | LOG_FP_REGS);
+// will print the registers and fp registers only once.
+//
+// __ debug("trace disasm", 1, TRACE_ENABLE | LOG_DISASM);
+// starts disassembling the code.
+//
+// __ debug("trace rets", 2, TRACE_ENABLE | LOG_REGS);
+// adds the general purpose registers to the trace.
+//
+// __ debug("stop regs", 3, TRACE_DISABLE | LOG_REGS);
+// stops tracing the registers.
+const unsigned kDebuggerTracingDirectivesMask = 3 << 6;
+enum DebugParameters {
+  NO_PARAM       = 0,
+  BREAK          = 1 << 0,
+  LOG_DISASM     = 1 << 1,  // Use only with TRACE. Disassemble the code.
+  LOG_REGS       = 1 << 2,  // Log general purpose registers.
+  LOG_FP_REGS    = 1 << 3,  // Log floating-point registers.
+  LOG_SYS_REGS   = 1 << 4,  // Log the status flags.
+  LOG_WRITE      = 1 << 5,  // Log any memory write.
+
+  LOG_STATE      = LOG_REGS | LOG_FP_REGS | LOG_SYS_REGS,
+  LOG_ALL        = LOG_DISASM | LOG_STATE | LOG_WRITE,
+
+  // Trace control.
+  TRACE_ENABLE   = 1 << 6,
+  TRACE_DISABLE  = 2 << 6,
+  TRACE_OVERRIDE = 3 << 6
+};
+
+
+} }  // namespace v8::internal
+
+
+#endif  // V8_ARM64_INSTRUCTIONS_ARM64_H_
diff --git a/src/arm64/instrument-arm64.cc b/src/arm64/instrument-arm64.cc
new file mode 100644
index 0000000..da505ff
--- /dev/null
+++ b/src/arm64/instrument-arm64.cc
@@ -0,0 +1,594 @@
+// Copyright 2013 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/arm64/instrument-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+Counter::Counter(const char* name, CounterType type)
+    : count_(0), enabled_(false), type_(type) {
+  DCHECK(name != NULL);
+  strncpy(name_, name, kCounterNameMaxLength);
+}
+
+
+void Counter::Enable() {
+  enabled_ = true;
+}
+
+
+void Counter::Disable() {
+  enabled_ = false;
+}
+
+
+bool Counter::IsEnabled() {
+  return enabled_;
+}
+
+
+void Counter::Increment() {
+  if (enabled_) {
+    count_++;
+  }
+}
+
+
+uint64_t Counter::count() {
+  uint64_t result = count_;
+  if (type_ == Gauge) {
+    // If the counter is a Gauge, reset the count after reading.
+    count_ = 0;
+  }
+  return result;
+}
+
+
+const char* Counter::name() {
+  return name_;
+}
+
+
+CounterType Counter::type() {
+  return type_;
+}
+
+
+typedef struct {
+  const char* name;
+  CounterType type;
+} CounterDescriptor;
+
+
+static const CounterDescriptor kCounterList[] = {
+  {"Instruction", Cumulative},
+
+  {"Move Immediate", Gauge},
+  {"Add/Sub DP", Gauge},
+  {"Logical DP", Gauge},
+  {"Other Int DP", Gauge},
+  {"FP DP", Gauge},
+
+  {"Conditional Select", Gauge},
+  {"Conditional Compare", Gauge},
+
+  {"Unconditional Branch", Gauge},
+  {"Compare and Branch", Gauge},
+  {"Test and Branch", Gauge},
+  {"Conditional Branch", Gauge},
+
+  {"Load Integer", Gauge},
+  {"Load FP", Gauge},
+  {"Load Pair", Gauge},
+  {"Load Literal", Gauge},
+
+  {"Store Integer", Gauge},
+  {"Store FP", Gauge},
+  {"Store Pair", Gauge},
+
+  {"PC Addressing", Gauge},
+  {"Other", Gauge},
+  {"SP Adjust", Gauge},
+};
+
+
+Instrument::Instrument(const char* datafile, uint64_t sample_period)
+    : output_stream_(stderr), sample_period_(sample_period) {
+
+  // Set up the output stream. If datafile is non-NULL, use that file. If it
+  // can't be opened, or datafile is NULL, use stderr.
+  if (datafile != NULL) {
+    output_stream_ = fopen(datafile, "w");
+    if (output_stream_ == NULL) {
+      fprintf(stderr, "Can't open output file %s. Using stderr.\n", datafile);
+      output_stream_ = stderr;
+    }
+  }
+
+  static const int num_counters = arraysize(kCounterList);
+
+  // Dump an instrumentation description comment at the top of the file.
+  fprintf(output_stream_, "# counters=%d\n", num_counters);
+  fprintf(output_stream_, "# sample_period=%" PRIu64 "\n", sample_period_);
+
+  // Construct Counter objects from counter description array.
+  for (int i = 0; i < num_counters; i++) {
+    Counter* counter = new Counter(kCounterList[i].name, kCounterList[i].type);
+    counters_.push_back(counter);
+  }
+
+  DumpCounterNames();
+}
+
+
+Instrument::~Instrument() {
+  // Dump any remaining instruction data to the output file.
+  DumpCounters();
+
+  // Free all the counter objects.
+  std::list<Counter*>::iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    delete *it;
+  }
+
+  if (output_stream_ != stderr) {
+    fclose(output_stream_);
+  }
+}
+
+
+void Instrument::Update() {
+  // Increment the instruction counter, and dump all counters if a sample period
+  // has elapsed.
+  static Counter* counter = GetCounter("Instruction");
+  DCHECK(counter->type() == Cumulative);
+  counter->Increment();
+
+  if (counter->IsEnabled() && (counter->count() % sample_period_) == 0) {
+    DumpCounters();
+  }
+}
+
+
+void Instrument::DumpCounters() {
+  // Iterate through the counter objects, dumping their values to the output
+  // stream.
+  std::list<Counter*>::const_iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    fprintf(output_stream_, "%" PRIu64 ",", (*it)->count());
+  }
+  fprintf(output_stream_, "\n");
+  fflush(output_stream_);
+}
+
+
+void Instrument::DumpCounterNames() {
+  // Iterate through the counter objects, dumping the counter names to the
+  // output stream.
+  std::list<Counter*>::const_iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    fprintf(output_stream_, "%s,", (*it)->name());
+  }
+  fprintf(output_stream_, "\n");
+  fflush(output_stream_);
+}
+
+
+void Instrument::HandleInstrumentationEvent(unsigned event) {
+  switch (event) {
+    case InstrumentStateEnable: Enable(); break;
+    case InstrumentStateDisable: Disable(); break;
+    default: DumpEventMarker(event);
+  }
+}
+
+
+void Instrument::DumpEventMarker(unsigned marker) {
+  // Dumpan event marker to the output stream as a specially formatted comment
+  // line.
+  static Counter* counter = GetCounter("Instruction");
+
+  fprintf(output_stream_, "# %c%c @ %" PRId64 "\n", marker & 0xff,
+          (marker >> 8) & 0xff, counter->count());
+}
+
+
+Counter* Instrument::GetCounter(const char* name) {
+  // Get a Counter object by name from the counter list.
+  std::list<Counter*>::const_iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    if (strcmp((*it)->name(), name) == 0) {
+      return *it;
+    }
+  }
+
+  // A Counter by that name does not exist: print an error message to stderr
+  // and the output file, and exit.
+  static const char* error_message =
+    "# Error: Unknown counter \"%s\". Exiting.\n";
+  fprintf(stderr, error_message, name);
+  fprintf(output_stream_, error_message, name);
+  exit(1);
+}
+
+
+void Instrument::Enable() {
+  std::list<Counter*>::iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    (*it)->Enable();
+  }
+}
+
+
+void Instrument::Disable() {
+  std::list<Counter*>::iterator it;
+  for (it = counters_.begin(); it != counters_.end(); it++) {
+    (*it)->Disable();
+  }
+}
+
+
+void Instrument::VisitPCRelAddressing(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("PC Addressing");
+  counter->Increment();
+}
+
+
+void Instrument::VisitAddSubImmediate(Instruction* instr) {
+  Update();
+  static Counter* sp_counter = GetCounter("SP Adjust");
+  static Counter* add_sub_counter = GetCounter("Add/Sub DP");
+  if (((instr->Mask(AddSubOpMask) == SUB) ||
+       (instr->Mask(AddSubOpMask) == ADD)) &&
+      (instr->Rd() == 31) && (instr->Rn() == 31)) {
+    // Count adjustments to the C stack pointer caused by V8 needing two SPs.
+    sp_counter->Increment();
+  } else {
+    add_sub_counter->Increment();
+  }
+}
+
+
+void Instrument::VisitLogicalImmediate(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Logical DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitMoveWideImmediate(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Move Immediate");
+
+  if (instr->IsMovn() && (instr->Rd() == kZeroRegCode)) {
+    unsigned imm = instr->ImmMoveWide();
+    HandleInstrumentationEvent(imm);
+  } else {
+    counter->Increment();
+  }
+}
+
+
+void Instrument::VisitBitfield(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other Int DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitExtract(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other Int DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitUnconditionalBranch(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Unconditional Branch");
+  counter->Increment();
+}
+
+
+void Instrument::VisitUnconditionalBranchToRegister(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Unconditional Branch");
+  counter->Increment();
+}
+
+
+void Instrument::VisitCompareBranch(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Compare and Branch");
+  counter->Increment();
+}
+
+
+void Instrument::VisitTestBranch(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Test and Branch");
+  counter->Increment();
+}
+
+
+void Instrument::VisitConditionalBranch(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Branch");
+  counter->Increment();
+}
+
+
+void Instrument::VisitSystem(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other");
+  counter->Increment();
+}
+
+
+void Instrument::VisitException(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other");
+  counter->Increment();
+}
+
+
+void Instrument::InstrumentLoadStorePair(Instruction* instr) {
+  static Counter* load_pair_counter = GetCounter("Load Pair");
+  static Counter* store_pair_counter = GetCounter("Store Pair");
+  if (instr->Mask(LoadStorePairLBit) != 0) {
+    load_pair_counter->Increment();
+  } else {
+    store_pair_counter->Increment();
+  }
+}
+
+
+void Instrument::VisitLoadStorePairPostIndex(Instruction* instr) {
+  Update();
+  InstrumentLoadStorePair(instr);
+}
+
+
+void Instrument::VisitLoadStorePairOffset(Instruction* instr) {
+  Update();
+  InstrumentLoadStorePair(instr);
+}
+
+
+void Instrument::VisitLoadStorePairPreIndex(Instruction* instr) {
+  Update();
+  InstrumentLoadStorePair(instr);
+}
+
+
+void Instrument::VisitLoadStorePairNonTemporal(Instruction* instr) {
+  Update();
+  InstrumentLoadStorePair(instr);
+}
+
+
+void Instrument::VisitLoadLiteral(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Load Literal");
+  counter->Increment();
+}
+
+
+void Instrument::InstrumentLoadStore(Instruction* instr) {
+  static Counter* load_int_counter = GetCounter("Load Integer");
+  static Counter* store_int_counter = GetCounter("Store Integer");
+  static Counter* load_fp_counter = GetCounter("Load FP");
+  static Counter* store_fp_counter = GetCounter("Store FP");
+
+  switch (instr->Mask(LoadStoreOpMask)) {
+    case STRB_w:    // Fall through.
+    case STRH_w:    // Fall through.
+    case STR_w:     // Fall through.
+    case STR_x:     store_int_counter->Increment(); break;
+    case STR_s:     // Fall through.
+    case STR_d:     store_fp_counter->Increment(); break;
+    case LDRB_w:    // Fall through.
+    case LDRH_w:    // Fall through.
+    case LDR_w:     // Fall through.
+    case LDR_x:     // Fall through.
+    case LDRSB_x:   // Fall through.
+    case LDRSH_x:   // Fall through.
+    case LDRSW_x:   // Fall through.
+    case LDRSB_w:   // Fall through.
+    case LDRSH_w:   load_int_counter->Increment(); break;
+    case LDR_s:     // Fall through.
+    case LDR_d:     load_fp_counter->Increment(); break;
+    default: UNREACHABLE();
+  }
+}
+
+
+void Instrument::VisitLoadStoreUnscaledOffset(Instruction* instr) {
+  Update();
+  InstrumentLoadStore(instr);
+}
+
+
+void Instrument::VisitLoadStorePostIndex(Instruction* instr) {
+  Update();
+  InstrumentLoadStore(instr);
+}
+
+
+void Instrument::VisitLoadStorePreIndex(Instruction* instr) {
+  Update();
+  InstrumentLoadStore(instr);
+}
+
+
+void Instrument::VisitLoadStoreRegisterOffset(Instruction* instr) {
+  Update();
+  InstrumentLoadStore(instr);
+}
+
+
+void Instrument::VisitLoadStoreUnsignedOffset(Instruction* instr) {
+  Update();
+  InstrumentLoadStore(instr);
+}
+
+
+void Instrument::VisitLogicalShifted(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Logical DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitAddSubShifted(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Add/Sub DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitAddSubExtended(Instruction* instr) {
+  Update();
+  static Counter* sp_counter = GetCounter("SP Adjust");
+  static Counter* add_sub_counter = GetCounter("Add/Sub DP");
+  if (((instr->Mask(AddSubOpMask) == SUB) ||
+       (instr->Mask(AddSubOpMask) == ADD)) &&
+      (instr->Rd() == 31) && (instr->Rn() == 31)) {
+    // Count adjustments to the C stack pointer caused by V8 needing two SPs.
+    sp_counter->Increment();
+  } else {
+    add_sub_counter->Increment();
+  }
+}
+
+
+void Instrument::VisitAddSubWithCarry(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Add/Sub DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitConditionalCompareRegister(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Compare");
+  counter->Increment();
+}
+
+
+void Instrument::VisitConditionalCompareImmediate(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Compare");
+  counter->Increment();
+}
+
+
+void Instrument::VisitConditionalSelect(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Select");
+  counter->Increment();
+}
+
+
+void Instrument::VisitDataProcessing1Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other Int DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitDataProcessing2Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other Int DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitDataProcessing3Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other Int DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPCompare(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPConditionalCompare(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Compare");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPConditionalSelect(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Conditional Select");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPImmediate(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPDataProcessing1Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPDataProcessing2Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPDataProcessing3Source(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPIntegerConvert(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitFPFixedPointConvert(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("FP DP");
+  counter->Increment();
+}
+
+
+void Instrument::VisitUnallocated(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other");
+  counter->Increment();
+}
+
+
+void Instrument::VisitUnimplemented(Instruction* instr) {
+  Update();
+  static Counter* counter = GetCounter("Other");
+  counter->Increment();
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/arm64/instrument-arm64.h b/src/arm64/instrument-arm64.h
new file mode 100644
index 0000000..86ddfcb
--- /dev/null
+++ b/src/arm64/instrument-arm64.h
@@ -0,0 +1,85 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_INSTRUMENT_ARM64_H_
+#define V8_ARM64_INSTRUMENT_ARM64_H_
+
+#include "src/globals.h"
+#include "src/utils.h"
+
+#include "src/arm64/constants-arm64.h"
+#include "src/arm64/decoder-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+const int kCounterNameMaxLength = 256;
+const uint64_t kDefaultInstrumentationSamplingPeriod = 1 << 22;
+
+
+enum InstrumentState {
+  InstrumentStateDisable = 0,
+  InstrumentStateEnable = 1
+};
+
+
+enum CounterType {
+  Gauge = 0,      // Gauge counters reset themselves after reading.
+  Cumulative = 1  // Cumulative counters keep their value after reading.
+};
+
+
+class Counter {
+ public:
+  explicit Counter(const char* name, CounterType type = Gauge);
+
+  void Increment();
+  void Enable();
+  void Disable();
+  bool IsEnabled();
+  uint64_t count();
+  const char* name();
+  CounterType type();
+
+ private:
+  char name_[kCounterNameMaxLength];
+  uint64_t count_;
+  bool enabled_;
+  CounterType type_;
+};
+
+
+class Instrument: public DecoderVisitor {
+ public:
+  explicit Instrument(const char* datafile = NULL,
+    uint64_t sample_period = kDefaultInstrumentationSamplingPeriod);
+  ~Instrument();
+
+  // Declare all Visitor functions.
+  #define DECLARE(A) void Visit##A(Instruction* instr);
+  VISITOR_LIST(DECLARE)
+  #undef DECLARE
+
+ private:
+  void Update();
+  void Enable();
+  void Disable();
+  void DumpCounters();
+  void DumpCounterNames();
+  void DumpEventMarker(unsigned marker);
+  void HandleInstrumentationEvent(unsigned event);
+  Counter* GetCounter(const char* name);
+
+  void InstrumentLoadStore(Instruction* instr);
+  void InstrumentLoadStorePair(Instruction* instr);
+
+  std::list<Counter*> counters_;
+
+  FILE *output_stream_;
+  uint64_t sample_period_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_INSTRUMENT_ARM64_H_
diff --git a/src/arm64/interface-descriptors-arm64.cc b/src/arm64/interface-descriptors-arm64.cc
new file mode 100644
index 0000000..690c8c2
--- /dev/null
+++ b/src/arm64/interface-descriptors-arm64.cc
@@ -0,0 +1,368 @@
+// Copyright 2012 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/interface-descriptors.h"
+
+namespace v8 {
+namespace internal {
+
+const Register CallInterfaceDescriptor::ContextRegister() { return cp; }
+
+
+const Register LoadDescriptor::ReceiverRegister() { return x1; }
+const Register LoadDescriptor::NameRegister() { return x2; }
+
+
+const Register VectorLoadICTrampolineDescriptor::SlotRegister() { return x0; }
+
+
+const Register VectorLoadICDescriptor::VectorRegister() { return x3; }
+
+
+const Register StoreDescriptor::ReceiverRegister() { return x1; }
+const Register StoreDescriptor::NameRegister() { return x2; }
+const Register StoreDescriptor::ValueRegister() { return x0; }
+
+
+const Register ElementTransitionAndStoreDescriptor::MapRegister() { return x3; }
+
+
+const Register InstanceofDescriptor::left() {
+  // Object to check (instanceof lhs).
+  return x11;
+}
+
+
+const Register InstanceofDescriptor::right() {
+  // Constructor function (instanceof rhs).
+  return x10;
+}
+
+
+const Register ArgumentsAccessReadDescriptor::index() { return x1; }
+const Register ArgumentsAccessReadDescriptor::parameter_count() { return x0; }
+
+
+const Register ApiGetterDescriptor::function_address() { return x2; }
+
+
+const Register MathPowTaggedDescriptor::exponent() { return x11; }
+
+
+const Register MathPowIntegerDescriptor::exponent() { return x12; }
+
+
+void FastNewClosureDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x2: function info
+  Register registers[] = {cp, x2};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void FastNewContextDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: function
+  Register registers[] = {cp, x1};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ToNumberDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x0: value
+  Register registers[] = {cp, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void NumberToStringDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x0: value
+  Register registers[] = {cp, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void FastCloneShallowArrayDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x3: array literals array
+  // x2: array literal index
+  // x1: constant elements
+  Register registers[] = {cp, x3, x2, x1};
+  Representation representations[] = {
+      Representation::Tagged(), Representation::Tagged(), Representation::Smi(),
+      Representation::Tagged()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void FastCloneShallowObjectDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x3: object literals array
+  // x2: object literal index
+  // x1: constant properties
+  // x0: object literal flags
+  Register registers[] = {cp, x3, x2, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CreateAllocationSiteDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x2: feedback vector
+  // x3: call feedback slot
+  Register registers[] = {cp, x2, x3};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void StoreArrayLiteralElementDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, x3, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CallFunctionDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // x1  function    the function to call
+  Register registers[] = {cp, x1};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void CallFunctionWithFeedbackDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  Register registers[] = {cp, x1, x3};
+  Representation representations[] = {Representation::Tagged(),
+                                      Representation::Tagged(),
+                                      Representation::Smi()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void CallConstructDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // x0 : number of arguments
+  // x1 : the function to call
+  // x2 : feedback vector
+  // x3 : slot in feedback vector (smi) (if r2 is not the megamorphic symbol)
+  // TODO(turbofan): So far we don't gather type feedback and hence skip the
+  // slot parameter, but ArrayConstructStub needs the vector to be undefined.
+  Register registers[] = {cp, x0, x1, x2};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void RegExpConstructResultDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x2: length
+  // x1: index (of last match)
+  // x0: string
+  Register registers[] = {cp, x2, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void TransitionElementsKindDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x0: value (js_array)
+  // x1: to_map
+  Register registers[] = {cp, x0, x1};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ArrayConstructorConstantArgCountDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: function
+  // x2: allocation site with elements kind
+  // x0: number of arguments to the constructor function
+  Register registers[] = {cp, x1, x2};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ArrayConstructorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // stack param count needs (constructor pointer, and single argument)
+  Register registers[] = {cp, x1, x2, x0};
+  Representation representations[] = {
+      Representation::Tagged(), Representation::Tagged(),
+      Representation::Tagged(), Representation::Integer32()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void InternalArrayConstructorConstantArgCountDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: constructor function
+  // x0: number of arguments to the constructor function
+  Register registers[] = {cp, x1};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void InternalArrayConstructorDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // stack param count needs (constructor pointer, and single argument)
+  Register registers[] = {cp, x1, x0};
+  Representation representations[] = {Representation::Tagged(),
+                                      Representation::Tagged(),
+                                      Representation::Integer32()};
+  data->Initialize(arraysize(registers), registers, representations);
+}
+
+
+void CompareNilDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x0: value to compare
+  Register registers[] = {cp, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void ToBooleanDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x0: value
+  Register registers[] = {cp, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void BinaryOpDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: left operand
+  // x0: right operand
+  Register registers[] = {cp, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void BinaryOpWithAllocationSiteDescriptor::Initialize(
+    CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x2: allocation site
+  // x1: left operand
+  // x0: right operand
+  Register registers[] = {cp, x2, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void StringAddDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  // cp: context
+  // x1: left operand
+  // x0: right operand
+  Register registers[] = {cp, x1, x0};
+  data->Initialize(arraysize(registers), registers, NULL);
+}
+
+
+void KeyedDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  static PlatformInterfaceDescriptor noInlineDescriptor =
+      PlatformInterfaceDescriptor(NEVER_INLINE_TARGET_ADDRESS);
+
+  Register registers[] = {
+      cp,  // context
+      x2,  // key
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // key
+  };
+  data->Initialize(arraysize(registers), registers, representations,
+                   &noInlineDescriptor);
+}
+
+
+void NamedDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  static PlatformInterfaceDescriptor noInlineDescriptor =
+      PlatformInterfaceDescriptor(NEVER_INLINE_TARGET_ADDRESS);
+
+  Register registers[] = {
+      cp,  // context
+      x2,  // name
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // name
+  };
+  data->Initialize(arraysize(registers), registers, representations,
+                   &noInlineDescriptor);
+}
+
+
+void CallHandlerDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  static PlatformInterfaceDescriptor default_descriptor =
+      PlatformInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
+
+  Register registers[] = {
+      cp,  // context
+      x0,  // receiver
+  };
+  Representation representations[] = {
+      Representation::Tagged(),  // context
+      Representation::Tagged(),  // receiver
+  };
+  data->Initialize(arraysize(registers), registers, representations,
+                   &default_descriptor);
+}
+
+
+void ArgumentAdaptorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  static PlatformInterfaceDescriptor default_descriptor =
+      PlatformInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
+
+  Register registers[] = {
+      cp,  // context
+      x1,  // JSFunction
+      x0,  // actual number of arguments
+      x2,  // expected number of arguments
+  };
+  Representation representations[] = {
+      Representation::Tagged(),     // context
+      Representation::Tagged(),     // JSFunction
+      Representation::Integer32(),  // actual number of arguments
+      Representation::Integer32(),  // expected number of arguments
+  };
+  data->Initialize(arraysize(registers), registers, representations,
+                   &default_descriptor);
+}
+
+
+void ApiFunctionDescriptor::Initialize(CallInterfaceDescriptorData* data) {
+  static PlatformInterfaceDescriptor default_descriptor =
+      PlatformInterfaceDescriptor(CAN_INLINE_TARGET_ADDRESS);
+
+  Register registers[] = {
+      cp,  // context
+      x0,  // callee
+      x4,  // call_data
+      x2,  // holder
+      x1,  // api_function_address
+  };
+  Representation representations[] = {
+      Representation::Tagged(),    // context
+      Representation::Tagged(),    // callee
+      Representation::Tagged(),    // call_data
+      Representation::Tagged(),    // holder
+      Representation::External(),  // api_function_address
+  };
+  data->Initialize(arraysize(registers), registers, representations,
+                   &default_descriptor);
+}
+}
+}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/interface-descriptors-arm64.h b/src/arm64/interface-descriptors-arm64.h
new file mode 100644
index 0000000..76def88
--- /dev/null
+++ b/src/arm64/interface-descriptors-arm64.h
@@ -0,0 +1,26 @@
+// Copyright 2012 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.
+
+#ifndef V8_ARM64_INTERFACE_DESCRIPTORS_ARM64_H_
+#define V8_ARM64_INTERFACE_DESCRIPTORS_ARM64_H_
+
+#include "src/interface-descriptors.h"
+
+namespace v8 {
+namespace internal {
+
+class PlatformInterfaceDescriptor {
+ public:
+  explicit PlatformInterfaceDescriptor(TargetAddressStorageMode storage_mode)
+      : storage_mode_(storage_mode) {}
+
+  TargetAddressStorageMode storage_mode() { return storage_mode_; }
+
+ private:
+  TargetAddressStorageMode storage_mode_;
+};
+}
+}  // namespace v8::internal
+
+#endif  // V8_ARM64_INTERFACE_DESCRIPTORS_ARM64_H_
diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc
new file mode 100644
index 0000000..502b046
--- /dev/null
+++ b/src/arm64/lithium-arm64.cc
@@ -0,0 +1,2755 @@
+// Copyright 2013 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/v8.h"
+
+#include "src/arm64/lithium-codegen-arm64.h"
+#include "src/hydrogen-osr.h"
+#include "src/lithium-inl.h"
+
+namespace v8 {
+namespace internal {
+
+#define DEFINE_COMPILE(type)                            \
+  void L##type::CompileToNative(LCodeGen* generator) {  \
+    generator->Do##type(this);                          \
+  }
+LITHIUM_CONCRETE_INSTRUCTION_LIST(DEFINE_COMPILE)
+#undef DEFINE_COMPILE
+
+#ifdef DEBUG
+void LInstruction::VerifyCall() {
+  // Call instructions can use only fixed registers as temporaries and
+  // outputs because all registers are blocked by the calling convention.
+  // Inputs operands must use a fixed register or use-at-start policy or
+  // a non-register policy.
+  DCHECK(Output() == NULL ||
+         LUnallocated::cast(Output())->HasFixedPolicy() ||
+         !LUnallocated::cast(Output())->HasRegisterPolicy());
+  for (UseIterator it(this); !it.Done(); it.Advance()) {
+    LUnallocated* operand = LUnallocated::cast(it.Current());
+    DCHECK(operand->HasFixedPolicy() ||
+           operand->IsUsedAtStart());
+  }
+  for (TempIterator it(this); !it.Done(); it.Advance()) {
+    LUnallocated* operand = LUnallocated::cast(it.Current());
+    DCHECK(operand->HasFixedPolicy() ||!operand->HasRegisterPolicy());
+  }
+}
+#endif
+
+
+void LLabel::PrintDataTo(StringStream* stream) {
+  LGap::PrintDataTo(stream);
+  LLabel* rep = replacement();
+  if (rep != NULL) {
+    stream->Add(" Dead block replaced with B%d", rep->block_id());
+  }
+}
+
+
+void LAccessArgumentsAt::PrintDataTo(StringStream* stream) {
+  arguments()->PrintTo(stream);
+  stream->Add(" length ");
+  length()->PrintTo(stream);
+  stream->Add(" index ");
+  index()->PrintTo(stream);
+}
+
+
+void LBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("B%d | B%d on ", true_block_id(), false_block_id());
+  value()->PrintTo(stream);
+}
+
+
+void LCallJSFunction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  function()->PrintTo(stream);
+  stream->Add("#%d / ", arity());
+}
+
+
+void LCallWithDescriptor::PrintDataTo(StringStream* stream) {
+  for (int i = 0; i < InputCount(); i++) {
+    InputAt(i)->PrintTo(stream);
+    stream->Add(" ");
+  }
+  stream->Add("#%d / ", arity());
+}
+
+
+void LCallNew::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  constructor()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+}
+
+
+void LCallNewArray::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  constructor()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+  ElementsKind kind = hydrogen()->elements_kind();
+  stream->Add(" (%s) ", ElementsKindToString(kind));
+}
+
+
+void LClassOfTestAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if class_of_test(");
+  value()->PrintTo(stream);
+  stream->Add(", \"%o\") then B%d else B%d",
+              *hydrogen()->class_name(),
+              true_block_id(),
+              false_block_id());
+}
+
+
+void LCompareNumericAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if ");
+  left()->PrintTo(stream);
+  stream->Add(" %s ", Token::String(op()));
+  right()->PrintTo(stream);
+  stream->Add(" then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LHasCachedArrayIndexAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if has_cached_array_index(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+bool LGoto::HasInterestingComment(LCodeGen* gen) const {
+  return !gen->IsNextEmittedBlock(block_id());
+}
+
+
+void LGoto::PrintDataTo(StringStream* stream) {
+  stream->Add("B%d", block_id());
+}
+
+
+void LInnerAllocatedObject::PrintDataTo(StringStream* stream) {
+  stream->Add(" = ");
+  base_object()->PrintTo(stream);
+  stream->Add(" + ");
+  offset()->PrintTo(stream);
+}
+
+
+void LInvokeFunction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  function()->PrintTo(stream);
+  stream->Add(" #%d / ", arity());
+}
+
+
+void LInstruction::PrintTo(StringStream* stream) {
+  stream->Add("%s ", this->Mnemonic());
+
+  PrintOutputOperandTo(stream);
+
+  PrintDataTo(stream);
+
+  if (HasEnvironment()) {
+    stream->Add(" ");
+    environment()->PrintTo(stream);
+  }
+
+  if (HasPointerMap()) {
+    stream->Add(" ");
+    pointer_map()->PrintTo(stream);
+  }
+}
+
+
+void LInstruction::PrintDataTo(StringStream* stream) {
+  stream->Add("= ");
+  for (int i = 0; i < InputCount(); i++) {
+    if (i > 0) stream->Add(" ");
+    if (InputAt(i) == NULL) {
+      stream->Add("NULL");
+    } else {
+      InputAt(i)->PrintTo(stream);
+    }
+  }
+}
+
+
+void LInstruction::PrintOutputOperandTo(StringStream* stream) {
+  if (HasResult()) result()->PrintTo(stream);
+}
+
+
+void LHasInstanceTypeAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if has_instance_type(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsObjectAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_object(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsStringAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_string(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LIsSmiAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_smi(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LTypeofIsAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if typeof ");
+  value()->PrintTo(stream);
+  stream->Add(" == \"%s\" then B%d else B%d",
+              hydrogen()->type_literal()->ToCString().get(),
+              true_block_id(), false_block_id());
+}
+
+
+void LIsUndetectableAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if is_undetectable(");
+  value()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+bool LGap::IsRedundant() const {
+  for (int i = 0; i < 4; i++) {
+    if ((parallel_moves_[i] != NULL) && !parallel_moves_[i]->IsRedundant()) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+
+void LGap::PrintDataTo(StringStream* stream) {
+  for (int i = 0; i < 4; i++) {
+    stream->Add("(");
+    if (parallel_moves_[i] != NULL) {
+      parallel_moves_[i]->PrintDataTo(stream);
+    }
+    stream->Add(") ");
+  }
+}
+
+
+void LLoadContextSlot::PrintDataTo(StringStream* stream) {
+  context()->PrintTo(stream);
+  stream->Add("[%d]", slot_index());
+}
+
+
+void LStoreCodeEntry::PrintDataTo(StringStream* stream) {
+  stream->Add(" = ");
+  function()->PrintTo(stream);
+  stream->Add(".code_entry = ");
+  code_object()->PrintTo(stream);
+}
+
+
+void LStoreContextSlot::PrintDataTo(StringStream* stream) {
+  context()->PrintTo(stream);
+  stream->Add("[%d] <- ", slot_index());
+  value()->PrintTo(stream);
+}
+
+
+void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add("[");
+  key()->PrintTo(stream);
+  stream->Add("] <- ");
+  value()->PrintTo(stream);
+}
+
+
+void LStoreNamedField::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  OStringStream os;
+  os << hydrogen()->access();
+  stream->Add(os.c_str());
+  stream->Add(" <- ");
+  value()->PrintTo(stream);
+}
+
+
+void LStoreNamedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add(".");
+  stream->Add(String::cast(*name())->ToCString().get());
+  stream->Add(" <- ");
+  value()->PrintTo(stream);
+}
+
+
+void LStringCompareAndBranch::PrintDataTo(StringStream* stream) {
+  stream->Add("if string_compare(");
+  left()->PrintTo(stream);
+  right()->PrintTo(stream);
+  stream->Add(") then B%d else B%d", true_block_id(), false_block_id());
+}
+
+
+void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add("%p -> %p", *original_map(), *transitioned_map());
+}
+
+
+template<int T>
+void LUnaryMathOperation<T>::PrintDataTo(StringStream* stream) {
+  value()->PrintTo(stream);
+}
+
+
+const char* LArithmeticD::Mnemonic() const {
+  switch (op()) {
+    case Token::ADD: return "add-d";
+    case Token::SUB: return "sub-d";
+    case Token::MUL: return "mul-d";
+    case Token::DIV: return "div-d";
+    case Token::MOD: return "mod-d";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+const char* LArithmeticT::Mnemonic() const {
+  switch (op()) {
+    case Token::ADD: return "add-t";
+    case Token::SUB: return "sub-t";
+    case Token::MUL: return "mul-t";
+    case Token::MOD: return "mod-t";
+    case Token::DIV: return "div-t";
+    case Token::BIT_AND: return "bit-and-t";
+    case Token::BIT_OR: return "bit-or-t";
+    case Token::BIT_XOR: return "bit-xor-t";
+    case Token::ROR: return "ror-t";
+    case Token::SHL: return "shl-t";
+    case Token::SAR: return "sar-t";
+    case Token::SHR: return "shr-t";
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
+  return new(zone()) LUnallocated(LUnallocated::FIXED_REGISTER,
+                                  Register::ToAllocationIndex(reg));
+}
+
+
+LUnallocated* LChunkBuilder::ToUnallocated(DoubleRegister reg) {
+  return new(zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
+                                  DoubleRegister::ToAllocationIndex(reg));
+}
+
+
+LOperand* LChunkBuilder::Use(HValue* value, LUnallocated* operand) {
+  if (value->EmitAtUses()) {
+    HInstruction* instr = HInstruction::cast(value);
+    VisitInstruction(instr);
+  }
+  operand->set_virtual_register(value->id());
+  return operand;
+}
+
+
+LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
+  return Use(value, ToUnallocated(fixed_register));
+}
+
+
+LOperand* LChunkBuilder::UseFixedDouble(HValue* value,
+                                        DoubleRegister fixed_register) {
+  return Use(value, ToUnallocated(fixed_register));
+}
+
+
+LOperand* LChunkBuilder::UseRegister(HValue* value) {
+  return Use(value, new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
+}
+
+
+LOperand* LChunkBuilder::UseRegisterAndClobber(HValue* value) {
+  return Use(value, new(zone()) LUnallocated(LUnallocated::WRITABLE_REGISTER));
+}
+
+
+LOperand* LChunkBuilder::UseRegisterAtStart(HValue* value) {
+  return Use(value,
+             new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER,
+                                      LUnallocated::USED_AT_START));
+}
+
+
+LOperand* LChunkBuilder::UseRegisterOrConstant(HValue* value) {
+  return value->IsConstant() ? UseConstant(value) : UseRegister(value);
+}
+
+
+LOperand* LChunkBuilder::UseRegisterOrConstantAtStart(HValue* value) {
+  return value->IsConstant() ? UseConstant(value) : UseRegisterAtStart(value);
+}
+
+
+LConstantOperand* LChunkBuilder::UseConstant(HValue* value) {
+  return chunk_->DefineConstantOperand(HConstant::cast(value));
+}
+
+
+LOperand* LChunkBuilder::UseAny(HValue* value) {
+  return value->IsConstant()
+      ? UseConstant(value)
+      : Use(value, new(zone()) LUnallocated(LUnallocated::ANY));
+}
+
+
+LInstruction* LChunkBuilder::Define(LTemplateResultInstruction<1>* instr,
+                                    LUnallocated* result) {
+  result->set_virtual_register(current_instruction_->id());
+  instr->set_result(result);
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::DefineAsRegister(
+    LTemplateResultInstruction<1>* instr) {
+  return Define(instr,
+                new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER));
+}
+
+
+LInstruction* LChunkBuilder::DefineAsSpilled(
+    LTemplateResultInstruction<1>* instr, int index) {
+  return Define(instr,
+                new(zone()) LUnallocated(LUnallocated::FIXED_SLOT, index));
+}
+
+
+LInstruction* LChunkBuilder::DefineSameAsFirst(
+    LTemplateResultInstruction<1>* instr) {
+  return Define(instr,
+                new(zone()) LUnallocated(LUnallocated::SAME_AS_FIRST_INPUT));
+}
+
+
+LInstruction* LChunkBuilder::DefineFixed(
+    LTemplateResultInstruction<1>* instr, Register reg) {
+  return Define(instr, ToUnallocated(reg));
+}
+
+
+LInstruction* LChunkBuilder::DefineFixedDouble(
+    LTemplateResultInstruction<1>* instr, DoubleRegister reg) {
+  return Define(instr, ToUnallocated(reg));
+}
+
+
+LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
+                                        HInstruction* hinstr,
+                                        CanDeoptimize can_deoptimize) {
+  info()->MarkAsNonDeferredCalling();
+#ifdef DEBUG
+  instr->VerifyCall();
+#endif
+  instr->MarkAsCall();
+  instr = AssignPointerMap(instr);
+
+  // If instruction does not have side-effects lazy deoptimization
+  // after the call will try to deoptimize to the point before the call.
+  // Thus we still need to attach environment to this call even if
+  // call sequence can not deoptimize eagerly.
+  bool needs_environment =
+      (can_deoptimize == CAN_DEOPTIMIZE_EAGERLY) ||
+      !hinstr->HasObservableSideEffects();
+  if (needs_environment && !instr->HasEnvironment()) {
+    instr = AssignEnvironment(instr);
+    // We can't really figure out if the environment is needed or not.
+    instr->environment()->set_has_been_used();
+  }
+
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
+  DCHECK(!instr->HasPointerMap());
+  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
+  return instr;
+}
+
+
+LUnallocated* LChunkBuilder::TempRegister() {
+  LUnallocated* operand =
+      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_REGISTER);
+  int vreg = allocator_->GetVirtualRegister();
+  if (!allocator_->AllocationOk()) {
+    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
+    vreg = 0;
+  }
+  operand->set_virtual_register(vreg);
+  return operand;
+}
+
+
+LUnallocated* LChunkBuilder::TempDoubleRegister() {
+  LUnallocated* operand =
+      new(zone()) LUnallocated(LUnallocated::MUST_HAVE_DOUBLE_REGISTER);
+  int vreg = allocator_->GetVirtualRegister();
+  if (!allocator_->AllocationOk()) {
+    Abort(kOutOfVirtualRegistersWhileTryingToAllocateTempRegister);
+    vreg = 0;
+  }
+  operand->set_virtual_register(vreg);
+  return operand;
+}
+
+
+int LPlatformChunk::GetNextSpillIndex() {
+  return spill_slot_count_++;
+}
+
+
+LOperand* LPlatformChunk::GetNextSpillSlot(RegisterKind kind) {
+  int index = GetNextSpillIndex();
+  if (kind == DOUBLE_REGISTERS) {
+    return LDoubleStackSlot::Create(index, zone());
+  } else {
+    DCHECK(kind == GENERAL_REGISTERS);
+    return LStackSlot::Create(index, zone());
+  }
+}
+
+
+LOperand* LChunkBuilder::FixedTemp(Register reg) {
+  LUnallocated* operand = ToUnallocated(reg);
+  DCHECK(operand->HasFixedPolicy());
+  return operand;
+}
+
+
+LOperand* LChunkBuilder::FixedTemp(DoubleRegister reg) {
+  LUnallocated* operand = ToUnallocated(reg);
+  DCHECK(operand->HasFixedPolicy());
+  return operand;
+}
+
+
+LPlatformChunk* LChunkBuilder::Build() {
+  DCHECK(is_unused());
+  chunk_ = new(zone()) LPlatformChunk(info_, graph_);
+  LPhase phase("L_Building chunk", chunk_);
+  status_ = BUILDING;
+
+  // If compiling for OSR, reserve space for the unoptimized frame,
+  // which will be subsumed into this frame.
+  if (graph()->has_osr()) {
+    // TODO(all): GetNextSpillIndex just increments a field. It has no other
+    // side effects, so we should get rid of this loop.
+    for (int i = graph()->osr()->UnoptimizedFrameSlots(); i > 0; i--) {
+      chunk_->GetNextSpillIndex();
+    }
+  }
+
+  const ZoneList<HBasicBlock*>* blocks = graph_->blocks();
+  for (int i = 0; i < blocks->length(); i++) {
+    DoBasicBlock(blocks->at(i));
+    if (is_aborted()) return NULL;
+  }
+  status_ = DONE;
+  return chunk_;
+}
+
+
+void LChunkBuilder::DoBasicBlock(HBasicBlock* block) {
+  DCHECK(is_building());
+  current_block_ = block;
+
+  if (block->IsStartBlock()) {
+    block->UpdateEnvironment(graph_->start_environment());
+    argument_count_ = 0;
+  } else if (block->predecessors()->length() == 1) {
+    // We have a single predecessor => copy environment and outgoing
+    // argument count from the predecessor.
+    DCHECK(block->phis()->length() == 0);
+    HBasicBlock* pred = block->predecessors()->at(0);
+    HEnvironment* last_environment = pred->last_environment();
+    DCHECK(last_environment != NULL);
+
+    // Only copy the environment, if it is later used again.
+    if (pred->end()->SecondSuccessor() == NULL) {
+      DCHECK(pred->end()->FirstSuccessor() == block);
+    } else {
+      if ((pred->end()->FirstSuccessor()->block_id() > block->block_id()) ||
+          (pred->end()->SecondSuccessor()->block_id() > block->block_id())) {
+        last_environment = last_environment->Copy();
+      }
+    }
+    block->UpdateEnvironment(last_environment);
+    DCHECK(pred->argument_count() >= 0);
+    argument_count_ = pred->argument_count();
+  } else {
+    // We are at a state join => process phis.
+    HBasicBlock* pred = block->predecessors()->at(0);
+    // No need to copy the environment, it cannot be used later.
+    HEnvironment* last_environment = pred->last_environment();
+    for (int i = 0; i < block->phis()->length(); ++i) {
+      HPhi* phi = block->phis()->at(i);
+      if (phi->HasMergedIndex()) {
+        last_environment->SetValueAt(phi->merged_index(), phi);
+      }
+    }
+    for (int i = 0; i < block->deleted_phis()->length(); ++i) {
+      if (block->deleted_phis()->at(i) < last_environment->length()) {
+        last_environment->SetValueAt(block->deleted_phis()->at(i),
+                                     graph_->GetConstantUndefined());
+      }
+    }
+    block->UpdateEnvironment(last_environment);
+    // Pick up the outgoing argument count of one of the predecessors.
+    argument_count_ = pred->argument_count();
+  }
+
+  // Translate hydrogen instructions to lithium ones for the current block.
+  HInstruction* current = block->first();
+  int start = chunk_->instructions()->length();
+  while ((current != NULL) && !is_aborted()) {
+    // Code for constants in registers is generated lazily.
+    if (!current->EmitAtUses()) {
+      VisitInstruction(current);
+    }
+    current = current->next();
+  }
+  int end = chunk_->instructions()->length() - 1;
+  if (end >= start) {
+    block->set_first_instruction_index(start);
+    block->set_last_instruction_index(end);
+  }
+  block->set_argument_count(argument_count_);
+  current_block_ = NULL;
+}
+
+
+void LChunkBuilder::VisitInstruction(HInstruction* current) {
+  HInstruction* old_current = current_instruction_;
+  current_instruction_ = current;
+
+  LInstruction* instr = NULL;
+  if (current->CanReplaceWithDummyUses()) {
+    if (current->OperandCount() == 0) {
+      instr = DefineAsRegister(new(zone()) LDummy());
+    } else {
+      DCHECK(!current->OperandAt(0)->IsControlInstruction());
+      instr = DefineAsRegister(new(zone())
+          LDummyUse(UseAny(current->OperandAt(0))));
+    }
+    for (int i = 1; i < current->OperandCount(); ++i) {
+      if (current->OperandAt(i)->IsControlInstruction()) continue;
+      LInstruction* dummy =
+          new(zone()) LDummyUse(UseAny(current->OperandAt(i)));
+      dummy->set_hydrogen_value(current);
+      chunk_->AddInstruction(dummy, current_block_);
+    }
+  } else {
+    HBasicBlock* successor;
+    if (current->IsControlInstruction() &&
+        HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
+        successor != NULL) {
+      instr = new(zone()) LGoto(successor);
+    } else {
+      instr = current->CompileToLithium(this);
+    }
+  }
+
+  argument_count_ += current->argument_delta();
+  DCHECK(argument_count_ >= 0);
+
+  if (instr != NULL) {
+    AddInstruction(instr, current);
+  }
+
+  current_instruction_ = old_current;
+}
+
+
+void LChunkBuilder::AddInstruction(LInstruction* instr,
+                                   HInstruction* hydrogen_val) {
+  // Associate the hydrogen instruction first, since we may need it for
+  // the ClobbersRegisters() or ClobbersDoubleRegisters() calls below.
+  instr->set_hydrogen_value(hydrogen_val);
+
+#if DEBUG
+  // Make sure that the lithium instruction has either no fixed register
+  // constraints in temps or the result OR no uses that are only used at
+  // start. If this invariant doesn't hold, the register allocator can decide
+  // to insert a split of a range immediately before the instruction due to an
+  // already allocated register needing to be used for the instruction's fixed
+  // register constraint. In this case, the register allocator won't see an
+  // interference between the split child and the use-at-start (it would if
+  // the it was just a plain use), so it is free to move the split child into
+  // the same register that is used for the use-at-start.
+  // See https://code.google.com/p/chromium/issues/detail?id=201590
+  if (!(instr->ClobbersRegisters() &&
+        instr->ClobbersDoubleRegisters(isolate()))) {
+    int fixed = 0;
+    int used_at_start = 0;
+    for (UseIterator it(instr); !it.Done(); it.Advance()) {
+      LUnallocated* operand = LUnallocated::cast(it.Current());
+      if (operand->IsUsedAtStart()) ++used_at_start;
+    }
+    if (instr->Output() != NULL) {
+      if (LUnallocated::cast(instr->Output())->HasFixedPolicy()) ++fixed;
+    }
+    for (TempIterator it(instr); !it.Done(); it.Advance()) {
+      LUnallocated* operand = LUnallocated::cast(it.Current());
+      if (operand->HasFixedPolicy()) ++fixed;
+    }
+    DCHECK(fixed == 0 || used_at_start == 0);
+  }
+#endif
+
+  if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
+    instr = AssignPointerMap(instr);
+  }
+  if (FLAG_stress_environments && !instr->HasEnvironment()) {
+    instr = AssignEnvironment(instr);
+  }
+  chunk_->AddInstruction(instr, current_block_);
+
+  if (instr->IsCall()) {
+    HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
+    LInstruction* instruction_needing_environment = NULL;
+    if (hydrogen_val->HasObservableSideEffects()) {
+      HSimulate* sim = HSimulate::cast(hydrogen_val->next());
+      instruction_needing_environment = instr;
+      sim->ReplayEnvironment(current_block_->last_environment());
+      hydrogen_value_for_lazy_bailout = sim;
+    }
+    LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
+    bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
+    chunk_->AddInstruction(bailout, current_block_);
+    if (instruction_needing_environment != NULL) {
+      // Store the lazy deopt environment with the instruction if needed.
+      // Right now it is only used for LInstanceOfKnownGlobal.
+      instruction_needing_environment->
+          SetDeferredLazyDeoptimizationEnvironment(bailout->environment());
+    }
+  }
+}
+
+
+LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
+  HEnvironment* hydrogen_env = current_block_->last_environment();
+  int argument_index_accumulator = 0;
+  ZoneList<HValue*> objects_to_materialize(0, zone());
+  instr->set_environment(CreateEnvironment(hydrogen_env,
+                                           &argument_index_accumulator,
+                                           &objects_to_materialize));
+  return instr;
+}
+
+
+LInstruction* LChunkBuilder::DoAbnormalExit(HAbnormalExit* instr) {
+  // The control instruction marking the end of a block that completed
+  // abruptly (e.g., threw an exception). There is nothing specific to do.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoArithmeticD(Token::Value op,
+                                           HArithmeticBinaryOperation* instr) {
+  DCHECK(instr->representation().IsDouble());
+  DCHECK(instr->left()->representation().IsDouble());
+  DCHECK(instr->right()->representation().IsDouble());
+
+  if (op == Token::MOD) {
+    LOperand* left = UseFixedDouble(instr->left(), d0);
+    LOperand* right = UseFixedDouble(instr->right(), d1);
+    LArithmeticD* result = new(zone()) LArithmeticD(Token::MOD, left, right);
+    return MarkAsCall(DefineFixedDouble(result, d0), instr);
+  } else {
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterAtStart(instr->right());
+    LArithmeticD* result = new(zone()) LArithmeticD(op, left, right);
+    return DefineAsRegister(result);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoArithmeticT(Token::Value op,
+                                           HBinaryOperation* instr) {
+  DCHECK((op == Token::ADD) || (op == Token::SUB) || (op == Token::MUL) ||
+         (op == Token::DIV) || (op == Token::MOD) || (op == Token::SHR) ||
+         (op == Token::SHL) || (op == Token::SAR) || (op == Token::ROR) ||
+         (op == Token::BIT_OR) || (op == Token::BIT_AND) ||
+         (op == Token::BIT_XOR));
+  HValue* left = instr->left();
+  HValue* right = instr->right();
+
+  // TODO(jbramley): Once we've implemented smi support for all arithmetic
+  // operations, these assertions should check IsTagged().
+  DCHECK(instr->representation().IsSmiOrTagged());
+  DCHECK(left->representation().IsSmiOrTagged());
+  DCHECK(right->representation().IsSmiOrTagged());
+
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left_operand = UseFixed(left, x1);
+  LOperand* right_operand = UseFixed(right, x0);
+  LArithmeticT* result =
+      new(zone()) LArithmeticT(op, context, left_operand, right_operand);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoBoundsCheckBaseIndexInformation(
+    HBoundsCheckBaseIndexInformation* instr) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoAccessArgumentsAt(HAccessArgumentsAt* instr) {
+  info()->MarkAsRequiresFrame();
+  LOperand* args = NULL;
+  LOperand* length = NULL;
+  LOperand* index = NULL;
+
+  if (instr->length()->IsConstant() && instr->index()->IsConstant()) {
+    args = UseRegisterAtStart(instr->arguments());
+    length = UseConstant(instr->length());
+    index = UseConstant(instr->index());
+  } else {
+    args = UseRegister(instr->arguments());
+    length = UseRegisterAtStart(instr->length());
+    index = UseRegisterOrConstantAtStart(instr->index());
+  }
+
+  return DefineAsRegister(new(zone()) LAccessArgumentsAt(args, length, index));
+}
+
+
+LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+
+    LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
+    if (shifted_operation != NULL) {
+      return shifted_operation;
+    }
+
+    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
+    LOperand* right =
+        UseRegisterOrConstantAtStart(instr->BetterRightOperand());
+    LInstruction* result = instr->representation().IsSmi() ?
+        DefineAsRegister(new(zone()) LAddS(left, right)) :
+        DefineAsRegister(new(zone()) LAddI(left, right));
+    if (instr->CheckFlag(HValue::kCanOverflow)) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  } else if (instr->representation().IsExternal()) {
+    DCHECK(instr->left()->representation().IsExternal());
+    DCHECK(instr->right()->representation().IsInteger32());
+    DCHECK(!instr->CheckFlag(HValue::kCanOverflow));
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+    return DefineAsRegister(new(zone()) LAddE(left, right));
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::ADD, instr);
+  } else {
+    DCHECK(instr->representation().IsTagged());
+    return DoArithmeticT(Token::ADD, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoAllocate(HAllocate* instr) {
+  info()->MarkAsDeferredCalling();
+  LOperand* context = UseAny(instr->context());
+  LOperand* size = UseRegisterOrConstant(instr->size());
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+  LOperand* temp3 = instr->MustPrefillWithFiller() ? TempRegister() : NULL;
+  LAllocate* result = new(zone()) LAllocate(context, size, temp1, temp2, temp3);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoApplyArguments(HApplyArguments* instr) {
+  LOperand* function = UseFixed(instr->function(), x1);
+  LOperand* receiver = UseFixed(instr->receiver(), x0);
+  LOperand* length = UseFixed(instr->length(), x2);
+  LOperand* elements = UseFixed(instr->elements(), x3);
+  LApplyArguments* result = new(zone()) LApplyArguments(function,
+                                                        receiver,
+                                                        length,
+                                                        elements);
+  return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsElements(HArgumentsElements* instr) {
+  info()->MarkAsRequiresFrame();
+  LOperand* temp = instr->from_inlined() ? NULL : TempRegister();
+  return DefineAsRegister(new(zone()) LArgumentsElements(temp));
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsLength(HArgumentsLength* instr) {
+  info()->MarkAsRequiresFrame();
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new(zone()) LArgumentsLength(value));
+}
+
+
+LInstruction* LChunkBuilder::DoArgumentsObject(HArgumentsObject* instr) {
+  // There are no real uses of the arguments object.
+  // arguments.length and element access are supported directly on
+  // stack arguments, and any real arguments object use causes a bailout.
+  // So this value is never used.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoBitwise(HBitwise* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    DCHECK(instr->CheckFlag(HValue::kTruncatingToInt32));
+
+    LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
+    if (shifted_operation != NULL) {
+      return shifted_operation;
+    }
+
+    LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
+    LOperand* right =
+        UseRegisterOrConstantAtStart(instr->BetterRightOperand());
+    return instr->representation().IsSmi() ?
+        DefineAsRegister(new(zone()) LBitS(left, right)) :
+        DefineAsRegister(new(zone()) LBitI(left, right));
+  } else {
+    return DoArithmeticT(instr->op(), instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoBlockEntry(HBlockEntry* instr) {
+  // V8 expects a label to be generated for each basic block.
+  // This is used in some places like LAllocator::IsBlockBoundary
+  // in lithium-allocator.cc
+  return new(zone()) LLabel(instr->block());
+}
+
+
+LInstruction* LChunkBuilder::DoBoundsCheck(HBoundsCheck* instr) {
+  if (!FLAG_debug_code && instr->skip_check()) return NULL;
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+  LOperand* length = !index->IsConstantOperand()
+      ? UseRegisterOrConstantAtStart(instr->length())
+      : UseRegisterAtStart(instr->length());
+  LInstruction* result = new(zone()) LBoundsCheck(index, length);
+  if (!FLAG_debug_code || !instr->skip_check()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
+  HValue* value = instr->value();
+  Representation r = value->representation();
+  HType type = value->type();
+
+  if (r.IsInteger32() || r.IsSmi() || r.IsDouble()) {
+    // These representations have simple checks that cannot deoptimize.
+    return new(zone()) LBranch(UseRegister(value), NULL, NULL);
+  } else {
+    DCHECK(r.IsTagged());
+    if (type.IsBoolean() || type.IsSmi() || type.IsJSArray() ||
+        type.IsHeapNumber()) {
+      // These types have simple checks that cannot deoptimize.
+      return new(zone()) LBranch(UseRegister(value), NULL, NULL);
+    }
+
+    if (type.IsString()) {
+      // This type cannot deoptimize, but needs a scratch register.
+      return new(zone()) LBranch(UseRegister(value), TempRegister(), NULL);
+    }
+
+    ToBooleanStub::Types expected = instr->expected_input_types();
+    bool needs_temps = expected.NeedsMap() || expected.IsEmpty();
+    LOperand* temp1 = needs_temps ? TempRegister() : NULL;
+    LOperand* temp2 = needs_temps ? TempRegister() : NULL;
+
+    if (expected.IsGeneric() || expected.IsEmpty()) {
+      // The generic case cannot deoptimize because it already supports every
+      // possible input type.
+      DCHECK(needs_temps);
+      return new(zone()) LBranch(UseRegister(value), temp1, temp2);
+    } else {
+      return AssignEnvironment(
+          new(zone()) LBranch(UseRegister(value), temp1, temp2));
+    }
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoCallJSFunction(
+    HCallJSFunction* instr) {
+  LOperand* function = UseFixed(instr->function(), x1);
+
+  LCallJSFunction* result = new(zone()) LCallJSFunction(function);
+
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallWithDescriptor(
+    HCallWithDescriptor* instr) {
+  CallInterfaceDescriptor descriptor = instr->descriptor();
+
+  LOperand* target = UseRegisterOrConstantAtStart(instr->target());
+  ZoneList<LOperand*> ops(instr->OperandCount(), zone());
+  ops.Add(target, zone());
+  for (int i = 1; i < instr->OperandCount(); i++) {
+    LOperand* op =
+        UseFixed(instr->OperandAt(i), descriptor.GetParameterRegister(i - 1));
+    ops.Add(op, zone());
+  }
+
+  LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(descriptor,
+                                                                ops,
+                                                                zone());
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallFunction(HCallFunction* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* function = UseFixed(instr->function(), x1);
+  LCallFunction* call = new(zone()) LCallFunction(context, function);
+  return MarkAsCall(DefineFixed(call, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallNew(HCallNew* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  // The call to CallConstructStub will expect the constructor to be in x1.
+  LOperand* constructor = UseFixed(instr->constructor(), x1);
+  LCallNew* result = new(zone()) LCallNew(context, constructor);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallNewArray(HCallNewArray* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  // The call to ArrayConstructCode will expect the constructor to be in x1.
+  LOperand* constructor = UseFixed(instr->constructor(), x1);
+  LCallNewArray* result = new(zone()) LCallNewArray(context, constructor);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallRuntime(HCallRuntime* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new(zone()) LCallRuntime(context), x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCallStub(HCallStub* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(DefineFixed(new(zone()) LCallStub(context), x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCapturedObject(HCapturedObject* instr) {
+  instr->ReplayEnvironment(current_block_->last_environment());
+
+  // There are no real uses of a captured object.
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoChange(HChange* instr) {
+  Representation from = instr->from();
+  Representation to = instr->to();
+  HValue* val = instr->value();
+  if (from.IsSmi()) {
+    if (to.IsTagged()) {
+      LOperand* value = UseRegister(val);
+      return DefineSameAsFirst(new(zone()) LDummyUse(value));
+    }
+    from = Representation::Tagged();
+  }
+  if (from.IsTagged()) {
+    if (to.IsDouble()) {
+      LOperand* value = UseRegister(val);
+      LOperand* temp = TempRegister();
+      LInstruction* result =
+          DefineAsRegister(new(zone()) LNumberUntagD(value, temp));
+      if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+      return result;
+    } else if (to.IsSmi()) {
+      LOperand* value = UseRegister(val);
+      if (val->type().IsSmi()) {
+        return DefineSameAsFirst(new(zone()) LDummyUse(value));
+      }
+      return AssignEnvironment(DefineSameAsFirst(new(zone()) LCheckSmi(value)));
+    } else {
+      DCHECK(to.IsInteger32());
+      if (val->type().IsSmi() || val->representation().IsSmi()) {
+        LOperand* value = UseRegisterAtStart(val);
+        return DefineAsRegister(new(zone()) LSmiUntag(value, false));
+      } else {
+        LOperand* value = UseRegister(val);
+        LOperand* temp1 = TempRegister();
+        LOperand* temp2 = instr->CanTruncateToInt32()
+            ? NULL : TempDoubleRegister();
+        LInstruction* result =
+            DefineAsRegister(new(zone()) LTaggedToI(value, temp1, temp2));
+        if (!val->representation().IsSmi()) result = AssignEnvironment(result);
+        return result;
+      }
+    }
+  } else if (from.IsDouble()) {
+    if (to.IsTagged()) {
+      info()->MarkAsDeferredCalling();
+      LOperand* value = UseRegister(val);
+      LOperand* temp1 = TempRegister();
+      LOperand* temp2 = TempRegister();
+      LNumberTagD* result = new(zone()) LNumberTagD(value, temp1, temp2);
+      return AssignPointerMap(DefineAsRegister(result));
+    } else {
+      DCHECK(to.IsSmi() || to.IsInteger32());
+      if (instr->CanTruncateToInt32()) {
+        LOperand* value = UseRegister(val);
+        return DefineAsRegister(new(zone()) LTruncateDoubleToIntOrSmi(value));
+      } else {
+        LOperand* value = UseRegister(val);
+        LDoubleToIntOrSmi* result = new(zone()) LDoubleToIntOrSmi(value);
+        return AssignEnvironment(DefineAsRegister(result));
+      }
+    }
+  } else if (from.IsInteger32()) {
+    info()->MarkAsDeferredCalling();
+    if (to.IsTagged()) {
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        LOperand* value = UseRegister(val);
+        LNumberTagU* result =
+            new(zone()) LNumberTagU(value, TempRegister(), TempRegister());
+        return AssignPointerMap(DefineAsRegister(result));
+      } else {
+        STATIC_ASSERT((kMinInt == Smi::kMinValue) &&
+                      (kMaxInt == Smi::kMaxValue));
+        LOperand* value = UseRegisterAtStart(val);
+        return DefineAsRegister(new(zone()) LSmiTag(value));
+      }
+    } else if (to.IsSmi()) {
+      LOperand* value = UseRegisterAtStart(val);
+      LInstruction* result = DefineAsRegister(new(zone()) LSmiTag(value));
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        result = AssignEnvironment(result);
+      }
+      return result;
+    } else {
+      DCHECK(to.IsDouble());
+      if (val->CheckFlag(HInstruction::kUint32)) {
+        return DefineAsRegister(
+            new(zone()) LUint32ToDouble(UseRegisterAtStart(val)));
+      } else {
+        return DefineAsRegister(
+            new(zone()) LInteger32ToDouble(UseRegisterAtStart(val)));
+      }
+    }
+  }
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoCheckValue(HCheckValue* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return AssignEnvironment(new(zone()) LCheckValue(value));
+}
+
+
+LInstruction* LChunkBuilder::DoCheckInstanceType(HCheckInstanceType* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  LInstruction* result = new(zone()) LCheckInstanceType(value, temp);
+  return AssignEnvironment(result);
+}
+
+
+LInstruction* LChunkBuilder::DoCheckMaps(HCheckMaps* instr) {
+  if (instr->IsStabilityCheck()) return new(zone()) LCheckMaps;
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  LInstruction* result = AssignEnvironment(new(zone()) LCheckMaps(value, temp));
+  if (instr->HasMigrationTarget()) {
+    info()->MarkAsDeferredCalling();
+    result = AssignPointerMap(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoCheckHeapObject(HCheckHeapObject* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LInstruction* result = new(zone()) LCheckNonSmi(value);
+  if (!instr->value()->type().IsHeapObject()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoCheckSmi(HCheckSmi* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return AssignEnvironment(new(zone()) LCheckSmi(value));
+}
+
+
+LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
+  HValue* value = instr->value();
+  Representation input_rep = value->representation();
+  LOperand* reg = UseRegister(value);
+  if (input_rep.IsDouble()) {
+    return DefineAsRegister(new(zone()) LClampDToUint8(reg));
+  } else if (input_rep.IsInteger32()) {
+    return DefineAsRegister(new(zone()) LClampIToUint8(reg));
+  } else {
+    DCHECK(input_rep.IsSmiOrTagged());
+    return AssignEnvironment(
+        DefineAsRegister(new(zone()) LClampTToUint8(reg,
+                                                    TempDoubleRegister())));
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoClassOfTestAndBranch(
+    HClassOfTestAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new(zone()) LClassOfTestAndBranch(value,
+                                           TempRegister(),
+                                           TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoCompareNumericAndBranch(
+    HCompareNumericAndBranch* instr) {
+  Representation r = instr->representation();
+  if (r.IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(r));
+    DCHECK(instr->right()->representation().Equals(r));
+    LOperand* left = UseRegisterOrConstantAtStart(instr->left());
+    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+    return new(zone()) LCompareNumericAndBranch(left, right);
+  } else {
+    DCHECK(r.IsDouble());
+    DCHECK(instr->left()->representation().IsDouble());
+    DCHECK(instr->right()->representation().IsDouble());
+    if (instr->left()->IsConstant() && instr->right()->IsConstant()) {
+      LOperand* left = UseConstant(instr->left());
+      LOperand* right = UseConstant(instr->right());
+      return new(zone()) LCompareNumericAndBranch(left, right);
+    }
+    LOperand* left = UseRegisterAtStart(instr->left());
+    LOperand* right = UseRegisterAtStart(instr->right());
+    return new(zone()) LCompareNumericAndBranch(left, right);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoCompareGeneric(HCompareGeneric* instr) {
+  DCHECK(instr->left()->representation().IsTagged());
+  DCHECK(instr->right()->representation().IsTagged());
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), x1);
+  LOperand* right = UseFixed(instr->right(), x0);
+  LCmpT* result = new(zone()) LCmpT(context, left, right);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
+    HCompareHoleAndBranch* instr) {
+  LOperand* value = UseRegister(instr->value());
+  if (instr->representation().IsTagged()) {
+    return new(zone()) LCmpHoleAndBranchT(value);
+  } else {
+    LOperand* temp = TempRegister();
+    return new(zone()) LCmpHoleAndBranchD(value, temp);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoCompareObjectEqAndBranch(
+    HCompareObjectEqAndBranch* instr) {
+  LOperand* left = UseRegisterAtStart(instr->left());
+  LOperand* right = UseRegisterAtStart(instr->right());
+  return new(zone()) LCmpObjectEqAndBranch(left, right);
+}
+
+
+LInstruction* LChunkBuilder::DoCompareMap(HCompareMap* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  return new(zone()) LCmpMapAndBranch(value, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoConstant(HConstant* instr) {
+  Representation r = instr->representation();
+  if (r.IsSmi()) {
+    return DefineAsRegister(new(zone()) LConstantS);
+  } else if (r.IsInteger32()) {
+    return DefineAsRegister(new(zone()) LConstantI);
+  } else if (r.IsDouble()) {
+    return DefineAsRegister(new(zone()) LConstantD);
+  } else if (r.IsExternal()) {
+    return DefineAsRegister(new(zone()) LConstantE);
+  } else if (r.IsTagged()) {
+    return DefineAsRegister(new(zone()) LConstantT);
+  } else {
+    UNREACHABLE();
+    return NULL;
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoContext(HContext* instr) {
+  if (instr->HasNoUses()) return NULL;
+
+  if (info()->IsStub()) {
+    return DefineFixed(new(zone()) LContext, cp);
+  }
+
+  return DefineAsRegister(new(zone()) LContext);
+}
+
+
+LInstruction* LChunkBuilder::DoDateField(HDateField* instr) {
+  LOperand* object = UseFixed(instr->value(), x0);
+  LDateField* result = new(zone()) LDateField(object, instr->index());
+  return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoDebugBreak(HDebugBreak* instr) {
+  return new(zone()) LDebugBreak();
+}
+
+
+LInstruction* LChunkBuilder::DoDeclareGlobals(HDeclareGlobals* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(new(zone()) LDeclareGlobals(context), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoDeoptimize(HDeoptimize* instr) {
+  return AssignEnvironment(new(zone()) LDeoptimize);
+}
+
+
+LInstruction* LChunkBuilder::DoDivByPowerOf2I(HDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result = DefineAsRegister(new(zone()) LDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kCanOverflow) && divisor == -1) ||
+      (!instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
+       divisor != 1 && divisor != -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDivByConstI(HDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
+      ? NULL : TempRegister();
+  LInstruction* result = DefineAsRegister(new(zone()) LDivByConstI(
+          dividend, divisor, temp));
+  if (divisor == 0 ||
+      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      !instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDivI(HBinaryOperation* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LOperand* temp = instr->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)
+      ? NULL : TempRegister();
+  LInstruction* result =
+      DefineAsRegister(new(zone()) LDivI(dividend, divisor, temp));
+  if (!instr->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoDiv(HDiv* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    if (instr->RightIsPowerOf2()) {
+      return DoDivByPowerOf2I(instr);
+    } else if (instr->right()->IsConstant()) {
+      return DoDivByConstI(instr);
+    } else {
+      return DoDivI(instr);
+    }
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::DIV, instr);
+  } else {
+    return DoArithmeticT(Token::DIV, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoDummyUse(HDummyUse* instr) {
+  return DefineAsRegister(new(zone()) LDummyUse(UseAny(instr->value())));
+}
+
+
+LInstruction* LChunkBuilder::DoEnterInlined(HEnterInlined* instr) {
+  HEnvironment* outer = current_block_->last_environment();
+  outer->set_ast_id(instr->ReturnId());
+  HConstant* undefined = graph()->GetConstantUndefined();
+  HEnvironment* inner = outer->CopyForInlining(instr->closure(),
+                                               instr->arguments_count(),
+                                               instr->function(),
+                                               undefined,
+                                               instr->inlining_kind());
+  // Only replay binding of arguments object if it wasn't removed from graph.
+  if ((instr->arguments_var() != NULL) &&
+      instr->arguments_object()->IsLinked()) {
+    inner->Bind(instr->arguments_var(), instr->arguments_object());
+  }
+  inner->BindContext(instr->closure_context());
+  inner->set_entry(instr);
+  current_block_->UpdateEnvironment(inner);
+  chunk_->AddInlinedClosure(instr->closure());
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoEnvironmentMarker(HEnvironmentMarker* instr) {
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoForceRepresentation(
+    HForceRepresentation* instr) {
+  // All HForceRepresentation instructions should be eliminated in the
+  // representation change phase of Hydrogen.
+  UNREACHABLE();
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoFunctionLiteral(HFunctionLiteral* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(
+      DefineFixed(new(zone()) LFunctionLiteral(context), x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoGetCachedArrayIndex(
+    HGetCachedArrayIndex* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new(zone()) LGetCachedArrayIndex(value));
+}
+
+
+LInstruction* LChunkBuilder::DoGoto(HGoto* instr) {
+  return new(zone()) LGoto(instr->FirstSuccessor());
+}
+
+
+LInstruction* LChunkBuilder::DoHasCachedArrayIndexAndBranch(
+    HHasCachedArrayIndexAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  return new(zone()) LHasCachedArrayIndexAndBranch(
+      UseRegisterAtStart(instr->value()), TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoHasInstanceTypeAndBranch(
+    HHasInstanceTypeAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new(zone()) LHasInstanceTypeAndBranch(value, TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoInnerAllocatedObject(
+    HInnerAllocatedObject* instr) {
+  LOperand* base_object = UseRegisterAtStart(instr->base_object());
+  LOperand* offset = UseRegisterOrConstantAtStart(instr->offset());
+  return DefineAsRegister(
+      new(zone()) LInnerAllocatedObject(base_object, offset));
+}
+
+
+LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LInstanceOf* result = new(zone()) LInstanceOf(
+      context,
+      UseFixed(instr->left(), InstanceofStub::left()),
+      UseFixed(instr->right(), InstanceofStub::right()));
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoInstanceOfKnownGlobal(
+    HInstanceOfKnownGlobal* instr) {
+  LInstanceOfKnownGlobal* result = new(zone()) LInstanceOfKnownGlobal(
+      UseFixed(instr->context(), cp),
+      UseFixed(instr->left(), InstanceofStub::left()));
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTailCallThroughMegamorphicCache(
+    HTailCallThroughMegamorphicCache* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* receiver_register =
+      UseFixed(instr->receiver(), LoadDescriptor::ReceiverRegister());
+  LOperand* name_register =
+      UseFixed(instr->name(), LoadDescriptor::NameRegister());
+  // Not marked as call. It can't deoptimize, and it never returns.
+  return new (zone()) LTailCallThroughMegamorphicCache(
+      context, receiver_register, name_register);
+}
+
+
+LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  // The function is required (by MacroAssembler::InvokeFunction) to be in x1.
+  LOperand* function = UseFixed(instr->function(), x1);
+  LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
+  return MarkAsCall(DefineFixed(result, x0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoIsConstructCallAndBranch(
+    HIsConstructCallAndBranch* instr) {
+  return new(zone()) LIsConstructCallAndBranch(TempRegister(), TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
+    HCompareMinusZeroAndBranch* instr) {
+  LOperand* value = UseRegister(instr->value());
+  LOperand* scratch = TempRegister();
+  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+}
+
+
+LInstruction* LChunkBuilder::DoIsObjectAndBranch(HIsObjectAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+  return new(zone()) LIsObjectAndBranch(value, temp1, temp2);
+}
+
+
+LInstruction* LChunkBuilder::DoIsStringAndBranch(HIsStringAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp = TempRegister();
+  return new(zone()) LIsStringAndBranch(value, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoIsSmiAndBranch(HIsSmiAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  return new(zone()) LIsSmiAndBranch(UseRegisterAtStart(instr->value()));
+}
+
+
+LInstruction* LChunkBuilder::DoIsUndetectableAndBranch(
+    HIsUndetectableAndBranch* instr) {
+  DCHECK(instr->value()->representation().IsTagged());
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new(zone()) LIsUndetectableAndBranch(value, TempRegister());
+}
+
+
+LInstruction* LChunkBuilder::DoLeaveInlined(HLeaveInlined* instr) {
+  LInstruction* pop = NULL;
+  HEnvironment* env = current_block_->last_environment();
+
+  if (env->entry()->arguments_pushed()) {
+    int argument_count = env->arguments_environment()->parameter_count();
+    pop = new(zone()) LDrop(argument_count);
+    DCHECK(instr->argument_delta() == -argument_count);
+  }
+
+  HEnvironment* outer =
+      current_block_->last_environment()->DiscardInlined(false);
+  current_block_->UpdateEnvironment(outer);
+
+  return pop;
+}
+
+
+LInstruction* LChunkBuilder::DoLoadContextSlot(HLoadContextSlot* instr) {
+  LOperand* context = UseRegisterAtStart(instr->value());
+  LInstruction* result =
+      DefineAsRegister(new(zone()) LLoadContextSlot(context));
+  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoLoadFunctionPrototype(
+    HLoadFunctionPrototype* instr) {
+  LOperand* function = UseRegister(instr->function());
+  LOperand* temp = TempRegister();
+  return AssignEnvironment(DefineAsRegister(
+      new(zone()) LLoadFunctionPrototype(function, temp)));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalCell(HLoadGlobalCell* instr) {
+  LLoadGlobalCell* result = new(zone()) LLoadGlobalCell();
+  return instr->RequiresHoleCheck()
+      ? AssignEnvironment(DefineAsRegister(result))
+      : DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadGlobalGeneric(HLoadGlobalGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* global_object =
+      UseFixed(instr->global_object(), LoadDescriptor::ReceiverRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+
+  LLoadGlobalGeneric* result =
+      new(zone()) LLoadGlobalGeneric(context, global_object, vector);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) {
+  DCHECK(instr->key()->representation().IsSmiOrInteger32());
+  ElementsKind elements_kind = instr->elements_kind();
+  LOperand* elements = UseRegister(instr->elements());
+  LOperand* key = UseRegisterOrConstant(instr->key());
+
+  if (!instr->is_typed_elements()) {
+    if (instr->representation().IsDouble()) {
+      LOperand* temp = (!instr->key()->IsConstant() ||
+                        instr->RequiresHoleCheck())
+             ? TempRegister()
+             : NULL;
+
+      LLoadKeyedFixedDouble* result =
+          new(zone()) LLoadKeyedFixedDouble(elements, key, temp);
+      return instr->RequiresHoleCheck()
+          ? AssignEnvironment(DefineAsRegister(result))
+          : DefineAsRegister(result);
+    } else {
+      DCHECK(instr->representation().IsSmiOrTagged() ||
+             instr->representation().IsInteger32());
+      LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
+      LLoadKeyedFixed* result =
+          new(zone()) LLoadKeyedFixed(elements, key, temp);
+      return instr->RequiresHoleCheck()
+          ? AssignEnvironment(DefineAsRegister(result))
+          : DefineAsRegister(result);
+    }
+  } else {
+    DCHECK((instr->representation().IsInteger32() &&
+            !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
+           (instr->representation().IsDouble() &&
+            IsDoubleOrFloatElementsKind(instr->elements_kind())));
+
+    LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister();
+    LInstruction* result = DefineAsRegister(
+        new(zone()) LLoadKeyedExternal(elements, key, temp));
+    if ((elements_kind == EXTERNAL_UINT32_ELEMENTS ||
+         elements_kind == UINT32_ELEMENTS) &&
+        !instr->CheckFlag(HInstruction::kUint32)) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
+  LOperand* key = UseFixed(instr->key(), LoadDescriptor::NameRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+
+  LInstruction* result =
+      DefineFixed(new(zone()) LLoadKeyedGeneric(context, object, key, vector),
+                  x0);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadNamedField(HLoadNamedField* instr) {
+  LOperand* object = UseRegisterAtStart(instr->object());
+  return DefineAsRegister(new(zone()) LLoadNamedField(object));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadNamedGeneric(HLoadNamedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), LoadDescriptor::ReceiverRegister());
+  LOperand* vector = NULL;
+  if (FLAG_vector_ics) {
+    vector = FixedTemp(VectorLoadICDescriptor::VectorRegister());
+  }
+
+  LInstruction* result =
+      DefineFixed(new(zone()) LLoadNamedGeneric(context, object, vector), x0);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoLoadRoot(HLoadRoot* instr) {
+  return DefineAsRegister(new(zone()) LLoadRoot);
+}
+
+
+LInstruction* LChunkBuilder::DoMapEnumLength(HMapEnumLength* instr) {
+  LOperand* map = UseRegisterAtStart(instr->value());
+  return DefineAsRegister(new(zone()) LMapEnumLength(map));
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegisterAtStart(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result = DefineAsRegister(new(zone()) LFlooringDivByPowerOf2I(
+          dividend, divisor));
+  if ((instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) ||
+      (instr->CheckFlag(HValue::kLeftCanBeMinInt) && divisor == -1)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivByConstI(HMathFloorOfDiv* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LOperand* temp =
+      ((divisor > 0 && !instr->CheckFlag(HValue::kLeftCanBeNegative)) ||
+       (divisor < 0 && !instr->CheckFlag(HValue::kLeftCanBePositive))) ?
+      NULL : TempRegister();
+  LInstruction* result = DefineAsRegister(
+      new(zone()) LFlooringDivByConstI(dividend, divisor, temp));
+  if (divisor == 0 ||
+      (instr->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoFlooringDivI(HMathFloorOfDiv* instr) {
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LOperand* remainder = TempRegister();
+  LInstruction* result =
+      DefineAsRegister(new(zone()) LFlooringDivI(dividend, divisor, remainder));
+  return AssignEnvironment(result);
+}
+
+
+LInstruction* LChunkBuilder::DoMathFloorOfDiv(HMathFloorOfDiv* instr) {
+  if (instr->RightIsPowerOf2()) {
+    return DoFlooringDivByPowerOf2I(instr);
+  } else if (instr->right()->IsConstant()) {
+    return DoFlooringDivByConstI(instr);
+  } else {
+    return DoFlooringDivI(instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
+  LOperand* left = NULL;
+  LOperand* right = NULL;
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+    left = UseRegisterAtStart(instr->BetterLeftOperand());
+    right = UseRegisterOrConstantAtStart(instr->BetterRightOperand());
+  } else {
+    DCHECK(instr->representation().IsDouble());
+    DCHECK(instr->left()->representation().IsDouble());
+    DCHECK(instr->right()->representation().IsDouble());
+    left = UseRegisterAtStart(instr->left());
+    right = UseRegisterAtStart(instr->right());
+  }
+  return DefineAsRegister(new(zone()) LMathMinMax(left, right));
+}
+
+
+LInstruction* LChunkBuilder::DoModByPowerOf2I(HMod* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegisterAtStart(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LInstruction* result = DefineSameAsFirst(new(zone()) LModByPowerOf2I(
+          dividend, divisor));
+  if (instr->CheckFlag(HValue::kLeftCanBeNegative) &&
+      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoModByConstI(HMod* instr) {
+  DCHECK(instr->representation().IsInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  int32_t divisor = instr->right()->GetInteger32Constant();
+  LOperand* temp = TempRegister();
+  LInstruction* result = DefineAsRegister(new(zone()) LModByConstI(
+          dividend, divisor, temp));
+  if (divisor == 0 || instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoModI(HMod* instr) {
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+  LOperand* dividend = UseRegister(instr->left());
+  LOperand* divisor = UseRegister(instr->right());
+  LInstruction* result = DefineAsRegister(new(zone()) LModI(dividend, divisor));
+  if (instr->CheckFlag(HValue::kCanBeDivByZero) ||
+      instr->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoMod(HMod* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    if (instr->RightIsPowerOf2()) {
+      return DoModByPowerOf2I(instr);
+    } else if (instr->right()->IsConstant()) {
+      return DoModByConstI(instr);
+    } else {
+      return DoModI(instr);
+    }
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::MOD, instr);
+  } else {
+    return DoArithmeticT(Token::MOD, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoMul(HMul* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+
+    bool can_overflow = instr->CheckFlag(HValue::kCanOverflow);
+    bool bailout_on_minus_zero = instr->CheckFlag(HValue::kBailoutOnMinusZero);
+
+    HValue* least_const = instr->BetterLeftOperand();
+    HValue* most_const = instr->BetterRightOperand();
+
+    // LMulConstI can handle a subset of constants:
+    //  With support for overflow detection:
+    //    -1, 0, 1, 2
+    //    2^n, -(2^n)
+    //  Without support for overflow detection:
+    //    2^n + 1, -(2^n - 1)
+    if (most_const->IsConstant()) {
+      int32_t constant = HConstant::cast(most_const)->Integer32Value();
+      bool small_constant = (constant >= -1) && (constant <= 2);
+      bool end_range_constant = (constant <= -kMaxInt) || (constant == kMaxInt);
+      int32_t constant_abs = Abs(constant);
+
+      if (!end_range_constant &&
+          (small_constant || (base::bits::IsPowerOfTwo32(constant_abs)) ||
+           (!can_overflow && (base::bits::IsPowerOfTwo32(constant_abs + 1) ||
+                              base::bits::IsPowerOfTwo32(constant_abs - 1))))) {
+        LConstantOperand* right = UseConstant(most_const);
+        bool need_register =
+            base::bits::IsPowerOfTwo32(constant_abs) && !small_constant;
+        LOperand* left = need_register ? UseRegister(least_const)
+                                       : UseRegisterAtStart(least_const);
+        LInstruction* result =
+            DefineAsRegister(new(zone()) LMulConstIS(left, right));
+        if ((bailout_on_minus_zero && constant <= 0) || can_overflow) {
+          result = AssignEnvironment(result);
+        }
+        return result;
+      }
+    }
+
+    // LMulI/S can handle all cases, but it requires that a register is
+    // allocated for the second operand.
+    LOperand* left = UseRegisterAtStart(least_const);
+    LOperand* right = UseRegisterAtStart(most_const);
+    LInstruction* result = instr->representation().IsSmi()
+        ? DefineAsRegister(new(zone()) LMulS(left, right))
+        : DefineAsRegister(new(zone()) LMulI(left, right));
+    if ((bailout_on_minus_zero && least_const != most_const) || can_overflow) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::MUL, instr);
+  } else {
+    return DoArithmeticT(Token::MUL, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoOsrEntry(HOsrEntry* instr) {
+  DCHECK(argument_count_ == 0);
+  allocator_->MarkAsOsrEntry();
+  current_block_->last_environment()->set_ast_id(instr->ast_id());
+  return AssignEnvironment(new(zone()) LOsrEntry);
+}
+
+
+LInstruction* LChunkBuilder::DoParameter(HParameter* instr) {
+  LParameter* result = new(zone()) LParameter;
+  if (instr->kind() == HParameter::STACK_PARAMETER) {
+    int spill_index = chunk_->GetParameterStackSlot(instr->index());
+    return DefineAsSpilled(result, spill_index);
+  } else {
+    DCHECK(info()->IsStub());
+    CallInterfaceDescriptor descriptor =
+        info()->code_stub()->GetCallInterfaceDescriptor();
+    int index = static_cast<int>(instr->index());
+    Register reg = descriptor.GetEnvironmentParameterRegister(index);
+    return DefineFixed(result, reg);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoPower(HPower* instr) {
+  DCHECK(instr->representation().IsDouble());
+  // We call a C function for double power. It can't trigger a GC.
+  // We need to use fixed result register for the call.
+  Representation exponent_type = instr->right()->representation();
+  DCHECK(instr->left()->representation().IsDouble());
+  LOperand* left = UseFixedDouble(instr->left(), d0);
+  LOperand* right;
+  if (exponent_type.IsInteger32()) {
+    right = UseFixed(instr->right(), MathPowIntegerDescriptor::exponent());
+  } else if (exponent_type.IsDouble()) {
+    right = UseFixedDouble(instr->right(), d1);
+  } else {
+    right = UseFixed(instr->right(), MathPowTaggedDescriptor::exponent());
+  }
+  LPower* result = new(zone()) LPower(left, right);
+  return MarkAsCall(DefineFixedDouble(result, d0),
+                    instr,
+                    CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoPushArguments(HPushArguments* instr) {
+  int argc = instr->OperandCount();
+  AddInstruction(new(zone()) LPreparePushArguments(argc), instr);
+
+  LPushArguments* push_args = new(zone()) LPushArguments(zone());
+
+  for (int i = 0; i < argc; ++i) {
+    if (push_args->ShouldSplitPush()) {
+      AddInstruction(push_args, instr);
+      push_args = new(zone()) LPushArguments(zone());
+    }
+    push_args->AddArgument(UseRegister(instr->argument(i)));
+  }
+
+  return push_args;
+}
+
+
+LInstruction* LChunkBuilder::DoRegExpLiteral(HRegExpLiteral* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  return MarkAsCall(
+      DefineFixed(new(zone()) LRegExpLiteral(context), x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoDoubleBits(HDoubleBits* instr) {
+  HValue* value = instr->value();
+  DCHECK(value->representation().IsDouble());
+  return DefineAsRegister(new(zone()) LDoubleBits(UseRegister(value)));
+}
+
+
+LInstruction* LChunkBuilder::DoConstructDouble(HConstructDouble* instr) {
+  LOperand* lo = UseRegisterAndClobber(instr->lo());
+  LOperand* hi = UseRegister(instr->hi());
+  return DefineAsRegister(new(zone()) LConstructDouble(hi, lo));
+}
+
+
+LInstruction* LChunkBuilder::DoReturn(HReturn* instr) {
+  LOperand* context = info()->IsStub()
+      ? UseFixed(instr->context(), cp)
+      : NULL;
+  LOperand* parameter_count = UseRegisterOrConstant(instr->parameter_count());
+  return new(zone()) LReturn(UseFixed(instr->value(), x0), context,
+                             parameter_count);
+}
+
+
+LInstruction* LChunkBuilder::DoSeqStringGetChar(HSeqStringGetChar* instr) {
+  LOperand* string = UseRegisterAtStart(instr->string());
+  LOperand* index = UseRegisterOrConstantAtStart(instr->index());
+  LOperand* temp = TempRegister();
+  LSeqStringGetChar* result =
+      new(zone()) LSeqStringGetChar(string, index, temp);
+  return DefineAsRegister(result);
+}
+
+
+LInstruction* LChunkBuilder::DoSeqStringSetChar(HSeqStringSetChar* instr) {
+  LOperand* string = UseRegister(instr->string());
+  LOperand* index = FLAG_debug_code
+      ? UseRegister(instr->index())
+      : UseRegisterOrConstant(instr->index());
+  LOperand* value = UseRegister(instr->value());
+  LOperand* context = FLAG_debug_code ? UseFixed(instr->context(), cp) : NULL;
+  LOperand* temp = TempRegister();
+  LSeqStringSetChar* result =
+      new(zone()) LSeqStringSetChar(context, string, index, value, temp);
+  return DefineAsRegister(result);
+}
+
+
+HBitwiseBinaryOperation* LChunkBuilder::CanTransformToShiftedOp(HValue* val,
+                                                                HValue** left) {
+  if (!val->representation().IsInteger32()) return NULL;
+  if (!(val->IsBitwise() || val->IsAdd() || val->IsSub())) return NULL;
+
+  HBinaryOperation* hinstr = HBinaryOperation::cast(val);
+  HValue* hleft = hinstr->left();
+  HValue* hright = hinstr->right();
+  DCHECK(hleft->representation().Equals(hinstr->representation()));
+  DCHECK(hright->representation().Equals(hinstr->representation()));
+
+  if ((hright->IsConstant() &&
+       LikelyFitsImmField(hinstr, HConstant::cast(hright)->Integer32Value())) ||
+      (hinstr->IsCommutative() && hleft->IsConstant() &&
+       LikelyFitsImmField(hinstr, HConstant::cast(hleft)->Integer32Value()))) {
+    // The constant operand will likely fit in the immediate field. We are
+    // better off with
+    //     lsl x8, x9, #imm
+    //     add x0, x8, #imm2
+    // than with
+    //     mov x16, #imm2
+    //     add x0, x16, x9 LSL #imm
+    return NULL;
+  }
+
+  HBitwiseBinaryOperation* shift = NULL;
+  // TODO(aleram): We will miss situations where a shift operation is used by
+  // different instructions both as a left and right operands.
+  if (hright->IsBitwiseBinaryShift() &&
+      HBitwiseBinaryOperation::cast(hright)->right()->IsConstant()) {
+    shift = HBitwiseBinaryOperation::cast(hright);
+    if (left != NULL) {
+      *left = hleft;
+    }
+  } else if (hinstr->IsCommutative() &&
+             hleft->IsBitwiseBinaryShift() &&
+             HBitwiseBinaryOperation::cast(hleft)->right()->IsConstant()) {
+    shift = HBitwiseBinaryOperation::cast(hleft);
+    if (left != NULL) {
+      *left = hright;
+    }
+  } else {
+    return NULL;
+  }
+
+  if ((JSShiftAmountFromHConstant(shift->right()) == 0) && shift->IsShr()) {
+    // Shifts right by zero can deoptimize.
+    return NULL;
+  }
+
+  return shift;
+}
+
+
+bool LChunkBuilder::ShiftCanBeOptimizedAway(HBitwiseBinaryOperation* shift) {
+  if (!shift->representation().IsInteger32()) {
+    return false;
+  }
+  for (HUseIterator it(shift->uses()); !it.Done(); it.Advance()) {
+    if (shift != CanTransformToShiftedOp(it.value())) {
+      return false;
+    }
+  }
+  return true;
+}
+
+
+LInstruction* LChunkBuilder::TryDoOpWithShiftedRightOperand(
+    HBinaryOperation* instr) {
+  HValue* left;
+  HBitwiseBinaryOperation* shift = CanTransformToShiftedOp(instr, &left);
+
+  if ((shift != NULL) && ShiftCanBeOptimizedAway(shift)) {
+    return DoShiftedBinaryOp(instr, left, shift);
+  }
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoShiftedBinaryOp(
+    HBinaryOperation* hinstr, HValue* hleft, HBitwiseBinaryOperation* hshift) {
+  DCHECK(hshift->IsBitwiseBinaryShift());
+  DCHECK(!hshift->IsShr() || (JSShiftAmountFromHConstant(hshift->right()) > 0));
+
+  LTemplateResultInstruction<1>* res;
+  LOperand* left = UseRegisterAtStart(hleft);
+  LOperand* right = UseRegisterAtStart(hshift->left());
+  LOperand* shift_amount = UseConstant(hshift->right());
+  Shift shift_op;
+  switch (hshift->opcode()) {
+    case HValue::kShl: shift_op = LSL; break;
+    case HValue::kShr: shift_op = LSR; break;
+    case HValue::kSar: shift_op = ASR; break;
+    default: UNREACHABLE(); shift_op = NO_SHIFT;
+  }
+
+  if (hinstr->IsBitwise()) {
+    res = new(zone()) LBitI(left, right, shift_op, shift_amount);
+  } else if (hinstr->IsAdd()) {
+    res = new(zone()) LAddI(left, right, shift_op, shift_amount);
+  } else {
+    DCHECK(hinstr->IsSub());
+    res = new(zone()) LSubI(left, right, shift_op, shift_amount);
+  }
+  if (hinstr->CheckFlag(HValue::kCanOverflow)) {
+    AssignEnvironment(res);
+  }
+  return DefineAsRegister(res);
+}
+
+
+LInstruction* LChunkBuilder::DoShift(Token::Value op,
+                                     HBitwiseBinaryOperation* instr) {
+  if (instr->representation().IsTagged()) {
+    return DoArithmeticT(op, instr);
+  }
+
+  DCHECK(instr->representation().IsSmiOrInteger32());
+  DCHECK(instr->left()->representation().Equals(instr->representation()));
+  DCHECK(instr->right()->representation().Equals(instr->representation()));
+
+  if (ShiftCanBeOptimizedAway(instr)) {
+    return NULL;
+  }
+
+  LOperand* left = instr->representation().IsSmi()
+      ? UseRegister(instr->left())
+      : UseRegisterAtStart(instr->left());
+  LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+
+  // The only shift that can deoptimize is `left >>> 0`, where left is negative.
+  // In these cases, the result is a uint32 that is too large for an int32.
+  bool right_can_be_zero = !instr->right()->IsConstant() ||
+                           (JSShiftAmountFromHConstant(instr->right()) == 0);
+  bool can_deopt = false;
+  if ((op == Token::SHR) && right_can_be_zero) {
+    if (FLAG_opt_safe_uint32_operations) {
+      can_deopt = !instr->CheckFlag(HInstruction::kUint32);
+    } else {
+      can_deopt = !instr->CheckUsesForFlag(HValue::kTruncatingToInt32);
+    }
+  }
+
+  LInstruction* result;
+  if (instr->representation().IsInteger32()) {
+    result = DefineAsRegister(new (zone()) LShiftI(op, left, right, can_deopt));
+  } else {
+    DCHECK(instr->representation().IsSmi());
+    result = DefineAsRegister(new (zone()) LShiftS(op, left, right, can_deopt));
+  }
+
+  return can_deopt ? AssignEnvironment(result) : result;
+}
+
+
+LInstruction* LChunkBuilder::DoRor(HRor* instr) {
+  return DoShift(Token::ROR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoSar(HSar* instr) {
+  return DoShift(Token::SAR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoShl(HShl* instr) {
+  return DoShift(Token::SHL, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoShr(HShr* instr) {
+  return DoShift(Token::SHR, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoSimulate(HSimulate* instr) {
+  instr->ReplayEnvironment(current_block_->last_environment());
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoStackCheck(HStackCheck* instr) {
+  if (instr->is_function_entry()) {
+    LOperand* context = UseFixed(instr->context(), cp);
+    return MarkAsCall(new(zone()) LStackCheck(context), instr);
+  } else {
+    DCHECK(instr->is_backwards_branch());
+    LOperand* context = UseAny(instr->context());
+    return AssignEnvironment(
+        AssignPointerMap(new(zone()) LStackCheck(context)));
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoStoreCodeEntry(HStoreCodeEntry* instr) {
+  LOperand* function = UseRegister(instr->function());
+  LOperand* code_object = UseRegisterAtStart(instr->code_object());
+  LOperand* temp = TempRegister();
+  return new(zone()) LStoreCodeEntry(function, code_object, temp);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreContextSlot(HStoreContextSlot* instr) {
+  LOperand* temp = TempRegister();
+  LOperand* context;
+  LOperand* value;
+  if (instr->NeedsWriteBarrier()) {
+    // TODO(all): Replace these constraints when RecordWriteStub has been
+    // rewritten.
+    context = UseRegisterAndClobber(instr->context());
+    value = UseRegisterAndClobber(instr->value());
+  } else {
+    context = UseRegister(instr->context());
+    value = UseRegister(instr->value());
+  }
+  LInstruction* result = new(zone()) LStoreContextSlot(context, value, temp);
+  if (instr->RequiresHoleCheck() && instr->DeoptimizesOnHole()) {
+    result = AssignEnvironment(result);
+  }
+  return result;
+}
+
+
+LInstruction* LChunkBuilder::DoStoreGlobalCell(HStoreGlobalCell* instr) {
+  LOperand* value = UseRegister(instr->value());
+  if (instr->RequiresHoleCheck()) {
+    return AssignEnvironment(new(zone()) LStoreGlobalCell(value,
+                                                          TempRegister(),
+                                                          TempRegister()));
+  } else {
+    return new(zone()) LStoreGlobalCell(value, TempRegister(), NULL);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) {
+  LOperand* key = UseRegisterOrConstant(instr->key());
+  LOperand* temp = NULL;
+  LOperand* elements = NULL;
+  LOperand* val = NULL;
+
+  if (!instr->is_typed_elements() &&
+      instr->value()->representation().IsTagged() &&
+      instr->NeedsWriteBarrier()) {
+    // RecordWrite() will clobber all registers.
+    elements = UseRegisterAndClobber(instr->elements());
+    val = UseRegisterAndClobber(instr->value());
+    temp = TempRegister();
+  } else {
+    elements = UseRegister(instr->elements());
+    val = UseRegister(instr->value());
+    temp = instr->key()->IsConstant() ? NULL : TempRegister();
+  }
+
+  if (instr->is_typed_elements()) {
+    DCHECK((instr->value()->representation().IsInteger32() &&
+            !IsDoubleOrFloatElementsKind(instr->elements_kind())) ||
+           (instr->value()->representation().IsDouble() &&
+            IsDoubleOrFloatElementsKind(instr->elements_kind())));
+    DCHECK((instr->is_fixed_typed_array() &&
+            instr->elements()->representation().IsTagged()) ||
+           (instr->is_external() &&
+            instr->elements()->representation().IsExternal()));
+    return new(zone()) LStoreKeyedExternal(elements, key, val, temp);
+
+  } else if (instr->value()->representation().IsDouble()) {
+    DCHECK(instr->elements()->representation().IsTagged());
+    return new(zone()) LStoreKeyedFixedDouble(elements, key, val, temp);
+
+  } else {
+    DCHECK(instr->elements()->representation().IsTagged());
+    DCHECK(instr->value()->representation().IsSmiOrTagged() ||
+           instr->value()->representation().IsInteger32());
+    return new(zone()) LStoreKeyedFixed(elements, key, val, temp);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoStoreKeyedGeneric(HStoreKeyedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
+  LOperand* key = UseFixed(instr->key(), StoreDescriptor::NameRegister());
+  LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
+
+  DCHECK(instr->object()->representation().IsTagged());
+  DCHECK(instr->key()->representation().IsTagged());
+  DCHECK(instr->value()->representation().IsTagged());
+
+  return MarkAsCall(
+      new(zone()) LStoreKeyedGeneric(context, object, key, value), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
+  // TODO(jbramley): It might be beneficial to allow value to be a constant in
+  // some cases. x64 makes use of this with FLAG_track_fields, for example.
+
+  LOperand* object = UseRegister(instr->object());
+  LOperand* value;
+  LOperand* temp0 = NULL;
+  LOperand* temp1 = NULL;
+
+  if (instr->access().IsExternalMemory() ||
+      instr->field_representation().IsDouble()) {
+    value = UseRegister(instr->value());
+  } else if (instr->NeedsWriteBarrier()) {
+    value = UseRegisterAndClobber(instr->value());
+    temp0 = TempRegister();
+    temp1 = TempRegister();
+  } else if (instr->NeedsWriteBarrierForMap()) {
+    value = UseRegister(instr->value());
+    temp0 = TempRegister();
+    temp1 = TempRegister();
+  } else {
+    value = UseRegister(instr->value());
+    temp0 = TempRegister();
+  }
+
+  return new(zone()) LStoreNamedField(object, value, temp0, temp1);
+}
+
+
+LInstruction* LChunkBuilder::DoStoreNamedGeneric(HStoreNamedGeneric* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* object =
+      UseFixed(instr->object(), StoreDescriptor::ReceiverRegister());
+  LOperand* value = UseFixed(instr->value(), StoreDescriptor::ValueRegister());
+
+  LInstruction* result = new(zone()) LStoreNamedGeneric(context, object, value);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStringAdd(HStringAdd* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), x1);
+  LOperand* right = UseFixed(instr->right(), x0);
+
+  LStringAdd* result = new(zone()) LStringAdd(context, left, right);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoStringCharCodeAt(HStringCharCodeAt* instr) {
+  LOperand* string = UseRegisterAndClobber(instr->string());
+  LOperand* index = UseRegisterAndClobber(instr->index());
+  LOperand* context = UseAny(instr->context());
+  LStringCharCodeAt* result =
+      new(zone()) LStringCharCodeAt(context, string, index);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoStringCharFromCode(HStringCharFromCode* instr) {
+  LOperand* char_code = UseRegister(instr->value());
+  LOperand* context = UseAny(instr->context());
+  LStringCharFromCode* result =
+      new(zone()) LStringCharFromCode(context, char_code);
+  return AssignPointerMap(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoStringCompareAndBranch(
+    HStringCompareAndBranch* instr) {
+  DCHECK(instr->left()->representation().IsTagged());
+  DCHECK(instr->right()->representation().IsTagged());
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* left = UseFixed(instr->left(), x1);
+  LOperand* right = UseFixed(instr->right(), x0);
+  LStringCompareAndBranch* result =
+      new(zone()) LStringCompareAndBranch(context, left, right);
+  return MarkAsCall(result, instr);
+}
+
+
+LInstruction* LChunkBuilder::DoSub(HSub* instr) {
+  if (instr->representation().IsSmiOrInteger32()) {
+    DCHECK(instr->left()->representation().Equals(instr->representation()));
+    DCHECK(instr->right()->representation().Equals(instr->representation()));
+
+    LInstruction* shifted_operation = TryDoOpWithShiftedRightOperand(instr);
+    if (shifted_operation != NULL) {
+      return shifted_operation;
+    }
+
+    LOperand *left;
+    if (instr->left()->IsConstant() &&
+        (HConstant::cast(instr->left())->Integer32Value() == 0)) {
+      left = UseConstant(instr->left());
+    } else {
+      left = UseRegisterAtStart(instr->left());
+    }
+    LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+    LInstruction* result = instr->representation().IsSmi() ?
+        DefineAsRegister(new(zone()) LSubS(left, right)) :
+        DefineAsRegister(new(zone()) LSubI(left, right));
+    if (instr->CheckFlag(HValue::kCanOverflow)) {
+      result = AssignEnvironment(result);
+    }
+    return result;
+  } else if (instr->representation().IsDouble()) {
+    return DoArithmeticD(Token::SUB, instr);
+  } else {
+    return DoArithmeticT(Token::SUB, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoThisFunction(HThisFunction* instr) {
+  if (instr->HasNoUses()) {
+    return NULL;
+  } else {
+    return DefineAsRegister(new(zone()) LThisFunction);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoToFastProperties(HToFastProperties* instr) {
+  LOperand* object = UseFixed(instr->value(), x0);
+  LToFastProperties* result = new(zone()) LToFastProperties(object);
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTransitionElementsKind(
+    HTransitionElementsKind* instr) {
+  if (IsSimpleMapChangeTransition(instr->from_kind(), instr->to_kind())) {
+    LOperand* object = UseRegister(instr->object());
+    LTransitionElementsKind* result =
+        new(zone()) LTransitionElementsKind(object, NULL,
+                                            TempRegister(), TempRegister());
+    return result;
+  } else {
+    LOperand* object = UseFixed(instr->object(), x0);
+    LOperand* context = UseFixed(instr->context(), cp);
+    LTransitionElementsKind* result =
+        new(zone()) LTransitionElementsKind(object, context, NULL, NULL);
+    return MarkAsCall(result, instr);
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoTrapAllocationMemento(
+    HTrapAllocationMemento* instr) {
+  LOperand* object = UseRegister(instr->object());
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+  LTrapAllocationMemento* result =
+      new(zone()) LTrapAllocationMemento(object, temp1, temp2);
+  return AssignEnvironment(result);
+}
+
+
+LInstruction* LChunkBuilder::DoTypeof(HTypeof* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  // TODO(jbramley): In ARM, this uses UseFixed to force the input to x0.
+  // However, LCodeGen::DoTypeof just pushes it to the stack (for CallRuntime)
+  // anyway, so the input doesn't have to be in x0. We might be able to improve
+  // the ARM back-end a little by relaxing this restriction.
+  LTypeof* result =
+      new(zone()) LTypeof(context, UseRegisterAtStart(instr->value()));
+  return MarkAsCall(DefineFixed(result, x0), instr);
+}
+
+
+LInstruction* LChunkBuilder::DoTypeofIsAndBranch(HTypeofIsAndBranch* instr) {
+  // We only need temp registers in some cases, but we can't dereference the
+  // instr->type_literal() handle to test that here.
+  LOperand* temp1 = TempRegister();
+  LOperand* temp2 = TempRegister();
+
+  return new(zone()) LTypeofIsAndBranch(
+      UseRegister(instr->value()), temp1, temp2);
+}
+
+
+LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
+  switch (instr->op()) {
+    case kMathAbs: {
+      Representation r = instr->representation();
+      if (r.IsTagged()) {
+        // The tagged case might need to allocate a HeapNumber for the result,
+        // so it is handled by a separate LInstruction.
+        LOperand* context = UseFixed(instr->context(), cp);
+        LOperand* input = UseRegister(instr->value());
+        LOperand* temp1 = TempRegister();
+        LOperand* temp2 = TempRegister();
+        LOperand* temp3 = TempRegister();
+        LInstruction* result = DefineAsRegister(
+            new(zone()) LMathAbsTagged(context, input, temp1, temp2, temp3));
+        return AssignEnvironment(AssignPointerMap(result));
+      } else {
+        LOperand* input = UseRegisterAtStart(instr->value());
+        LInstruction* result = DefineAsRegister(new(zone()) LMathAbs(input));
+        if (!r.IsDouble()) result = AssignEnvironment(result);
+        return result;
+      }
+    }
+    case kMathExp: {
+      DCHECK(instr->representation().IsDouble());
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegister(instr->value());
+      LOperand* double_temp1 = TempDoubleRegister();
+      LOperand* temp1 = TempRegister();
+      LOperand* temp2 = TempRegister();
+      LOperand* temp3 = TempRegister();
+      LMathExp* result = new(zone()) LMathExp(input, double_temp1,
+                                              temp1, temp2, temp3);
+      return DefineAsRegister(result);
+    }
+    case kMathFloor: {
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegisterAtStart(instr->value());
+      if (instr->representation().IsInteger32()) {
+        LMathFloorI* result = new(zone()) LMathFloorI(input);
+        return AssignEnvironment(AssignPointerMap(DefineAsRegister(result)));
+      } else {
+        DCHECK(instr->representation().IsDouble());
+        LMathFloorD* result = new(zone()) LMathFloorD(input);
+        return DefineAsRegister(result);
+      }
+    }
+    case kMathLog: {
+      DCHECK(instr->representation().IsDouble());
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseFixedDouble(instr->value(), d0);
+      LMathLog* result = new(zone()) LMathLog(input);
+      return MarkAsCall(DefineFixedDouble(result, d0), instr);
+    }
+    case kMathPowHalf: {
+      DCHECK(instr->representation().IsDouble());
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegister(instr->value());
+      return DefineAsRegister(new(zone()) LMathPowHalf(input));
+    }
+    case kMathRound: {
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegister(instr->value());
+      if (instr->representation().IsInteger32()) {
+        LOperand* temp = TempDoubleRegister();
+        LMathRoundI* result = new(zone()) LMathRoundI(input, temp);
+        return AssignEnvironment(DefineAsRegister(result));
+      } else {
+        DCHECK(instr->representation().IsDouble());
+        LMathRoundD* result = new(zone()) LMathRoundD(input);
+        return DefineAsRegister(result);
+      }
+    }
+    case kMathFround: {
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegister(instr->value());
+      LMathFround* result = new (zone()) LMathFround(input);
+      return DefineAsRegister(result);
+    }
+    case kMathSqrt: {
+      DCHECK(instr->representation().IsDouble());
+      DCHECK(instr->value()->representation().IsDouble());
+      LOperand* input = UseRegisterAtStart(instr->value());
+      return DefineAsRegister(new(zone()) LMathSqrt(input));
+    }
+    case kMathClz32: {
+      DCHECK(instr->representation().IsInteger32());
+      DCHECK(instr->value()->representation().IsInteger32());
+      LOperand* input = UseRegisterAtStart(instr->value());
+      return DefineAsRegister(new(zone()) LMathClz32(input));
+    }
+    default:
+      UNREACHABLE();
+      return NULL;
+  }
+}
+
+
+LInstruction* LChunkBuilder::DoUnknownOSRValue(HUnknownOSRValue* instr) {
+  // Use an index that corresponds to the location in the unoptimized frame,
+  // which the optimized frame will subsume.
+  int env_index = instr->index();
+  int spill_index = 0;
+  if (instr->environment()->is_parameter_index(env_index)) {
+    spill_index = chunk_->GetParameterStackSlot(env_index);
+  } else {
+    spill_index = env_index - instr->environment()->first_local_index();
+    if (spill_index > LUnallocated::kMaxFixedSlotIndex) {
+      Retry(kTooManySpillSlotsNeededForOSR);
+      spill_index = 0;
+    }
+  }
+  return DefineAsSpilled(new(zone()) LUnknownOSRValue, spill_index);
+}
+
+
+LInstruction* LChunkBuilder::DoUseConst(HUseConst* instr) {
+  return NULL;
+}
+
+
+LInstruction* LChunkBuilder::DoForInPrepareMap(HForInPrepareMap* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  // Assign object to a fixed register different from those already used in
+  // LForInPrepareMap.
+  LOperand* object = UseFixed(instr->enumerable(), x0);
+  LForInPrepareMap* result = new(zone()) LForInPrepareMap(context, object);
+  return MarkAsCall(DefineFixed(result, x0), instr, CAN_DEOPTIMIZE_EAGERLY);
+}
+
+
+LInstruction* LChunkBuilder::DoForInCacheArray(HForInCacheArray* instr) {
+  LOperand* map = UseRegister(instr->map());
+  return AssignEnvironment(DefineAsRegister(new(zone()) LForInCacheArray(map)));
+}
+
+
+LInstruction* LChunkBuilder::DoCheckMapValue(HCheckMapValue* instr) {
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* map = UseRegister(instr->map());
+  LOperand* temp = TempRegister();
+  return AssignEnvironment(new(zone()) LCheckMapValue(value, map, temp));
+}
+
+
+LInstruction* LChunkBuilder::DoLoadFieldByIndex(HLoadFieldByIndex* instr) {
+  LOperand* object = UseRegisterAtStart(instr->object());
+  LOperand* index = UseRegisterAndClobber(instr->index());
+  LLoadFieldByIndex* load = new(zone()) LLoadFieldByIndex(object, index);
+  LInstruction* result = DefineSameAsFirst(load);
+  return AssignPointerMap(result);
+}
+
+
+LInstruction* LChunkBuilder::DoWrapReceiver(HWrapReceiver* instr) {
+  LOperand* receiver = UseRegister(instr->receiver());
+  LOperand* function = UseRegister(instr->function());
+  LWrapReceiver* result = new(zone()) LWrapReceiver(receiver, function);
+  return AssignEnvironment(DefineAsRegister(result));
+}
+
+
+LInstruction* LChunkBuilder::DoStoreFrameContext(HStoreFrameContext* instr) {
+  LOperand* context = UseRegisterAtStart(instr->context());
+  return new(zone()) LStoreFrameContext(context);
+}
+
+
+LInstruction* LChunkBuilder::DoAllocateBlockContext(
+    HAllocateBlockContext* instr) {
+  LOperand* context = UseFixed(instr->context(), cp);
+  LOperand* function = UseRegisterAtStart(instr->function());
+  LAllocateBlockContext* result =
+      new(zone()) LAllocateBlockContext(context, function);
+  return MarkAsCall(DefineFixed(result, cp), instr);
+}
+
+
+} }  // namespace v8::internal
diff --git a/src/arm64/lithium-arm64.h b/src/arm64/lithium-arm64.h
new file mode 100644
index 0000000..6ead3fe
--- /dev/null
+++ b/src/arm64/lithium-arm64.h
@@ -0,0 +1,3259 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_LITHIUM_ARM64_H_
+#define V8_ARM64_LITHIUM_ARM64_H_
+
+#include "src/hydrogen.h"
+#include "src/lithium.h"
+#include "src/lithium-allocator.h"
+#include "src/safepoint-table.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LCodeGen;
+
+#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
+  V(AccessArgumentsAt)                       \
+  V(AddE)                                    \
+  V(AddI)                                    \
+  V(AddS)                                    \
+  V(Allocate)                                \
+  V(AllocateBlockContext)                    \
+  V(ApplyArguments)                          \
+  V(ArgumentsElements)                       \
+  V(ArgumentsLength)                         \
+  V(ArithmeticD)                             \
+  V(ArithmeticT)                             \
+  V(BitI)                                    \
+  V(BitS)                                    \
+  V(BoundsCheck)                             \
+  V(Branch)                                  \
+  V(CallFunction)                            \
+  V(CallJSFunction)                          \
+  V(CallNew)                                 \
+  V(CallNewArray)                            \
+  V(CallRuntime)                             \
+  V(CallStub)                                \
+  V(CallWithDescriptor)                      \
+  V(CheckInstanceType)                       \
+  V(CheckMapValue)                           \
+  V(CheckMaps)                               \
+  V(CheckNonSmi)                             \
+  V(CheckSmi)                                \
+  V(CheckValue)                              \
+  V(ClampDToUint8)                           \
+  V(ClampIToUint8)                           \
+  V(ClampTToUint8)                           \
+  V(ClassOfTestAndBranch)                    \
+  V(CmpHoleAndBranchD)                       \
+  V(CmpHoleAndBranchT)                       \
+  V(CmpMapAndBranch)                         \
+  V(CmpObjectEqAndBranch)                    \
+  V(CmpT)                                    \
+  V(CompareMinusZeroAndBranch)               \
+  V(CompareNumericAndBranch)                 \
+  V(ConstantD)                               \
+  V(ConstantE)                               \
+  V(ConstantI)                               \
+  V(ConstantS)                               \
+  V(ConstantT)                               \
+  V(ConstructDouble)                         \
+  V(Context)                                 \
+  V(DateField)                               \
+  V(DebugBreak)                              \
+  V(DeclareGlobals)                          \
+  V(Deoptimize)                              \
+  V(DivByConstI)                             \
+  V(DivByPowerOf2I)                          \
+  V(DivI)                                    \
+  V(DoubleBits)                              \
+  V(DoubleToIntOrSmi)                        \
+  V(Drop)                                    \
+  V(Dummy)                                   \
+  V(DummyUse)                                \
+  V(FlooringDivByConstI)                     \
+  V(FlooringDivByPowerOf2I)                  \
+  V(FlooringDivI)                            \
+  V(ForInCacheArray)                         \
+  V(ForInPrepareMap)                         \
+  V(FunctionLiteral)                         \
+  V(GetCachedArrayIndex)                     \
+  V(Goto)                                    \
+  V(HasCachedArrayIndexAndBranch)            \
+  V(HasInstanceTypeAndBranch)                \
+  V(InnerAllocatedObject)                    \
+  V(InstanceOf)                              \
+  V(InstanceOfKnownGlobal)                   \
+  V(InstructionGap)                          \
+  V(Integer32ToDouble)                       \
+  V(InvokeFunction)                          \
+  V(IsConstructCallAndBranch)                \
+  V(IsObjectAndBranch)                       \
+  V(IsSmiAndBranch)                          \
+  V(IsStringAndBranch)                       \
+  V(IsUndetectableAndBranch)                 \
+  V(Label)                                   \
+  V(LazyBailout)                             \
+  V(LoadContextSlot)                         \
+  V(LoadFieldByIndex)                        \
+  V(LoadFunctionPrototype)                   \
+  V(LoadGlobalCell)                          \
+  V(LoadGlobalGeneric)                       \
+  V(LoadKeyedExternal)                       \
+  V(LoadKeyedFixed)                          \
+  V(LoadKeyedFixedDouble)                    \
+  V(LoadKeyedGeneric)                        \
+  V(LoadNamedField)                          \
+  V(LoadNamedGeneric)                        \
+  V(LoadRoot)                                \
+  V(MapEnumLength)                           \
+  V(MathAbs)                                 \
+  V(MathAbsTagged)                           \
+  V(MathClz32)                               \
+  V(MathExp)                                 \
+  V(MathFloorD)                              \
+  V(MathFloorI)                              \
+  V(MathFround)                              \
+  V(MathLog)                                 \
+  V(MathMinMax)                              \
+  V(MathPowHalf)                             \
+  V(MathRoundD)                              \
+  V(MathRoundI)                              \
+  V(MathSqrt)                                \
+  V(ModByConstI)                             \
+  V(ModByPowerOf2I)                          \
+  V(ModI)                                    \
+  V(MulConstIS)                              \
+  V(MulI)                                    \
+  V(MulS)                                    \
+  V(NumberTagD)                              \
+  V(NumberTagU)                              \
+  V(NumberUntagD)                            \
+  V(OsrEntry)                                \
+  V(Parameter)                               \
+  V(Power)                                   \
+  V(PreparePushArguments)                    \
+  V(PushArguments)                           \
+  V(RegExpLiteral)                           \
+  V(Return)                                  \
+  V(SeqStringGetChar)                        \
+  V(SeqStringSetChar)                        \
+  V(ShiftI)                                  \
+  V(ShiftS)                                  \
+  V(SmiTag)                                  \
+  V(SmiUntag)                                \
+  V(StackCheck)                              \
+  V(StoreCodeEntry)                          \
+  V(StoreContextSlot)                        \
+  V(StoreFrameContext)                       \
+  V(StoreGlobalCell)                         \
+  V(StoreKeyedExternal)                      \
+  V(StoreKeyedFixed)                         \
+  V(StoreKeyedFixedDouble)                   \
+  V(StoreKeyedGeneric)                       \
+  V(StoreNamedField)                         \
+  V(StoreNamedGeneric)                       \
+  V(StringAdd)                               \
+  V(StringCharCodeAt)                        \
+  V(StringCharFromCode)                      \
+  V(StringCompareAndBranch)                  \
+  V(SubI)                                    \
+  V(SubS)                                    \
+  V(TaggedToI)                               \
+  V(TailCallThroughMegamorphicCache)         \
+  V(ThisFunction)                            \
+  V(ToFastProperties)                        \
+  V(TransitionElementsKind)                  \
+  V(TrapAllocationMemento)                   \
+  V(TruncateDoubleToIntOrSmi)                \
+  V(Typeof)                                  \
+  V(TypeofIsAndBranch)                       \
+  V(Uint32ToDouble)                          \
+  V(UnknownOSRValue)                         \
+  V(WrapReceiver)
+
+
+#define DECLARE_CONCRETE_INSTRUCTION(type, mnemonic)                        \
+  virtual Opcode opcode() const FINAL OVERRIDE {                      \
+    return LInstruction::k##type;                                           \
+  }                                                                         \
+  virtual void CompileToNative(LCodeGen* generator) FINAL OVERRIDE;   \
+  virtual const char* Mnemonic() const FINAL OVERRIDE {               \
+    return mnemonic;                                                        \
+  }                                                                         \
+  static L##type* cast(LInstruction* instr) {                               \
+    DCHECK(instr->Is##type());                                              \
+    return reinterpret_cast<L##type*>(instr);                               \
+  }
+
+
+#define DECLARE_HYDROGEN_ACCESSOR(type)           \
+  H##type* hydrogen() const {                     \
+    return H##type::cast(this->hydrogen_value()); \
+  }
+
+
+class LInstruction : public ZoneObject {
+ public:
+  LInstruction()
+      : environment_(NULL),
+        hydrogen_value_(NULL),
+        bit_field_(IsCallBits::encode(false)) { }
+
+  virtual ~LInstruction() { }
+
+  virtual void CompileToNative(LCodeGen* generator) = 0;
+  virtual const char* Mnemonic() const = 0;
+  virtual void PrintTo(StringStream* stream);
+  virtual void PrintDataTo(StringStream* stream);
+  virtual void PrintOutputOperandTo(StringStream* stream);
+
+  enum Opcode {
+    // Declare a unique enum value for each instruction.
+#define DECLARE_OPCODE(type) k##type,
+    LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_OPCODE)
+    kNumberOfInstructions
+#undef DECLARE_OPCODE
+  };
+
+  virtual Opcode opcode() const = 0;
+
+  // Declare non-virtual type testers for all leaf IR classes.
+#define DECLARE_PREDICATE(type) \
+  bool Is##type() const { return opcode() == k##type; }
+  LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_PREDICATE)
+#undef DECLARE_PREDICATE
+
+  // Declare virtual predicates for instructions that don't have
+  // an opcode.
+  virtual bool IsGap() const { return false; }
+
+  virtual bool IsControl() const { return false; }
+
+  // Try deleting this instruction if possible.
+  virtual bool TryDelete() { return false; }
+
+  void set_environment(LEnvironment* env) { environment_ = env; }
+  LEnvironment* environment() const { return environment_; }
+  bool HasEnvironment() const { return environment_ != NULL; }
+
+  void set_pointer_map(LPointerMap* p) { pointer_map_.set(p); }
+  LPointerMap* pointer_map() const { return pointer_map_.get(); }
+  bool HasPointerMap() const { return pointer_map_.is_set(); }
+
+  void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
+  HValue* hydrogen_value() const { return hydrogen_value_; }
+
+  virtual void SetDeferredLazyDeoptimizationEnvironment(LEnvironment* env) { }
+
+  void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
+  bool IsCall() const { return IsCallBits::decode(bit_field_); }
+
+  // Interface to the register allocator and iterators.
+  bool ClobbersTemps() const { return IsCall(); }
+  bool ClobbersRegisters() const { return IsCall(); }
+  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const {
+    return IsCall();
+  }
+  bool IsMarkedAsCall() const { return IsCall(); }
+
+  virtual bool HasResult() const = 0;
+  virtual LOperand* result() const = 0;
+
+  virtual int InputCount() = 0;
+  virtual LOperand* InputAt(int i) = 0;
+  virtual int TempCount() = 0;
+  virtual LOperand* TempAt(int i) = 0;
+
+  LOperand* FirstInput() { return InputAt(0); }
+  LOperand* Output() { return HasResult() ? result() : NULL; }
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const { return true; }
+
+#ifdef DEBUG
+  void VerifyCall();
+#endif
+
+ private:
+  class IsCallBits: public BitField<bool, 0, 1> {};
+
+  LEnvironment* environment_;
+  SetOncePointer<LPointerMap> pointer_map_;
+  HValue* hydrogen_value_;
+  int32_t bit_field_;
+};
+
+
+// R = number of result operands (0 or 1).
+template<int R>
+class LTemplateResultInstruction : public LInstruction {
+ public:
+  // Allow 0 or 1 output operands.
+  STATIC_ASSERT(R == 0 || R == 1);
+  virtual bool HasResult() const FINAL OVERRIDE {
+    return (R != 0) && (result() != NULL);
+  }
+  void set_result(LOperand* operand) { results_[0] = operand; }
+  LOperand* result() const { return results_[0]; }
+
+ protected:
+  EmbeddedContainer<LOperand*, R> results_;
+};
+
+
+// R = number of result operands (0 or 1).
+// I = number of input operands.
+// T = number of temporary operands.
+template<int R, int I, int T>
+class LTemplateInstruction : public LTemplateResultInstruction<R> {
+ protected:
+  EmbeddedContainer<LOperand*, I> inputs_;
+  EmbeddedContainer<LOperand*, T> temps_;
+
+ private:
+  // Iterator support.
+  virtual int InputCount() FINAL OVERRIDE { return I; }
+  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+
+  virtual int TempCount() FINAL OVERRIDE { return T; }
+  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return temps_[i]; }
+};
+
+
+class LTailCallThroughMegamorphicCache FINAL
+    : public LTemplateInstruction<0, 3, 0> {
+ public:
+  explicit LTailCallThroughMegamorphicCache(LOperand* context,
+                                            LOperand* receiver,
+                                            LOperand* name) {
+    inputs_[0] = context;
+    inputs_[1] = receiver;
+    inputs_[2] = name;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* name() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TailCallThroughMegamorphicCache,
+                               "tail-call-through-megamorphic-cache")
+  DECLARE_HYDROGEN_ACCESSOR(TailCallThroughMegamorphicCache)
+};
+
+
+class LUnknownOSRValue FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+    return false;
+  }
+  DECLARE_CONCRETE_INSTRUCTION(UnknownOSRValue, "unknown-osr-value")
+};
+
+
+template<int I, int T>
+class LControlInstruction : public LTemplateInstruction<0, I, T> {
+ public:
+  LControlInstruction() : false_label_(NULL), true_label_(NULL) { }
+
+  virtual bool IsControl() const FINAL OVERRIDE { return true; }
+
+  int SuccessorCount() { return hydrogen()->SuccessorCount(); }
+  HBasicBlock* SuccessorAt(int i) { return hydrogen()->SuccessorAt(i); }
+
+  int TrueDestination(LChunk* chunk) {
+    return chunk->LookupDestination(true_block_id());
+  }
+
+  int FalseDestination(LChunk* chunk) {
+    return chunk->LookupDestination(false_block_id());
+  }
+
+  Label* TrueLabel(LChunk* chunk) {
+    if (true_label_ == NULL) {
+      true_label_ = chunk->GetAssemblyLabel(TrueDestination(chunk));
+    }
+    return true_label_;
+  }
+
+  Label* FalseLabel(LChunk* chunk) {
+    if (false_label_ == NULL) {
+      false_label_ = chunk->GetAssemblyLabel(FalseDestination(chunk));
+    }
+    return false_label_;
+  }
+
+ protected:
+  int true_block_id() { return SuccessorAt(0)->block_id(); }
+  int false_block_id() { return SuccessorAt(1)->block_id(); }
+
+ private:
+  DECLARE_HYDROGEN_ACCESSOR(ControlInstruction);
+
+  Label* false_label_;
+  Label* true_label_;
+};
+
+
+class LGap : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LGap(HBasicBlock* block)
+      : block_(block) {
+    parallel_moves_[BEFORE] = NULL;
+    parallel_moves_[START] = NULL;
+    parallel_moves_[END] = NULL;
+    parallel_moves_[AFTER] = NULL;
+  }
+
+  // Can't use the DECLARE-macro here because of sub-classes.
+  virtual bool IsGap() const OVERRIDE { return true; }
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  static LGap* cast(LInstruction* instr) {
+    DCHECK(instr->IsGap());
+    return reinterpret_cast<LGap*>(instr);
+  }
+
+  bool IsRedundant() const;
+
+  HBasicBlock* block() const { return block_; }
+
+  enum InnerPosition {
+    BEFORE,
+    START,
+    END,
+    AFTER,
+    FIRST_INNER_POSITION = BEFORE,
+    LAST_INNER_POSITION = AFTER
+  };
+
+  LParallelMove* GetOrCreateParallelMove(InnerPosition pos, Zone* zone)  {
+    if (parallel_moves_[pos] == NULL) {
+      parallel_moves_[pos] = new(zone) LParallelMove(zone);
+    }
+    return parallel_moves_[pos];
+  }
+
+  LParallelMove* GetParallelMove(InnerPosition pos)  {
+    return parallel_moves_[pos];
+  }
+
+ private:
+  LParallelMove* parallel_moves_[LAST_INNER_POSITION + 1];
+  HBasicBlock* block_;
+};
+
+
+class LInstructionGap FINAL : public LGap {
+ public:
+  explicit LInstructionGap(HBasicBlock* block) : LGap(block) { }
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+    return !IsRedundant();
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstructionGap, "gap")
+};
+
+
+class LDrop FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LDrop(int count) : count_(count) { }
+
+  int count() const { return count_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Drop, "drop")
+
+ private:
+  int count_;
+};
+
+
+class LDummy FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  LDummy() {}
+  DECLARE_CONCRETE_INSTRUCTION(Dummy, "dummy")
+};
+
+
+class LDummyUse FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDummyUse(LOperand* value) {
+    inputs_[0] = value;
+  }
+  DECLARE_CONCRETE_INSTRUCTION(DummyUse, "dummy-use")
+};
+
+
+class LGoto FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LGoto(HBasicBlock* block) : block_(block) { }
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE;
+  DECLARE_CONCRETE_INSTRUCTION(Goto, "goto")
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+  virtual bool IsControl() const OVERRIDE { return true; }
+
+  int block_id() const { return block_->block_id(); }
+
+ private:
+  HBasicBlock* block_;
+};
+
+
+class LLazyBailout FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  LLazyBailout() : gap_instructions_size_(0) { }
+
+  DECLARE_CONCRETE_INSTRUCTION(LazyBailout, "lazy-bailout")
+
+  void set_gap_instructions_size(int gap_instructions_size) {
+    gap_instructions_size_ = gap_instructions_size;
+  }
+  int gap_instructions_size() { return gap_instructions_size_; }
+
+ private:
+  int gap_instructions_size_;
+};
+
+
+class LLabel FINAL : public LGap {
+ public:
+  explicit LLabel(HBasicBlock* block)
+      : LGap(block), replacement_(NULL) { }
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+    return false;
+  }
+  DECLARE_CONCRETE_INSTRUCTION(Label, "label")
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int block_id() const { return block()->block_id(); }
+  bool is_loop_header() const { return block()->IsLoopHeader(); }
+  bool is_osr_entry() const { return block()->is_osr_entry(); }
+  Label* label() { return &label_; }
+  LLabel* replacement() const { return replacement_; }
+  void set_replacement(LLabel* label) { replacement_ = label; }
+  bool HasReplacement() const { return replacement_ != NULL; }
+
+ private:
+  Label label_;
+  LLabel* replacement_;
+};
+
+
+class LOsrEntry FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  LOsrEntry() {}
+
+  virtual bool HasInterestingComment(LCodeGen* gen) const OVERRIDE {
+    return false;
+  }
+  DECLARE_CONCRETE_INSTRUCTION(OsrEntry, "osr-entry")
+};
+
+
+class LAccessArgumentsAt FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LAccessArgumentsAt(LOperand* arguments,
+                     LOperand* length,
+                     LOperand* index) {
+    inputs_[0] = arguments;
+    inputs_[1] = length;
+    inputs_[2] = index;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(AccessArgumentsAt, "access-arguments-at")
+
+  LOperand* arguments() { return inputs_[0]; }
+  LOperand* length() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LAddE FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAddE(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AddE, "add-e")
+  DECLARE_HYDROGEN_ACCESSOR(Add)
+};
+
+
+class LAddI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAddI(LOperand* left, LOperand* right)
+      : shift_(NO_SHIFT), shift_amount_(0)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LAddI(LOperand* left, LOperand* right, Shift shift, LOperand* shift_amount)
+      : shift_(shift), shift_amount_(shift_amount)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Shift shift() const { return shift_; }
+  LOperand* shift_amount() const { return shift_amount_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AddI, "add-i")
+  DECLARE_HYDROGEN_ACCESSOR(Add)
+
+ protected:
+  Shift shift_;
+  LOperand* shift_amount_;
+};
+
+
+class LAddS FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAddS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(AddS, "add-s")
+  DECLARE_HYDROGEN_ACCESSOR(Add)
+};
+
+
+class LAllocate FINAL : public LTemplateInstruction<1, 2, 3> {
+ public:
+  LAllocate(LOperand* context,
+            LOperand* size,
+            LOperand* temp1,
+            LOperand* temp2,
+            LOperand* temp3) {
+    inputs_[0] = context;
+    inputs_[1] = size;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = temp3;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* size() { return inputs_[1]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+  LOperand* temp3() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Allocate, "allocate")
+  DECLARE_HYDROGEN_ACCESSOR(Allocate)
+};
+
+
+class LApplyArguments FINAL : public LTemplateInstruction<1, 4, 0> {
+ public:
+  LApplyArguments(LOperand* function,
+                  LOperand* receiver,
+                  LOperand* length,
+                  LOperand* elements) {
+    inputs_[0] = function;
+    inputs_[1] = receiver;
+    inputs_[2] = length;
+    inputs_[3] = elements;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(ApplyArguments, "apply-arguments")
+
+  LOperand* function() { return inputs_[0]; }
+  LOperand* receiver() { return inputs_[1]; }
+  LOperand* length() { return inputs_[2]; }
+  LOperand* elements() { return inputs_[3]; }
+};
+
+
+class LArgumentsElements FINAL : public LTemplateInstruction<1, 0, 1> {
+ public:
+  explicit LArgumentsElements(LOperand* temp) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsElements, "arguments-elements")
+  DECLARE_HYDROGEN_ACCESSOR(ArgumentsElements)
+};
+
+
+class LArgumentsLength FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LArgumentsLength(LOperand* elements) {
+    inputs_[0] = elements;
+  }
+
+  LOperand* elements() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ArgumentsLength, "arguments-length")
+};
+
+
+class LArithmeticD FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LArithmeticD(Token::Value op,
+               LOperand* left,
+               LOperand* right)
+      : op_(op) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  Token::Value op() const { return op_; }
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  virtual Opcode opcode() const OVERRIDE {
+    return LInstruction::kArithmeticD;
+  }
+  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
+  virtual const char* Mnemonic() const OVERRIDE;
+
+ private:
+  Token::Value op_;
+};
+
+
+class LArithmeticT FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LArithmeticT(Token::Value op,
+               LOperand* context,
+               LOperand* left,
+               LOperand* right)
+      : op_(op) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+  Token::Value op() const { return op_; }
+
+  virtual Opcode opcode() const OVERRIDE {
+    return LInstruction::kArithmeticT;
+  }
+  virtual void CompileToNative(LCodeGen* generator) OVERRIDE;
+  virtual const char* Mnemonic() const OVERRIDE;
+
+ private:
+  Token::Value op_;
+};
+
+
+class LBoundsCheck FINAL : public LTemplateInstruction<0, 2, 0> {
+ public:
+  explicit LBoundsCheck(LOperand* index, LOperand* length) {
+    inputs_[0] = index;
+    inputs_[1] = length;
+  }
+
+  LOperand* index() { return inputs_[0]; }
+  LOperand* length() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(BoundsCheck, "bounds-check")
+  DECLARE_HYDROGEN_ACCESSOR(BoundsCheck)
+};
+
+
+class LBitI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LBitI(LOperand* left, LOperand* right)
+      : shift_(NO_SHIFT), shift_amount_(0)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LBitI(LOperand* left, LOperand* right, Shift shift, LOperand* shift_amount)
+      : shift_(shift), shift_amount_(shift_amount)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Shift shift() const { return shift_; }
+  LOperand* shift_amount() const { return shift_amount_; }
+
+  Token::Value op() const { return hydrogen()->op(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(BitI, "bit-i")
+  DECLARE_HYDROGEN_ACCESSOR(Bitwise)
+
+ protected:
+  Shift shift_;
+  LOperand* shift_amount_;
+};
+
+
+class LBitS FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LBitS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Token::Value op() const { return hydrogen()->op(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(BitS, "bit-s")
+  DECLARE_HYDROGEN_ACCESSOR(Bitwise)
+};
+
+
+class LBranch FINAL : public LControlInstruction<1, 2> {
+ public:
+  explicit LBranch(LOperand* value, LOperand *temp1, LOperand *temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Branch, "branch")
+  DECLARE_HYDROGEN_ACCESSOR(Branch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LCallJSFunction FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallJSFunction(LOperand* function) {
+    inputs_[0] = function;
+  }
+
+  LOperand* function() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallJSFunction, "call-js-function")
+  DECLARE_HYDROGEN_ACCESSOR(CallJSFunction)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallFunction(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallFunction, "call-function")
+  DECLARE_HYDROGEN_ACCESSOR(CallFunction)
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallNew FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallNew(LOperand* context, LOperand* constructor) {
+    inputs_[0] = context;
+    inputs_[1] = constructor;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* constructor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNew, "call-new")
+  DECLARE_HYDROGEN_ACCESSOR(CallNew)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallNewArray FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LCallNewArray(LOperand* context, LOperand* constructor) {
+    inputs_[0] = context;
+    inputs_[1] = constructor;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* constructor() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallNewArray, "call-new-array")
+  DECLARE_HYDROGEN_ACCESSOR(CallNewArray)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LCallRuntime FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallRuntime(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallRuntime, "call-runtime")
+  DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
+
+  virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
+    return save_doubles() == kDontSaveFPRegs;
+  }
+
+  const Runtime::Function* function() const { return hydrogen()->function(); }
+  int arity() const { return hydrogen()->argument_count(); }
+  SaveFPRegsMode save_doubles() const { return hydrogen()->save_doubles(); }
+};
+
+
+class LCallStub FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCallStub(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CallStub, "call-stub")
+  DECLARE_HYDROGEN_ACCESSOR(CallStub)
+};
+
+
+class LCheckInstanceType FINAL : public LTemplateInstruction<0, 1, 1> {
+ public:
+  explicit LCheckInstanceType(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckInstanceType, "check-instance-type")
+  DECLARE_HYDROGEN_ACCESSOR(CheckInstanceType)
+};
+
+
+class LCheckMaps FINAL : public LTemplateInstruction<0, 1, 1> {
+ public:
+  explicit LCheckMaps(LOperand* value = NULL, LOperand* temp = NULL) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckMaps, "check-maps")
+  DECLARE_HYDROGEN_ACCESSOR(CheckMaps)
+};
+
+
+class LCheckNonSmi FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckNonSmi(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckNonSmi, "check-non-smi")
+  DECLARE_HYDROGEN_ACCESSOR(CheckHeapObject)
+};
+
+
+class LCheckSmi FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LCheckSmi(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckSmi, "check-smi")
+};
+
+
+class LCheckValue FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LCheckValue(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckValue, "check-value")
+  DECLARE_HYDROGEN_ACCESSOR(CheckValue)
+};
+
+
+class LClampDToUint8 FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LClampDToUint8(LOperand* unclamped) {
+    inputs_[0] = unclamped;
+  }
+
+  LOperand* unclamped() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampDToUint8, "clamp-d-to-uint8")
+};
+
+
+class LClampIToUint8 FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LClampIToUint8(LOperand* unclamped) {
+    inputs_[0] = unclamped;
+  }
+
+  LOperand* unclamped() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampIToUint8, "clamp-i-to-uint8")
+};
+
+
+class LClampTToUint8 FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LClampTToUint8(LOperand* unclamped, LOperand* temp1) {
+    inputs_[0] = unclamped;
+    temps_[0] = temp1;
+  }
+
+  LOperand* unclamped() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClampTToUint8, "clamp-t-to-uint8")
+};
+
+
+class LDoubleBits FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDoubleBits(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DoubleBits, "double-bits")
+  DECLARE_HYDROGEN_ACCESSOR(DoubleBits)
+};
+
+
+class LConstructDouble FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LConstructDouble(LOperand* hi, LOperand* lo) {
+    inputs_[0] = hi;
+    inputs_[1] = lo;
+  }
+
+  LOperand* hi() { return inputs_[0]; }
+  LOperand* lo() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ConstructDouble, "construct-double")
+};
+
+
+class LClassOfTestAndBranch FINAL : public LControlInstruction<1, 2> {
+ public:
+  LClassOfTestAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ClassOfTestAndBranch,
+                               "class-of-test-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(ClassOfTestAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LCmpHoleAndBranchD FINAL : public LControlInstruction<1, 1> {
+ public:
+  explicit LCmpHoleAndBranchD(LOperand* object, LOperand* temp) {
+    inputs_[0] = object;
+    temps_[0] = temp;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranchD, "cmp-hole-and-branch-d")
+  DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch)
+};
+
+
+class LCmpHoleAndBranchT FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LCmpHoleAndBranchT(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpHoleAndBranchT, "cmp-hole-and-branch-t")
+  DECLARE_HYDROGEN_ACCESSOR(CompareHoleAndBranch)
+};
+
+
+class LCmpMapAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCmpMapAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpMapAndBranch, "cmp-map-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMap)
+
+  Handle<Map> map() const { return hydrogen()->map().handle(); }
+};
+
+
+class LCmpObjectEqAndBranch FINAL : public LControlInstruction<2, 0> {
+ public:
+  LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpObjectEqAndBranch, "cmp-object-eq-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareObjectEqAndBranch)
+};
+
+
+class LCmpT FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LCmpT(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CmpT, "cmp-t")
+  DECLARE_HYDROGEN_ACCESSOR(CompareGeneric)
+
+  Token::Value op() const { return hydrogen()->token(); }
+};
+
+
+class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
+                               "cmp-minus-zero-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareMinusZeroAndBranch)
+};
+
+
+class LCompareNumericAndBranch FINAL : public LControlInstruction<2, 0> {
+ public:
+  LCompareNumericAndBranch(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CompareNumericAndBranch,
+                               "compare-numeric-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(CompareNumericAndBranch)
+
+  Token::Value op() const { return hydrogen()->token(); }
+  bool is_double() const {
+    return hydrogen()->representation().IsDouble();
+  }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LConstantD FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantD, "constant-d")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  double value() const { return hydrogen()->DoubleValue(); }
+};
+
+
+class LConstantE FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantE, "constant-e")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  ExternalReference value() const {
+    return hydrogen()->ExternalReferenceValue();
+  }
+};
+
+
+class LConstantI FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  int32_t value() const { return hydrogen()->Integer32Value(); }
+};
+
+
+class LConstantS FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantS, "constant-s")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  Smi* value() const { return Smi::FromInt(hydrogen()->Integer32Value()); }
+};
+
+
+class LConstantT FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ConstantT, "constant-t")
+  DECLARE_HYDROGEN_ACCESSOR(Constant)
+
+  Handle<Object> value(Isolate* isolate) const {
+    return hydrogen()->handle(isolate);
+  }
+};
+
+
+class LContext FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(Context, "context")
+  DECLARE_HYDROGEN_ACCESSOR(Context)
+};
+
+
+class LDateField FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LDateField(LOperand* date, Smi* index) : index_(index) {
+    inputs_[0] = date;
+  }
+
+  LOperand* date() { return inputs_[0]; }
+  Smi* index() const { return index_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DateField, "date-field")
+  DECLARE_HYDROGEN_ACCESSOR(DateField)
+
+ private:
+  Smi* index_;
+};
+
+
+class LDebugBreak FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(DebugBreak, "break")
+};
+
+
+class LDeclareGlobals FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LDeclareGlobals(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DeclareGlobals, "declare-globals")
+  DECLARE_HYDROGEN_ACCESSOR(DeclareGlobals)
+};
+
+
+class LDeoptimize FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  virtual bool IsControl() const OVERRIDE { return true; }
+  DECLARE_CONCRETE_INSTRUCTION(Deoptimize, "deoptimize")
+  DECLARE_HYDROGEN_ACCESSOR(Deoptimize)
+};
+
+
+class LDivByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivByPowerOf2I, "div-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(Div)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LDivByConstI FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivByConstI, "div-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(Div)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LDivI FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    inputs_[1] = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  LOperand* divisor() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DivI, "div-i")
+  DECLARE_HYDROGEN_ACCESSOR(BinaryOperation)
+};
+
+
+class LDoubleToIntOrSmi FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LDoubleToIntOrSmi(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(DoubleToIntOrSmi, "double-to-int-or-smi")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+  bool tag_result() { return hydrogen()->representation().IsSmi(); }
+};
+
+
+class LForInCacheArray FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LForInCacheArray(LOperand* map) {
+    inputs_[0] = map;
+  }
+
+  LOperand* map() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ForInCacheArray, "for-in-cache-array")
+
+  int idx() {
+    return HForInCacheArray::cast(this->hydrogen_value())->idx();
+  }
+};
+
+
+class LForInPrepareMap FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LForInPrepareMap(LOperand* context, LOperand* object) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ForInPrepareMap, "for-in-prepare-map")
+};
+
+
+class LGetCachedArrayIndex FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LGetCachedArrayIndex(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(GetCachedArrayIndex, "get-cached-array-index")
+  DECLARE_HYDROGEN_ACCESSOR(GetCachedArrayIndex)
+};
+
+
+class LHasCachedArrayIndexAndBranch FINAL
+    : public LControlInstruction<1, 1> {
+ public:
+  LHasCachedArrayIndexAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(HasCachedArrayIndexAndBranch,
+                               "has-cached-array-index-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(HasCachedArrayIndexAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LHasInstanceTypeAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LHasInstanceTypeAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(HasInstanceTypeAndBranch,
+                               "has-instance-type-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(HasInstanceTypeAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LInnerAllocatedObject FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LInnerAllocatedObject(LOperand* base_object, LOperand* offset) {
+    inputs_[0] = base_object;
+    inputs_[1] = offset;
+  }
+
+  LOperand* base_object() const { return inputs_[0]; }
+  LOperand* offset() const { return inputs_[1]; }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  DECLARE_CONCRETE_INSTRUCTION(InnerAllocatedObject, "inner-allocated-object")
+};
+
+
+class LInstanceOf FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LInstanceOf(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstanceOf, "instance-of")
+};
+
+
+class LInstanceOfKnownGlobal FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LInstanceOfKnownGlobal(LOperand* context, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InstanceOfKnownGlobal,
+                               "instance-of-known-global")
+  DECLARE_HYDROGEN_ACCESSOR(InstanceOfKnownGlobal)
+
+  Handle<JSFunction> function() const { return hydrogen()->function(); }
+  LEnvironment* GetDeferredLazyDeoptimizationEnvironment() {
+    return lazy_deopt_env_;
+  }
+  virtual void SetDeferredLazyDeoptimizationEnvironment(
+      LEnvironment* env) OVERRIDE {
+    lazy_deopt_env_ = env;
+  }
+
+ private:
+  LEnvironment* lazy_deopt_env_;
+};
+
+
+class LInteger32ToDouble FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LInteger32ToDouble(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Integer32ToDouble, "int32-to-double")
+};
+
+
+class LCallWithDescriptor FINAL : public LTemplateResultInstruction<1> {
+ public:
+  LCallWithDescriptor(CallInterfaceDescriptor descriptor,
+                      const ZoneList<LOperand*>& operands, Zone* zone)
+      : descriptor_(descriptor),
+        inputs_(descriptor.GetRegisterParameterCount() + 1, zone) {
+    DCHECK(descriptor.GetRegisterParameterCount() + 1 == operands.length());
+    inputs_.AddAll(operands, zone);
+  }
+
+  LOperand* target() const { return inputs_[0]; }
+
+  CallInterfaceDescriptor descriptor() { return descriptor_; }
+
+ private:
+  DECLARE_CONCRETE_INSTRUCTION(CallWithDescriptor, "call-with-descriptor")
+  DECLARE_HYDROGEN_ACCESSOR(CallWithDescriptor)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+
+  CallInterfaceDescriptor descriptor_;
+  ZoneList<LOperand*> inputs_;
+
+  // Iterator support.
+  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
+  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+
+  virtual int TempCount() FINAL OVERRIDE { return 0; }
+  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+};
+
+
+class LInvokeFunction FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LInvokeFunction(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(InvokeFunction, "invoke-function")
+  DECLARE_HYDROGEN_ACCESSOR(InvokeFunction)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  int arity() const { return hydrogen()->argument_count() - 1; }
+};
+
+
+class LIsConstructCallAndBranch FINAL : public LControlInstruction<0, 2> {
+ public:
+  LIsConstructCallAndBranch(LOperand* temp1, LOperand* temp2) {
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsConstructCallAndBranch,
+                               "is-construct-call-and-branch")
+};
+
+
+class LIsObjectAndBranch FINAL : public LControlInstruction<1, 2> {
+ public:
+  LIsObjectAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsObjectAndBranch, "is-object-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsObjectAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsStringAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  LIsStringAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsStringAndBranch, "is-string-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsStringAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsSmiAndBranch FINAL : public LControlInstruction<1, 0> {
+ public:
+  explicit LIsSmiAndBranch(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsSmiAndBranch, "is-smi-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsSmiAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LIsUndetectableAndBranch FINAL : public LControlInstruction<1, 1> {
+ public:
+  explicit LIsUndetectableAndBranch(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(IsUndetectableAndBranch,
+                               "is-undetectable-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(IsUndetectableAndBranch)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LLoadContextSlot FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadContextSlot(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadContextSlot, "load-context-slot")
+  DECLARE_HYDROGEN_ACCESSOR(LoadContextSlot)
+
+  int slot_index() const { return hydrogen()->slot_index(); }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LLoadNamedField FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LLoadNamedField(LOperand* object) {
+    inputs_[0] = object;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedField, "load-named-field")
+  DECLARE_HYDROGEN_ACCESSOR(LoadNamedField)
+};
+
+
+class LFunctionLiteral FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LFunctionLiteral(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FunctionLiteral, "function-literal")
+  DECLARE_HYDROGEN_ACCESSOR(FunctionLiteral)
+};
+
+
+class LLoadFunctionPrototype FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LLoadFunctionPrototype(LOperand* function, LOperand* temp) {
+    inputs_[0] = function;
+    temps_[0] = temp;
+  }
+
+  LOperand* function() { return inputs_[0]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadFunctionPrototype, "load-function-prototype")
+  DECLARE_HYDROGEN_ACCESSOR(LoadFunctionPrototype)
+};
+
+
+class LLoadGlobalCell FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(LoadGlobalCell, "load-global-cell")
+  DECLARE_HYDROGEN_ACCESSOR(LoadGlobalCell)
+};
+
+
+class LLoadGlobalGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LLoadGlobalGeneric(LOperand* context, LOperand* global_object,
+                     LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = global_object;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* global_object() { return inputs_[1]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadGlobalGeneric, "load-global-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadGlobalGeneric)
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+  bool for_typeof() const { return hydrogen()->for_typeof(); }
+};
+
+
+template<int T>
+class LLoadKeyed : public LTemplateInstruction<1, 2, T> {
+ public:
+  LLoadKeyed(LOperand* elements, LOperand* key) {
+    this->inputs_[0] = elements;
+    this->inputs_[1] = key;
+  }
+
+  LOperand* elements() { return this->inputs_[0]; }
+  LOperand* key() { return this->inputs_[1]; }
+  ElementsKind elements_kind() const {
+    return this->hydrogen()->elements_kind();
+  }
+  bool is_external() const {
+    return this->hydrogen()->is_external();
+  }
+  bool is_fixed_typed_array() const {
+    return hydrogen()->is_fixed_typed_array();
+  }
+  bool is_typed_elements() const {
+    return is_external() || is_fixed_typed_array();
+  }
+  uint32_t base_offset() const {
+    return this->hydrogen()->base_offset();
+  }
+  void PrintDataTo(StringStream* stream) OVERRIDE {
+    this->elements()->PrintTo(stream);
+    stream->Add("[");
+    this->key()->PrintTo(stream);
+    if (this->base_offset() != 0) {
+      stream->Add(" + %d]", this->base_offset());
+    } else {
+      stream->Add("]");
+    }
+  }
+
+  DECLARE_HYDROGEN_ACCESSOR(LoadKeyed)
+};
+
+
+class LLoadKeyedExternal: public LLoadKeyed<1> {
+ public:
+  LLoadKeyedExternal(LOperand* elements, LOperand* key, LOperand* temp) :
+      LLoadKeyed<1>(elements, key) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedExternal, "load-keyed-external");
+};
+
+
+class LLoadKeyedFixed: public LLoadKeyed<1> {
+ public:
+  LLoadKeyedFixed(LOperand* elements, LOperand* key, LOperand* temp) :
+      LLoadKeyed<1>(elements, key) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFixed, "load-keyed-fixed");
+};
+
+
+class LLoadKeyedFixedDouble: public LLoadKeyed<1> {
+ public:
+  LLoadKeyedFixedDouble(LOperand* elements, LOperand* key, LOperand* temp) :
+      LLoadKeyed<1>(elements, key) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedFixedDouble, "load-keyed-fixed-double");
+};
+
+
+class LLoadKeyedGeneric FINAL : public LTemplateInstruction<1, 3, 1> {
+ public:
+  LLoadKeyedGeneric(LOperand* context, LOperand* object, LOperand* key,
+                    LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    inputs_[2] = key;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* key() { return inputs_[2]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadKeyedGeneric, "load-keyed-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadKeyedGeneric)
+};
+
+
+class LLoadNamedGeneric FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LLoadNamedGeneric(LOperand* context, LOperand* object, LOperand* vector) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    temps_[0] = vector;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* temp_vector() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadNamedGeneric, "load-named-generic")
+  DECLARE_HYDROGEN_ACCESSOR(LoadNamedGeneric)
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+};
+
+
+class LLoadRoot FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(LoadRoot, "load-root")
+  DECLARE_HYDROGEN_ACCESSOR(LoadRoot)
+
+  Heap::RootListIndex index() const { return hydrogen()->index(); }
+};
+
+
+class LMapEnumLength FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LMapEnumLength(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MapEnumLength, "map-enum-length")
+};
+
+
+template<int T>
+class LUnaryMathOperation : public LTemplateInstruction<1, 1, T> {
+ public:
+  explicit LUnaryMathOperation(LOperand* value) {
+    this->inputs_[0] = value;
+  }
+
+  LOperand* value() { return this->inputs_[0]; }
+  BuiltinFunctionId op() const { return this->hydrogen()->op(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathAbs FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathAbs(LOperand* value) : LUnaryMathOperation<0>(value) {}
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbs, "math-abs")
+};
+
+
+class LMathAbsTagged: public LTemplateInstruction<1, 2, 3> {
+ public:
+  LMathAbsTagged(LOperand* context, LOperand* value,
+                 LOperand* temp1, LOperand* temp2, LOperand* temp3) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = temp3;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+  LOperand* temp3() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathAbsTagged, "math-abs-tagged")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
+};
+
+
+class LMathExp FINAL : public LUnaryMathOperation<4> {
+ public:
+  LMathExp(LOperand* value,
+                LOperand* double_temp1,
+                LOperand* temp1,
+                LOperand* temp2,
+                LOperand* temp3)
+      : LUnaryMathOperation<4>(value) {
+    temps_[0] = double_temp1;
+    temps_[1] = temp1;
+    temps_[2] = temp2;
+    temps_[3] = temp3;
+    ExternalReference::InitializeMathExpData();
+  }
+
+  LOperand* double_temp1() { return temps_[0]; }
+  LOperand* temp1() { return temps_[1]; }
+  LOperand* temp2() { return temps_[2]; }
+  LOperand* temp3() { return temps_[3]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+};
+
+
+// Math.floor with a double result.
+class LMathFloorD FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathFloorD(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathFloorD, "math-floor-d")
+};
+
+
+// Math.floor with an integer result.
+class LMathFloorI FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathFloorI(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathFloorI, "math-floor-i")
+};
+
+
+class LFlooringDivByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LFlooringDivByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivByPowerOf2I,
+                               "flooring-div-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LFlooringDivByConstI FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LFlooringDivByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivByConstI, "flooring-div-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LFlooringDivI FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LFlooringDivI(LOperand* dividend, LOperand* divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    inputs_[1] = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  LOperand* divisor() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(FlooringDivI, "flooring-div-i")
+  DECLARE_HYDROGEN_ACCESSOR(MathFloorOfDiv)
+};
+
+
+class LMathLog FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathLog(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathLog, "math-log")
+};
+
+
+class LMathClz32 FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathClz32(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
+};
+
+
+class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMathMinMax(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
+  DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
+};
+
+
+class LMathPowHalf FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathPowHalf(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
+};
+
+
+// Math.round with an integer result.
+class LMathRoundD FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathRoundD(LOperand* value)
+      : LUnaryMathOperation<0>(value) {
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRoundD, "math-round-d")
+};
+
+
+// Math.round with an integer result.
+class LMathRoundI FINAL : public LUnaryMathOperation<1> {
+ public:
+  LMathRoundI(LOperand* value, LOperand* temp1)
+      : LUnaryMathOperation<1>(value) {
+    temps_[0] = temp1;
+  }
+
+  LOperand* temp1() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathRoundI, "math-round-i")
+};
+
+
+class LMathFround FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathFround(LOperand* value) : LUnaryMathOperation<0>(value) {}
+
+  DECLARE_CONCRETE_INSTRUCTION(MathFround, "math-fround")
+};
+
+
+class LMathSqrt FINAL : public LUnaryMathOperation<0> {
+ public:
+  explicit LMathSqrt(LOperand* value) : LUnaryMathOperation<0>(value) { }
+  DECLARE_CONCRETE_INSTRUCTION(MathSqrt, "math-sqrt")
+};
+
+
+class LModByPowerOf2I FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LModByPowerOf2I(LOperand* dividend, int32_t divisor) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModByPowerOf2I, "mod-by-power-of-2-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LModByConstI FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LModByConstI(LOperand* dividend, int32_t divisor, LOperand* temp) {
+    inputs_[0] = dividend;
+    divisor_ = divisor;
+    temps_[0] = temp;
+  }
+
+  LOperand* dividend() { return inputs_[0]; }
+  int32_t divisor() const { return divisor_; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModByConstI, "mod-by-const-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+
+ private:
+  int32_t divisor_;
+};
+
+
+class LModI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LModI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ModI, "mod-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mod)
+};
+
+
+class LMulConstIS FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMulConstIS(LOperand* left, LConstantOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LConstantOperand* right() { return LConstantOperand::cast(inputs_[1]); }
+
+  DECLARE_CONCRETE_INSTRUCTION(MulConstIS, "mul-const-i-s")
+  DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
+class LMulI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMulI(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-i")
+  DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
+class LMulS FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LMulS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MulI, "mul-s")
+  DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
+class LNumberTagD FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  LNumberTagD(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagD, "number-tag-d")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LNumberTagU FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  explicit LNumberTagU(LOperand* value,
+                       LOperand* temp1,
+                       LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberTagU, "number-tag-u")
+};
+
+
+class LNumberUntagD FINAL : public LTemplateInstruction<1, 1, 1> {
+ public:
+  LNumberUntagD(LOperand* value, LOperand* temp) {
+    inputs_[0] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(NumberUntagD, "double-untag")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LParameter FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  virtual bool HasInterestingComment(LCodeGen* gen) const { return false; }
+  DECLARE_CONCRETE_INSTRUCTION(Parameter, "parameter")
+};
+
+
+class LPower FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LPower(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Power, "power")
+  DECLARE_HYDROGEN_ACCESSOR(Power)
+};
+
+
+class LPreparePushArguments FINAL : public LTemplateInstruction<0, 0, 0> {
+ public:
+  explicit LPreparePushArguments(int argc) : argc_(argc) {}
+
+  inline int argc() const { return argc_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(PreparePushArguments, "prepare-push-arguments")
+
+ protected:
+  int argc_;
+};
+
+
+class LPushArguments FINAL : public LTemplateResultInstruction<0> {
+ public:
+  explicit LPushArguments(Zone* zone,
+                          int capacity = kRecommendedMaxPushedArgs)
+      : zone_(zone), inputs_(capacity, zone) {}
+
+  LOperand* argument(int i) { return inputs_[i]; }
+  int ArgumentCount() const { return inputs_.length(); }
+
+  void AddArgument(LOperand* arg) { inputs_.Add(arg, zone_); }
+
+  DECLARE_CONCRETE_INSTRUCTION(PushArguments, "push-arguments")
+
+  // It is better to limit the number of arguments pushed simultaneously to
+  // avoid pressure on the register allocator.
+  static const int kRecommendedMaxPushedArgs = 4;
+  bool ShouldSplitPush() const {
+    return inputs_.length() >= kRecommendedMaxPushedArgs;
+  }
+
+ protected:
+  Zone* zone_;
+  ZoneList<LOperand*> inputs_;
+
+ private:
+  // Iterator support.
+  virtual int InputCount() FINAL OVERRIDE { return inputs_.length(); }
+  virtual LOperand* InputAt(int i) FINAL OVERRIDE { return inputs_[i]; }
+
+  virtual int TempCount() FINAL OVERRIDE { return 0; }
+  virtual LOperand* TempAt(int i) FINAL OVERRIDE { return NULL; }
+};
+
+
+class LRegExpLiteral FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LRegExpLiteral(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(RegExpLiteral, "regexp-literal")
+  DECLARE_HYDROGEN_ACCESSOR(RegExpLiteral)
+};
+
+
+class LReturn FINAL : public LTemplateInstruction<0, 3, 0> {
+ public:
+  LReturn(LOperand* value, LOperand* context, LOperand* parameter_count) {
+    inputs_[0] = value;
+    inputs_[1] = context;
+    inputs_[2] = parameter_count;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* parameter_count() { return inputs_[2]; }
+
+  bool has_constant_parameter_count() {
+    return parameter_count()->IsConstantOperand();
+  }
+  LConstantOperand* constant_parameter_count() {
+    DCHECK(has_constant_parameter_count());
+    return LConstantOperand::cast(parameter_count());
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(Return, "return")
+};
+
+
+class LSeqStringGetChar FINAL : public LTemplateInstruction<1, 2, 1> {
+ public:
+  LSeqStringGetChar(LOperand* string,
+                    LOperand* index,
+                    LOperand* temp) {
+    inputs_[0] = string;
+    inputs_[1] = index;
+    temps_[0] = temp;
+  }
+
+  LOperand* string() { return inputs_[0]; }
+  LOperand* index() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SeqStringGetChar, "seq-string-get-char")
+  DECLARE_HYDROGEN_ACCESSOR(SeqStringGetChar)
+};
+
+
+class LSeqStringSetChar FINAL : public LTemplateInstruction<1, 4, 1> {
+ public:
+  LSeqStringSetChar(LOperand* context,
+                    LOperand* string,
+                    LOperand* index,
+                    LOperand* value,
+                    LOperand* temp) {
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+    inputs_[3] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SeqStringSetChar, "seq-string-set-char")
+  DECLARE_HYDROGEN_ACCESSOR(SeqStringSetChar)
+};
+
+
+class LSmiTag FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LSmiTag(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SmiTag, "smi-tag")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+};
+
+
+class LSmiUntag FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  LSmiUntag(LOperand* value, bool needs_check)
+      : needs_check_(needs_check) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  bool needs_check() const { return needs_check_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SmiUntag, "smi-untag")
+
+ private:
+  bool needs_check_;
+};
+
+
+class LStackCheck FINAL : public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LStackCheck(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StackCheck, "stack-check")
+  DECLARE_HYDROGEN_ACCESSOR(StackCheck)
+
+  Label* done_label() { return &done_label_; }
+
+ private:
+  Label done_label_;
+};
+
+
+template<int T>
+class LStoreKeyed : public LTemplateInstruction<0, 3, T> {
+ public:
+  LStoreKeyed(LOperand* elements, LOperand* key, LOperand* value) {
+    this->inputs_[0] = elements;
+    this->inputs_[1] = key;
+    this->inputs_[2] = value;
+  }
+
+  bool is_external() const { return this->hydrogen()->is_external(); }
+  bool is_fixed_typed_array() const {
+    return hydrogen()->is_fixed_typed_array();
+  }
+  bool is_typed_elements() const {
+    return is_external() || is_fixed_typed_array();
+  }
+  LOperand* elements() { return this->inputs_[0]; }
+  LOperand* key() { return this->inputs_[1]; }
+  LOperand* value() { return this->inputs_[2]; }
+  ElementsKind elements_kind() const {
+    return this->hydrogen()->elements_kind();
+  }
+
+  bool NeedsCanonicalization() {
+    if (hydrogen()->value()->IsAdd() || hydrogen()->value()->IsSub() ||
+        hydrogen()->value()->IsMul() || hydrogen()->value()->IsDiv()) {
+      return false;
+    }
+    return this->hydrogen()->NeedsCanonicalization();
+  }
+  uint32_t base_offset() const { return this->hydrogen()->base_offset(); }
+
+  void PrintDataTo(StringStream* stream) OVERRIDE {
+    this->elements()->PrintTo(stream);
+    stream->Add("[");
+    this->key()->PrintTo(stream);
+    if (this->base_offset() != 0) {
+      stream->Add(" + %d] <-", this->base_offset());
+    } else {
+      stream->Add("] <- ");
+    }
+
+    if (this->value() == NULL) {
+      DCHECK(hydrogen()->IsConstantHoleStore() &&
+             hydrogen()->value()->representation().IsDouble());
+      stream->Add("<the hole(nan)>");
+    } else {
+      this->value()->PrintTo(stream);
+    }
+  }
+
+  DECLARE_HYDROGEN_ACCESSOR(StoreKeyed)
+};
+
+
+class LStoreKeyedExternal FINAL : public LStoreKeyed<1> {
+ public:
+  LStoreKeyedExternal(LOperand* elements, LOperand* key, LOperand* value,
+                      LOperand* temp) :
+      LStoreKeyed<1>(elements, key, value) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedExternal, "store-keyed-external")
+};
+
+
+class LStoreKeyedFixed FINAL : public LStoreKeyed<1> {
+ public:
+  LStoreKeyedFixed(LOperand* elements, LOperand* key, LOperand* value,
+                   LOperand* temp) :
+      LStoreKeyed<1>(elements, key, value) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFixed, "store-keyed-fixed")
+};
+
+
+class LStoreKeyedFixedDouble FINAL : public LStoreKeyed<1> {
+ public:
+  LStoreKeyedFixedDouble(LOperand* elements, LOperand* key, LOperand* value,
+                         LOperand* temp) :
+      LStoreKeyed<1>(elements, key, value) {
+    temps_[0] = temp;
+  }
+
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedFixedDouble,
+                               "store-keyed-fixed-double")
+};
+
+
+class LStoreKeyedGeneric FINAL : public LTemplateInstruction<0, 4, 0> {
+ public:
+  LStoreKeyedGeneric(LOperand* context,
+                     LOperand* obj,
+                     LOperand* key,
+                     LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = obj;
+    inputs_[2] = key;
+    inputs_[3] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* key() { return inputs_[2]; }
+  LOperand* value() { return inputs_[3]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreKeyedGeneric, "store-keyed-generic")
+  DECLARE_HYDROGEN_ACCESSOR(StoreKeyedGeneric)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  StrictMode strict_mode() { return hydrogen()->strict_mode(); }
+};
+
+
+class LStoreNamedField FINAL : public LTemplateInstruction<0, 2, 2> {
+ public:
+  LStoreNamedField(LOperand* object, LOperand* value,
+                   LOperand* temp0, LOperand* temp1) {
+    inputs_[0] = object;
+    inputs_[1] = value;
+    temps_[0] = temp0;
+    temps_[1] = temp1;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+  LOperand* temp0() { return temps_[0]; }
+  LOperand* temp1() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedField, "store-named-field")
+  DECLARE_HYDROGEN_ACCESSOR(StoreNamedField)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Representation representation() const {
+    return hydrogen()->field_representation();
+  }
+};
+
+
+class LStoreNamedGeneric FINAL: public LTemplateInstruction<0, 3, 0> {
+ public:
+  LStoreNamedGeneric(LOperand* context, LOperand* object, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = object;
+    inputs_[2] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* object() { return inputs_[1]; }
+  LOperand* value() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreNamedGeneric, "store-named-generic")
+  DECLARE_HYDROGEN_ACCESSOR(StoreNamedGeneric)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Handle<Object> name() const { return hydrogen()->name(); }
+  StrictMode strict_mode() { return hydrogen()->strict_mode(); }
+};
+
+
+class LStringAdd FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LStringAdd(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringAdd, "string-add")
+  DECLARE_HYDROGEN_ACCESSOR(StringAdd)
+};
+
+
+
+class LStringCharCodeAt FINAL : public LTemplateInstruction<1, 3, 0> {
+ public:
+  LStringCharCodeAt(LOperand* context, LOperand* string, LOperand* index) {
+    inputs_[0] = context;
+    inputs_[1] = string;
+    inputs_[2] = index;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* string() { return inputs_[1]; }
+  LOperand* index() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCharCodeAt, "string-char-code-at")
+  DECLARE_HYDROGEN_ACCESSOR(StringCharCodeAt)
+};
+
+
+class LStringCharFromCode FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LStringCharFromCode(LOperand* context, LOperand* char_code) {
+    inputs_[0] = context;
+    inputs_[1] = char_code;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* char_code() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCharFromCode, "string-char-from-code")
+  DECLARE_HYDROGEN_ACCESSOR(StringCharFromCode)
+};
+
+
+class LStringCompareAndBranch FINAL : public LControlInstruction<3, 0> {
+ public:
+  LStringCompareAndBranch(LOperand* context, LOperand* left, LOperand* right) {
+    inputs_[0] = context;
+    inputs_[1] = left;
+    inputs_[2] = right;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* left() { return inputs_[1]; }
+  LOperand* right() { return inputs_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StringCompareAndBranch,
+                               "string-compare-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(StringCompareAndBranch)
+
+  Token::Value op() const { return hydrogen()->token(); }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+// Truncating conversion from a tagged value to an int32.
+class LTaggedToI FINAL : public LTemplateInstruction<1, 1, 2> {
+ public:
+  explicit LTaggedToI(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TaggedToI, "tagged-to-i")
+  DECLARE_HYDROGEN_ACCESSOR(Change)
+
+  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
+};
+
+
+class LShiftI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LShiftI(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
+      : op_(op), can_deopt_(can_deopt) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  Token::Value op() const { return op_; }
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+  bool can_deopt() const { return can_deopt_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ShiftI, "shift-i")
+
+ private:
+  Token::Value op_;
+  bool can_deopt_;
+};
+
+
+class LShiftS FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LShiftS(Token::Value op, LOperand* left, LOperand* right, bool can_deopt)
+      : op_(op), can_deopt_(can_deopt) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  Token::Value op() const { return op_; }
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+  bool can_deopt() const { return can_deopt_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ShiftS, "shift-s")
+
+ private:
+  Token::Value op_;
+  bool can_deopt_;
+};
+
+
+class LStoreCodeEntry FINAL: public LTemplateInstruction<0, 2, 1> {
+ public:
+  LStoreCodeEntry(LOperand* function, LOperand* code_object,
+                  LOperand* temp) {
+    inputs_[0] = function;
+    inputs_[1] = code_object;
+    temps_[0] = temp;
+  }
+
+  LOperand* function() { return inputs_[0]; }
+  LOperand* code_object() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreCodeEntry, "store-code-entry")
+  DECLARE_HYDROGEN_ACCESSOR(StoreCodeEntry)
+};
+
+
+class LStoreContextSlot FINAL : public LTemplateInstruction<0, 2, 1> {
+ public:
+  LStoreContextSlot(LOperand* context, LOperand* value, LOperand* temp) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+    temps_[0] = temp;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreContextSlot, "store-context-slot")
+  DECLARE_HYDROGEN_ACCESSOR(StoreContextSlot)
+
+  int slot_index() { return hydrogen()->slot_index(); }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LStoreGlobalCell FINAL : public LTemplateInstruction<0, 1, 2> {
+ public:
+  LStoreGlobalCell(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreGlobalCell, "store-global-cell")
+  DECLARE_HYDROGEN_ACCESSOR(StoreGlobalCell)
+};
+
+
+class LSubI FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LSubI(LOperand* left, LOperand* right)
+      : shift_(NO_SHIFT), shift_amount_(0)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LSubI(LOperand* left, LOperand* right, Shift shift, LOperand* shift_amount)
+      : shift_(shift), shift_amount_(shift_amount)  {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  Shift shift() const { return shift_; }
+  LOperand* shift_amount() const { return shift_amount_; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SubI, "sub-i")
+  DECLARE_HYDROGEN_ACCESSOR(Sub)
+
+ protected:
+  Shift shift_;
+  LOperand* shift_amount_;
+};
+
+
+class LSubS: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LSubS(LOperand* left, LOperand* right) {
+    inputs_[0] = left;
+    inputs_[1] = right;
+  }
+
+  LOperand* left() { return inputs_[0]; }
+  LOperand* right() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(SubS, "sub-s")
+  DECLARE_HYDROGEN_ACCESSOR(Sub)
+};
+
+
+class LThisFunction FINAL : public LTemplateInstruction<1, 0, 0> {
+ public:
+  DECLARE_CONCRETE_INSTRUCTION(ThisFunction, "this-function")
+  DECLARE_HYDROGEN_ACCESSOR(ThisFunction)
+};
+
+
+class LToFastProperties FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LToFastProperties(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(ToFastProperties, "to-fast-properties")
+  DECLARE_HYDROGEN_ACCESSOR(ToFastProperties)
+};
+
+
+class LTransitionElementsKind FINAL : public LTemplateInstruction<0, 2, 2> {
+ public:
+  LTransitionElementsKind(LOperand* object,
+                          LOperand* context,
+                          LOperand* temp1,
+                          LOperand* temp2) {
+    inputs_[0] = object;
+    inputs_[1] = context;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* context() { return inputs_[1]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TransitionElementsKind,
+                               "transition-elements-kind")
+  DECLARE_HYDROGEN_ACCESSOR(TransitionElementsKind)
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+
+  Handle<Map> original_map() { return hydrogen()->original_map().handle(); }
+  Handle<Map> transitioned_map() {
+    return hydrogen()->transitioned_map().handle();
+  }
+  ElementsKind from_kind() const { return hydrogen()->from_kind(); }
+  ElementsKind to_kind() const { return hydrogen()->to_kind(); }
+};
+
+
+class LTrapAllocationMemento FINAL : public LTemplateInstruction<0, 1, 2> {
+ public:
+  LTrapAllocationMemento(LOperand* object, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = object;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TrapAllocationMemento, "trap-allocation-memento")
+};
+
+
+class LTruncateDoubleToIntOrSmi FINAL
+    : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LTruncateDoubleToIntOrSmi(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TruncateDoubleToIntOrSmi,
+                               "truncate-double-to-int-or-smi")
+  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
+
+  bool tag_result() { return hydrogen()->representation().IsSmi(); }
+};
+
+
+class LTypeof FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LTypeof(LOperand* context, LOperand* value) {
+    inputs_[0] = context;
+    inputs_[1] = value;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* value() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Typeof, "typeof")
+};
+
+
+class LTypeofIsAndBranch FINAL : public LControlInstruction<1, 2> {
+ public:
+  LTypeofIsAndBranch(LOperand* value, LOperand* temp1, LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(TypeofIsAndBranch, "typeof-is-and-branch")
+  DECLARE_HYDROGEN_ACCESSOR(TypeofIsAndBranch)
+
+  Handle<String> type_literal() const { return hydrogen()->type_literal(); }
+
+  virtual void PrintDataTo(StringStream* stream) OVERRIDE;
+};
+
+
+class LUint32ToDouble FINAL : public LTemplateInstruction<1, 1, 0> {
+ public:
+  explicit LUint32ToDouble(LOperand* value) {
+    inputs_[0] = value;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(Uint32ToDouble, "uint32-to-double")
+};
+
+
+class LCheckMapValue FINAL : public LTemplateInstruction<0, 2, 1> {
+ public:
+  LCheckMapValue(LOperand* value, LOperand* map, LOperand* temp) {
+    inputs_[0] = value;
+    inputs_[1] = map;
+    temps_[0] = temp;
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* map() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(CheckMapValue, "check-map-value")
+};
+
+
+class LLoadFieldByIndex FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LLoadFieldByIndex(LOperand* object, LOperand* index) {
+    inputs_[0] = object;
+    inputs_[1] = index;
+  }
+
+  LOperand* object() { return inputs_[0]; }
+  LOperand* index() { return inputs_[1]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(LoadFieldByIndex, "load-field-by-index")
+};
+
+
+class LStoreFrameContext: public LTemplateInstruction<0, 1, 0> {
+ public:
+  explicit LStoreFrameContext(LOperand* context) {
+    inputs_[0] = context;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(StoreFrameContext, "store-frame-context")
+};
+
+
+class LAllocateBlockContext: public LTemplateInstruction<1, 2, 0> {
+ public:
+  LAllocateBlockContext(LOperand* context, LOperand* function) {
+    inputs_[0] = context;
+    inputs_[1] = function;
+  }
+
+  LOperand* context() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+
+  Handle<ScopeInfo> scope_info() { return hydrogen()->scope_info(); }
+
+  DECLARE_CONCRETE_INSTRUCTION(AllocateBlockContext, "allocate-block-context")
+  DECLARE_HYDROGEN_ACCESSOR(AllocateBlockContext)
+};
+
+
+class LWrapReceiver FINAL : public LTemplateInstruction<1, 2, 0> {
+ public:
+  LWrapReceiver(LOperand* receiver, LOperand* function) {
+    inputs_[0] = receiver;
+    inputs_[1] = function;
+  }
+
+  DECLARE_CONCRETE_INSTRUCTION(WrapReceiver, "wrap-receiver")
+  DECLARE_HYDROGEN_ACCESSOR(WrapReceiver)
+
+  LOperand* receiver() { return inputs_[0]; }
+  LOperand* function() { return inputs_[1]; }
+};
+
+
+class LChunkBuilder;
+class LPlatformChunk FINAL : public LChunk {
+ public:
+  LPlatformChunk(CompilationInfo* info, HGraph* graph)
+      : LChunk(info, graph) { }
+
+  int GetNextSpillIndex();
+  LOperand* GetNextSpillSlot(RegisterKind kind);
+};
+
+
+class LChunkBuilder FINAL : public LChunkBuilderBase {
+ public:
+  LChunkBuilder(CompilationInfo* info, HGraph* graph, LAllocator* allocator)
+      : LChunkBuilderBase(info, graph),
+        current_instruction_(NULL),
+        current_block_(NULL),
+        allocator_(allocator) {}
+
+  // Build the sequence for the graph.
+  LPlatformChunk* Build();
+
+  // Declare methods that deal with the individual node types.
+#define DECLARE_DO(type) LInstruction* Do##type(H##type* node);
+  HYDROGEN_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+  LInstruction* DoDivByPowerOf2I(HDiv* instr);
+  LInstruction* DoDivByConstI(HDiv* instr);
+  LInstruction* DoDivI(HBinaryOperation* instr);
+  LInstruction* DoModByPowerOf2I(HMod* instr);
+  LInstruction* DoModByConstI(HMod* instr);
+  LInstruction* DoModI(HMod* instr);
+  LInstruction* DoFlooringDivByPowerOf2I(HMathFloorOfDiv* instr);
+  LInstruction* DoFlooringDivByConstI(HMathFloorOfDiv* instr);
+  LInstruction* DoFlooringDivI(HMathFloorOfDiv* instr);
+
+  static bool HasMagicNumberForDivision(int32_t divisor);
+
+ private:
+  // Methods for getting operands for Use / Define / Temp.
+  LUnallocated* ToUnallocated(Register reg);
+  LUnallocated* ToUnallocated(DoubleRegister reg);
+
+  // Methods for setting up define-use relationships.
+  MUST_USE_RESULT LOperand* Use(HValue* value, LUnallocated* operand);
+  MUST_USE_RESULT LOperand* UseFixed(HValue* value, Register fixed_register);
+  MUST_USE_RESULT LOperand* UseFixedDouble(HValue* value,
+                                           DoubleRegister fixed_register);
+
+  // A value that is guaranteed to be allocated to a register.
+  // The operand created by UseRegister is guaranteed to be live until the end
+  // of the instruction. This means that register allocator will not reuse its
+  // register for any other operand inside instruction.
+  MUST_USE_RESULT LOperand* UseRegister(HValue* value);
+
+  // The operand created by UseRegisterAndClobber is guaranteed to be live until
+  // the end of the end of the instruction, and it may also be used as a scratch
+  // register by the instruction implementation.
+  //
+  // This behaves identically to ARM's UseTempRegister. However, it is renamed
+  // to discourage its use in ARM64, since in most cases it is better to
+  // allocate a temporary register for the Lithium instruction.
+  MUST_USE_RESULT LOperand* UseRegisterAndClobber(HValue* value);
+
+  // The operand created by UseRegisterAtStart is guaranteed to be live only at
+  // instruction start. The register allocator is free to assign the same
+  // register to some other operand used inside instruction (i.e. temporary or
+  // output).
+  MUST_USE_RESULT LOperand* UseRegisterAtStart(HValue* value);
+
+  // An input operand in a register or a constant operand.
+  MUST_USE_RESULT LOperand* UseRegisterOrConstant(HValue* value);
+  MUST_USE_RESULT LOperand* UseRegisterOrConstantAtStart(HValue* value);
+
+  // A constant operand.
+  MUST_USE_RESULT LConstantOperand* UseConstant(HValue* value);
+
+  // An input operand in register, stack slot or a constant operand.
+  // Will not be moved to a register even if one is freely available.
+  virtual MUST_USE_RESULT LOperand* UseAny(HValue* value);
+
+  // Temporary operand that must be in a register.
+  MUST_USE_RESULT LUnallocated* TempRegister();
+
+  // Temporary operand that must be in a double register.
+  MUST_USE_RESULT LUnallocated* TempDoubleRegister();
+
+  MUST_USE_RESULT LOperand* FixedTemp(Register reg);
+
+  // Temporary operand that must be in a fixed double register.
+  MUST_USE_RESULT LOperand* FixedTemp(DoubleRegister reg);
+
+  // Methods for setting up define-use relationships.
+  // Return the same instruction that they are passed.
+  LInstruction* Define(LTemplateResultInstruction<1>* instr,
+                       LUnallocated* result);
+  LInstruction* DefineAsRegister(LTemplateResultInstruction<1>* instr);
+  LInstruction* DefineAsSpilled(LTemplateResultInstruction<1>* instr,
+                                int index);
+
+  LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
+  LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
+                            Register reg);
+  LInstruction* DefineFixedDouble(LTemplateResultInstruction<1>* instr,
+                                  DoubleRegister reg);
+
+  enum CanDeoptimize { CAN_DEOPTIMIZE_EAGERLY, CANNOT_DEOPTIMIZE_EAGERLY };
+
+  // By default we assume that instruction sequences generated for calls
+  // cannot deoptimize eagerly and we do not attach environment to this
+  // instruction.
+  LInstruction* MarkAsCall(
+      LInstruction* instr,
+      HInstruction* hinstr,
+      CanDeoptimize can_deoptimize = CANNOT_DEOPTIMIZE_EAGERLY);
+
+  LInstruction* AssignPointerMap(LInstruction* instr);
+  LInstruction* AssignEnvironment(LInstruction* instr);
+
+  void VisitInstruction(HInstruction* current);
+  void AddInstruction(LInstruction* instr, HInstruction* current);
+  void DoBasicBlock(HBasicBlock* block);
+
+  int JSShiftAmountFromHConstant(HValue* constant) {
+    return HConstant::cast(constant)->Integer32Value() & 0x1f;
+  }
+  bool LikelyFitsImmField(HInstruction* instr, int imm) {
+    if (instr->IsAdd() || instr->IsSub()) {
+      return Assembler::IsImmAddSub(imm) || Assembler::IsImmAddSub(-imm);
+    } else {
+      DCHECK(instr->IsBitwise());
+      unsigned unused_n, unused_imm_s, unused_imm_r;
+      return Assembler::IsImmLogical(imm, kWRegSizeInBits,
+                                     &unused_n, &unused_imm_s, &unused_imm_r);
+    }
+  }
+
+  // Indicates if a sequence of the form
+  //   lsl x8, x9, #imm
+  //   add x0, x1, x8
+  // can be replaced with:
+  //   add x0, x1, x9 LSL #imm
+  // If this is not possible, the function returns NULL. Otherwise it returns a
+  // pointer to the shift instruction that would be optimized away.
+  HBitwiseBinaryOperation* CanTransformToShiftedOp(HValue* val,
+                                                   HValue** left = NULL);
+  // Checks if all uses of the shift operation can optimize it away.
+  bool ShiftCanBeOptimizedAway(HBitwiseBinaryOperation* shift);
+  // Attempts to merge the binary operation and an eventual previous shift
+  // operation into a single operation. Returns the merged instruction on
+  // success, and NULL otherwise.
+  LInstruction* TryDoOpWithShiftedRightOperand(HBinaryOperation* op);
+  LInstruction* DoShiftedBinaryOp(HBinaryOperation* instr,
+                                  HValue* left,
+                                  HBitwiseBinaryOperation* shift);
+
+  LInstruction* DoShift(Token::Value op, HBitwiseBinaryOperation* instr);
+  LInstruction* DoArithmeticD(Token::Value op,
+                              HArithmeticBinaryOperation* instr);
+  LInstruction* DoArithmeticT(Token::Value op,
+                              HBinaryOperation* instr);
+
+  HInstruction* current_instruction_;
+  HBasicBlock* current_block_;
+  LAllocator* allocator_;
+
+  DISALLOW_COPY_AND_ASSIGN(LChunkBuilder);
+};
+
+#undef DECLARE_HYDROGEN_ACCESSOR
+#undef DECLARE_CONCRETE_INSTRUCTION
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_LITHIUM_ARM64_H_
diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc
new file mode 100644
index 0000000..2998642
--- /dev/null
+++ b/src/arm64/lithium-codegen-arm64.cc
@@ -0,0 +1,6044 @@
+// Copyright 2013 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/v8.h"
+
+#include "src/arm64/lithium-codegen-arm64.h"
+#include "src/arm64/lithium-gap-resolver-arm64.h"
+#include "src/base/bits.h"
+#include "src/code-factory.h"
+#include "src/code-stubs.h"
+#include "src/hydrogen-osr.h"
+#include "src/ic/ic.h"
+#include "src/ic/stub-cache.h"
+
+namespace v8 {
+namespace internal {
+
+
+class SafepointGenerator FINAL : public CallWrapper {
+ public:
+  SafepointGenerator(LCodeGen* codegen,
+                     LPointerMap* pointers,
+                     Safepoint::DeoptMode mode)
+      : codegen_(codegen),
+        pointers_(pointers),
+        deopt_mode_(mode) { }
+  virtual ~SafepointGenerator() { }
+
+  virtual void BeforeCall(int call_size) const { }
+
+  virtual void AfterCall() const {
+    codegen_->RecordSafepoint(pointers_, deopt_mode_);
+  }
+
+ private:
+  LCodeGen* codegen_;
+  LPointerMap* pointers_;
+  Safepoint::DeoptMode deopt_mode_;
+};
+
+
+#define __ masm()->
+
+// Emit code to branch if the given condition holds.
+// The code generated here doesn't modify the flags and they must have
+// been set by some prior instructions.
+//
+// The EmitInverted function simply inverts the condition.
+class BranchOnCondition : public BranchGenerator {
+ public:
+  BranchOnCondition(LCodeGen* codegen, Condition cond)
+    : BranchGenerator(codegen),
+      cond_(cond) { }
+
+  virtual void Emit(Label* label) const {
+    __ B(cond_, label);
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    if (cond_ != al) {
+      __ B(NegateCondition(cond_), label);
+    }
+  }
+
+ private:
+  Condition cond_;
+};
+
+
+// Emit code to compare lhs and rhs and branch if the condition holds.
+// This uses MacroAssembler's CompareAndBranch function so it will handle
+// converting the comparison to Cbz/Cbnz if the right-hand side is 0.
+//
+// EmitInverted still compares the two operands but inverts the condition.
+class CompareAndBranch : public BranchGenerator {
+ public:
+  CompareAndBranch(LCodeGen* codegen,
+                   Condition cond,
+                   const Register& lhs,
+                   const Operand& rhs)
+    : BranchGenerator(codegen),
+      cond_(cond),
+      lhs_(lhs),
+      rhs_(rhs) { }
+
+  virtual void Emit(Label* label) const {
+    __ CompareAndBranch(lhs_, rhs_, cond_, label);
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    __ CompareAndBranch(lhs_, rhs_, NegateCondition(cond_), label);
+  }
+
+ private:
+  Condition cond_;
+  const Register& lhs_;
+  const Operand& rhs_;
+};
+
+
+// Test the input with the given mask and branch if the condition holds.
+// If the condition is 'eq' or 'ne' this will use MacroAssembler's
+// TestAndBranchIfAllClear and TestAndBranchIfAnySet so it will handle the
+// conversion to Tbz/Tbnz when possible.
+class TestAndBranch : public BranchGenerator {
+ public:
+  TestAndBranch(LCodeGen* codegen,
+                Condition cond,
+                const Register& value,
+                uint64_t mask)
+    : BranchGenerator(codegen),
+      cond_(cond),
+      value_(value),
+      mask_(mask) { }
+
+  virtual void Emit(Label* label) const {
+    switch (cond_) {
+      case eq:
+        __ TestAndBranchIfAllClear(value_, mask_, label);
+        break;
+      case ne:
+        __ TestAndBranchIfAnySet(value_, mask_, label);
+        break;
+      default:
+        __ Tst(value_, mask_);
+        __ B(cond_, label);
+    }
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    // The inverse of "all clear" is "any set" and vice versa.
+    switch (cond_) {
+      case eq:
+        __ TestAndBranchIfAnySet(value_, mask_, label);
+        break;
+      case ne:
+        __ TestAndBranchIfAllClear(value_, mask_, label);
+        break;
+      default:
+        __ Tst(value_, mask_);
+        __ B(NegateCondition(cond_), label);
+    }
+  }
+
+ private:
+  Condition cond_;
+  const Register& value_;
+  uint64_t mask_;
+};
+
+
+// Test the input and branch if it is non-zero and not a NaN.
+class BranchIfNonZeroNumber : public BranchGenerator {
+ public:
+  BranchIfNonZeroNumber(LCodeGen* codegen, const FPRegister& value,
+                        const FPRegister& scratch)
+    : BranchGenerator(codegen), value_(value), scratch_(scratch) { }
+
+  virtual void Emit(Label* label) const {
+    __ Fabs(scratch_, value_);
+    // Compare with 0.0. Because scratch_ is positive, the result can be one of
+    // nZCv (equal), nzCv (greater) or nzCV (unordered).
+    __ Fcmp(scratch_, 0.0);
+    __ B(gt, label);
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    __ Fabs(scratch_, value_);
+    __ Fcmp(scratch_, 0.0);
+    __ B(le, label);
+  }
+
+ private:
+  const FPRegister& value_;
+  const FPRegister& scratch_;
+};
+
+
+// Test the input and branch if it is a heap number.
+class BranchIfHeapNumber : public BranchGenerator {
+ public:
+  BranchIfHeapNumber(LCodeGen* codegen, const Register& value)
+      : BranchGenerator(codegen), value_(value) { }
+
+  virtual void Emit(Label* label) const {
+    __ JumpIfHeapNumber(value_, label);
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    __ JumpIfNotHeapNumber(value_, label);
+  }
+
+ private:
+  const Register& value_;
+};
+
+
+// Test the input and branch if it is the specified root value.
+class BranchIfRoot : public BranchGenerator {
+ public:
+  BranchIfRoot(LCodeGen* codegen, const Register& value,
+               Heap::RootListIndex index)
+      : BranchGenerator(codegen), value_(value), index_(index) { }
+
+  virtual void Emit(Label* label) const {
+    __ JumpIfRoot(value_, index_, label);
+  }
+
+  virtual void EmitInverted(Label* label) const {
+    __ JumpIfNotRoot(value_, index_, label);
+  }
+
+ private:
+  const Register& value_;
+  const Heap::RootListIndex index_;
+};
+
+
+void LCodeGen::WriteTranslation(LEnvironment* environment,
+                                Translation* translation) {
+  if (environment == NULL) return;
+
+  // The translation includes one command per value in the environment.
+  int translation_size = environment->translation_size();
+  // The output frame height does not include the parameters.
+  int height = translation_size - environment->parameter_count();
+
+  WriteTranslation(environment->outer(), translation);
+  bool has_closure_id = !info()->closure().is_null() &&
+      !info()->closure().is_identical_to(environment->closure());
+  int closure_id = has_closure_id
+      ? DefineDeoptimizationLiteral(environment->closure())
+      : Translation::kSelfLiteralId;
+
+  switch (environment->frame_type()) {
+    case JS_FUNCTION:
+      translation->BeginJSFrame(environment->ast_id(), closure_id, height);
+      break;
+    case JS_CONSTRUCT:
+      translation->BeginConstructStubFrame(closure_id, translation_size);
+      break;
+    case JS_GETTER:
+      DCHECK(translation_size == 1);
+      DCHECK(height == 0);
+      translation->BeginGetterStubFrame(closure_id);
+      break;
+    case JS_SETTER:
+      DCHECK(translation_size == 2);
+      DCHECK(height == 0);
+      translation->BeginSetterStubFrame(closure_id);
+      break;
+    case STUB:
+      translation->BeginCompiledStubFrame();
+      break;
+    case ARGUMENTS_ADAPTOR:
+      translation->BeginArgumentsAdaptorFrame(closure_id, translation_size);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  int object_index = 0;
+  int dematerialized_index = 0;
+  for (int i = 0; i < translation_size; ++i) {
+    LOperand* value = environment->values()->at(i);
+
+    AddToTranslation(environment,
+                     translation,
+                     value,
+                     environment->HasTaggedValueAt(i),
+                     environment->HasUint32ValueAt(i),
+                     &object_index,
+                     &dematerialized_index);
+  }
+}
+
+
+void LCodeGen::AddToTranslation(LEnvironment* environment,
+                                Translation* translation,
+                                LOperand* op,
+                                bool is_tagged,
+                                bool is_uint32,
+                                int* object_index_pointer,
+                                int* dematerialized_index_pointer) {
+  if (op == LEnvironment::materialization_marker()) {
+    int object_index = (*object_index_pointer)++;
+    if (environment->ObjectIsDuplicateAt(object_index)) {
+      int dupe_of = environment->ObjectDuplicateOfAt(object_index);
+      translation->DuplicateObject(dupe_of);
+      return;
+    }
+    int object_length = environment->ObjectLengthAt(object_index);
+    if (environment->ObjectIsArgumentsAt(object_index)) {
+      translation->BeginArgumentsObject(object_length);
+    } else {
+      translation->BeginCapturedObject(object_length);
+    }
+    int dematerialized_index = *dematerialized_index_pointer;
+    int env_offset = environment->translation_size() + dematerialized_index;
+    *dematerialized_index_pointer += object_length;
+    for (int i = 0; i < object_length; ++i) {
+      LOperand* value = environment->values()->at(env_offset + i);
+      AddToTranslation(environment,
+                       translation,
+                       value,
+                       environment->HasTaggedValueAt(env_offset + i),
+                       environment->HasUint32ValueAt(env_offset + i),
+                       object_index_pointer,
+                       dematerialized_index_pointer);
+    }
+    return;
+  }
+
+  if (op->IsStackSlot()) {
+    if (is_tagged) {
+      translation->StoreStackSlot(op->index());
+    } else if (is_uint32) {
+      translation->StoreUint32StackSlot(op->index());
+    } else {
+      translation->StoreInt32StackSlot(op->index());
+    }
+  } else if (op->IsDoubleStackSlot()) {
+    translation->StoreDoubleStackSlot(op->index());
+  } else if (op->IsRegister()) {
+    Register reg = ToRegister(op);
+    if (is_tagged) {
+      translation->StoreRegister(reg);
+    } else if (is_uint32) {
+      translation->StoreUint32Register(reg);
+    } else {
+      translation->StoreInt32Register(reg);
+    }
+  } else if (op->IsDoubleRegister()) {
+    DoubleRegister reg = ToDoubleRegister(op);
+    translation->StoreDoubleRegister(reg);
+  } else if (op->IsConstantOperand()) {
+    HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
+    int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
+    translation->StoreLiteral(src_index);
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+int LCodeGen::DefineDeoptimizationLiteral(Handle<Object> literal) {
+  int result = deoptimization_literals_.length();
+  for (int i = 0; i < deoptimization_literals_.length(); ++i) {
+    if (deoptimization_literals_[i].is_identical_to(literal)) return i;
+  }
+  deoptimization_literals_.Add(literal, zone());
+  return result;
+}
+
+
+void LCodeGen::RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                                    Safepoint::DeoptMode mode) {
+  environment->set_has_been_used();
+  if (!environment->HasBeenRegistered()) {
+    int frame_count = 0;
+    int jsframe_count = 0;
+    for (LEnvironment* e = environment; e != NULL; e = e->outer()) {
+      ++frame_count;
+      if (e->frame_type() == JS_FUNCTION) {
+        ++jsframe_count;
+      }
+    }
+    Translation translation(&translations_, frame_count, jsframe_count, zone());
+    WriteTranslation(environment, &translation);
+    int deoptimization_index = deoptimizations_.length();
+    int pc_offset = masm()->pc_offset();
+    environment->Register(deoptimization_index,
+                          translation.index(),
+                          (mode == Safepoint::kLazyDeopt) ? pc_offset : -1);
+    deoptimizations_.Add(environment, zone());
+  }
+}
+
+
+void LCodeGen::CallCode(Handle<Code> code,
+                        RelocInfo::Mode mode,
+                        LInstruction* instr) {
+  CallCodeGeneric(code, mode, instr, RECORD_SIMPLE_SAFEPOINT);
+}
+
+
+void LCodeGen::CallCodeGeneric(Handle<Code> code,
+                               RelocInfo::Mode mode,
+                               LInstruction* instr,
+                               SafepointMode safepoint_mode) {
+  DCHECK(instr != NULL);
+
+  Assembler::BlockPoolsScope scope(masm_);
+  __ Call(code, mode);
+  RecordSafepointWithLazyDeopt(instr, safepoint_mode);
+
+  if ((code->kind() == Code::BINARY_OP_IC) ||
+      (code->kind() == Code::COMPARE_IC)) {
+    // Signal that we don't inline smi code before these stubs in the
+    // optimizing code generator.
+    InlineSmiCheckInfo::EmitNotInlined(masm());
+  }
+}
+
+
+void LCodeGen::DoCallFunction(LCallFunction* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->function()).Is(x1));
+  DCHECK(ToRegister(instr->result()).Is(x0));
+
+  int arity = instr->arity();
+  CallFunctionStub stub(isolate(), arity, instr->hydrogen()->function_flags());
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoCallNew(LCallNew* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(ToRegister(instr->constructor()).is(x1));
+
+  __ Mov(x0, instr->arity());
+  // No cell in x2 for construct type feedback in optimized code.
+  __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+
+  CallConstructStub stub(isolate(), NO_CALL_CONSTRUCTOR_FLAGS);
+  CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  after_push_argument_ = false;
+
+  DCHECK(ToRegister(instr->result()).is(x0));
+}
+
+
+void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->constructor()).is(x1));
+
+  __ Mov(x0, Operand(instr->arity()));
+  __ LoadRoot(x2, Heap::kUndefinedValueRootIndex);
+
+  ElementsKind kind = instr->hydrogen()->elements_kind();
+  AllocationSiteOverrideMode override_mode =
+      (AllocationSite::GetMode(kind) == TRACK_ALLOCATION_SITE)
+          ? DISABLE_ALLOCATION_SITES
+          : DONT_OVERRIDE;
+
+  if (instr->arity() == 0) {
+    ArrayNoArgumentConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  } else if (instr->arity() == 1) {
+    Label done;
+    if (IsFastPackedElementsKind(kind)) {
+      Label packed_case;
+
+      // We might need to create a holey array; look at the first argument.
+      __ Peek(x10, 0);
+      __ Cbz(x10, &packed_case);
+
+      ElementsKind holey_kind = GetHoleyElementsKind(kind);
+      ArraySingleArgumentConstructorStub stub(isolate(),
+                                              holey_kind,
+                                              override_mode);
+      CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+      __ B(&done);
+      __ Bind(&packed_case);
+    }
+
+    ArraySingleArgumentConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+    __ Bind(&done);
+  } else {
+    ArrayNArgumentsConstructorStub stub(isolate(), kind, override_mode);
+    CallCode(stub.GetCode(), RelocInfo::CONSTRUCT_CALL, instr);
+  }
+  after_push_argument_ = false;
+
+  DCHECK(ToRegister(instr->result()).is(x0));
+}
+
+
+void LCodeGen::CallRuntime(const Runtime::Function* function,
+                           int num_arguments,
+                           LInstruction* instr,
+                           SaveFPRegsMode save_doubles) {
+  DCHECK(instr != NULL);
+
+  __ CallRuntime(function, num_arguments, save_doubles);
+
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+}
+
+
+void LCodeGen::LoadContextFromDeferred(LOperand* context) {
+  if (context->IsRegister()) {
+    __ Mov(cp, ToRegister(context));
+  } else if (context->IsStackSlot()) {
+    __ Ldr(cp, ToMemOperand(context, kMustUseFramePointer));
+  } else if (context->IsConstantOperand()) {
+    HConstant* constant =
+        chunk_->LookupConstant(LConstantOperand::cast(context));
+    __ LoadHeapObject(cp,
+                      Handle<HeapObject>::cast(constant->handle(isolate())));
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
+                                       int argc,
+                                       LInstruction* instr,
+                                       LOperand* context) {
+  LoadContextFromDeferred(context);
+  __ CallRuntimeSaveDoubles(id);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
+}
+
+
+void LCodeGen::RecordAndWritePosition(int position) {
+  if (position == RelocInfo::kNoPosition) return;
+  masm()->positions_recorder()->RecordPosition(position);
+  masm()->positions_recorder()->WriteRecordedPositions();
+}
+
+
+void LCodeGen::RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                            SafepointMode safepoint_mode) {
+  if (safepoint_mode == RECORD_SIMPLE_SAFEPOINT) {
+    RecordSafepoint(instr->pointer_map(), Safepoint::kLazyDeopt);
+  } else {
+    DCHECK(safepoint_mode == RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), 0, Safepoint::kLazyDeopt);
+  }
+}
+
+
+void LCodeGen::RecordSafepoint(LPointerMap* pointers,
+                               Safepoint::Kind kind,
+                               int arguments,
+                               Safepoint::DeoptMode deopt_mode) {
+  DCHECK(expected_safepoint_kind_ == kind);
+
+  const ZoneList<LOperand*>* operands = pointers->GetNormalizedOperands();
+  Safepoint safepoint = safepoints_.DefineSafepoint(
+      masm(), kind, arguments, deopt_mode);
+
+  for (int i = 0; i < operands->length(); i++) {
+    LOperand* pointer = operands->at(i);
+    if (pointer->IsStackSlot()) {
+      safepoint.DefinePointerSlot(pointer->index(), zone());
+    } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
+      safepoint.DefinePointerRegister(ToRegister(pointer), zone());
+    }
+  }
+
+  if (kind & Safepoint::kWithRegisters) {
+    // Register cp always contains a pointer to the context.
+    safepoint.DefinePointerRegister(cp, zone());
+  }
+}
+
+void LCodeGen::RecordSafepoint(LPointerMap* pointers,
+                               Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kSimple, 0, deopt_mode);
+}
+
+
+void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
+  LPointerMap empty_pointers(zone());
+  RecordSafepoint(&empty_pointers, deopt_mode);
+}
+
+
+void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
+                                            int arguments,
+                                            Safepoint::DeoptMode deopt_mode) {
+  RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments, deopt_mode);
+}
+
+
+bool LCodeGen::GenerateCode() {
+  LPhase phase("Z_Code generation", chunk());
+  DCHECK(is_unused());
+  status_ = GENERATING;
+
+  // Open a frame scope to indicate that there is a frame on the stack.  The
+  // NONE indicates that the scope shouldn't actually generate code to set up
+  // the frame (that is done in GeneratePrologue).
+  FrameScope frame_scope(masm_, StackFrame::NONE);
+
+  return GeneratePrologue() && GenerateBody() && GenerateDeferredCode() &&
+         GenerateJumpTable() && GenerateSafepointTable();
+}
+
+
+void LCodeGen::SaveCallerDoubles() {
+  DCHECK(info()->saves_caller_doubles());
+  DCHECK(NeedsEagerFrame());
+  Comment(";;; Save clobbered callee double registers");
+  BitVector* doubles = chunk()->allocated_double_registers();
+  BitVector::Iterator iterator(doubles);
+  int count = 0;
+  while (!iterator.Done()) {
+    // TODO(all): Is this supposed to save just the callee-saved doubles? It
+    // looks like it's saving all of them.
+    FPRegister value = FPRegister::FromAllocationIndex(iterator.Current());
+    __ Poke(value, count * kDoubleSize);
+    iterator.Advance();
+    count++;
+  }
+}
+
+
+void LCodeGen::RestoreCallerDoubles() {
+  DCHECK(info()->saves_caller_doubles());
+  DCHECK(NeedsEagerFrame());
+  Comment(";;; Restore clobbered callee double registers");
+  BitVector* doubles = chunk()->allocated_double_registers();
+  BitVector::Iterator iterator(doubles);
+  int count = 0;
+  while (!iterator.Done()) {
+    // TODO(all): Is this supposed to restore just the callee-saved doubles? It
+    // looks like it's restoring all of them.
+    FPRegister value = FPRegister::FromAllocationIndex(iterator.Current());
+    __ Peek(value, count * kDoubleSize);
+    iterator.Advance();
+    count++;
+  }
+}
+
+
+bool LCodeGen::GeneratePrologue() {
+  DCHECK(is_generating());
+
+  if (info()->IsOptimizing()) {
+    ProfileEntryHookStub::MaybeCallEntryHook(masm_);
+
+    // TODO(all): Add support for stop_t FLAG in DEBUG mode.
+
+    // Sloppy mode functions and builtins need to replace the receiver with the
+    // global proxy when called as functions (without an explicit receiver
+    // object).
+    if (info_->this_has_uses() &&
+        info_->strict_mode() == SLOPPY &&
+        !info_->is_native()) {
+      Label ok;
+      int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
+      __ Peek(x10, receiver_offset);
+      __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
+
+      __ Ldr(x10, GlobalObjectMemOperand());
+      __ Ldr(x10, FieldMemOperand(x10, GlobalObject::kGlobalProxyOffset));
+      __ Poke(x10, receiver_offset);
+
+      __ Bind(&ok);
+    }
+  }
+
+  DCHECK(__ StackPointer().Is(jssp));
+  info()->set_prologue_offset(masm_->pc_offset());
+  if (NeedsEagerFrame()) {
+    if (info()->IsStub()) {
+      __ StubPrologue();
+    } else {
+      __ Prologue(info()->IsCodePreAgingActive());
+    }
+    frame_is_built_ = true;
+    info_->AddNoFrameRange(0, masm_->pc_offset());
+  }
+
+  // Reserve space for the stack slots needed by the code.
+  int slots = GetStackSlotCount();
+  if (slots > 0) {
+    __ Claim(slots, kPointerSize);
+  }
+
+  if (info()->saves_caller_doubles()) {
+    SaveCallerDoubles();
+  }
+
+  // Allocate a local context if needed.
+  int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
+  if (heap_slots > 0) {
+    Comment(";;; Allocate local context");
+    bool need_write_barrier = true;
+    // Argument to NewContext is the function, which is in x1.
+    if (heap_slots <= FastNewContextStub::kMaximumSlots) {
+      FastNewContextStub stub(isolate(), heap_slots);
+      __ CallStub(&stub);
+      // Result of FastNewContextStub is always in new space.
+      need_write_barrier = false;
+    } else {
+      __ Push(x1);
+      __ CallRuntime(Runtime::kNewFunctionContext, 1);
+    }
+    RecordSafepoint(Safepoint::kNoLazyDeopt);
+    // Context is returned in x0. It replaces the context passed to us. It's
+    // saved in the stack and kept live in cp.
+    __ Mov(cp, x0);
+    __ Str(x0, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    // Copy any necessary parameters into the context.
+    int num_parameters = scope()->num_parameters();
+    for (int i = 0; i < num_parameters; i++) {
+      Variable* var = scope()->parameter(i);
+      if (var->IsContextSlot()) {
+        Register value = x0;
+        Register scratch = x3;
+
+        int parameter_offset = StandardFrameConstants::kCallerSPOffset +
+            (num_parameters - 1 - i) * kPointerSize;
+        // Load parameter from stack.
+        __ Ldr(value, MemOperand(fp, parameter_offset));
+        // Store it in the context.
+        MemOperand target = ContextMemOperand(cp, var->index());
+        __ Str(value, target);
+        // Update the write barrier. This clobbers value and scratch.
+        if (need_write_barrier) {
+          __ RecordWriteContextSlot(cp, target.offset(), value, scratch,
+                                    GetLinkRegisterState(), kSaveFPRegs);
+        } else if (FLAG_debug_code) {
+          Label done;
+          __ JumpIfInNewSpace(cp, &done);
+          __ Abort(kExpectedNewSpaceObject);
+          __ bind(&done);
+        }
+      }
+    }
+    Comment(";;; End allocate local context");
+  }
+
+  // Trace the call.
+  if (FLAG_trace && info()->IsOptimizing()) {
+    // We have not executed any compiled code yet, so cp still holds the
+    // incoming context.
+    __ CallRuntime(Runtime::kTraceEnter, 0);
+  }
+
+  return !is_aborted();
+}
+
+
+void LCodeGen::GenerateOsrPrologue() {
+  // Generate the OSR entry prologue at the first unknown OSR value, or if there
+  // are none, at the OSR entrypoint instruction.
+  if (osr_pc_offset_ >= 0) return;
+
+  osr_pc_offset_ = masm()->pc_offset();
+
+  // Adjust the frame size, subsuming the unoptimized frame into the
+  // optimized frame.
+  int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
+  DCHECK(slots >= 0);
+  __ Claim(slots);
+}
+
+
+void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
+  if (instr->IsCall()) {
+    EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
+  }
+  if (!instr->IsLazyBailout() && !instr->IsGap()) {
+    safepoints_.BumpLastLazySafepointIndex();
+  }
+}
+
+
+bool LCodeGen::GenerateDeferredCode() {
+  DCHECK(is_generating());
+  if (deferred_.length() > 0) {
+    for (int i = 0; !is_aborted() && (i < deferred_.length()); i++) {
+      LDeferredCode* code = deferred_[i];
+
+      HValue* value =
+          instructions_->at(code->instruction_index())->hydrogen_value();
+      RecordAndWritePosition(
+          chunk()->graph()->SourcePositionToScriptPosition(value->position()));
+
+      Comment(";;; <@%d,#%d> "
+              "-------------------- Deferred %s --------------------",
+              code->instruction_index(),
+              code->instr()->hydrogen_value()->id(),
+              code->instr()->Mnemonic());
+
+      __ Bind(code->entry());
+
+      if (NeedsDeferredFrame()) {
+        Comment(";;; Build frame");
+        DCHECK(!frame_is_built_);
+        DCHECK(info()->IsStub());
+        frame_is_built_ = true;
+        __ Push(lr, fp, cp);
+        __ Mov(fp, Smi::FromInt(StackFrame::STUB));
+        __ Push(fp);
+        __ Add(fp, __ StackPointer(),
+               StandardFrameConstants::kFixedFrameSizeFromFp);
+        Comment(";;; Deferred code");
+      }
+
+      code->Generate();
+
+      if (NeedsDeferredFrame()) {
+        Comment(";;; Destroy frame");
+        DCHECK(frame_is_built_);
+        __ Pop(xzr, cp, fp, lr);
+        frame_is_built_ = false;
+      }
+
+      __ B(code->exit());
+    }
+  }
+
+  // Force constant pool emission at the end of the deferred code to make
+  // sure that no constant pools are emitted after deferred code because
+  // deferred code generation is the last step which generates code. The two
+  // following steps will only output data used by crakshaft.
+  masm()->CheckConstPool(true, false);
+
+  return !is_aborted();
+}
+
+
+bool LCodeGen::GenerateJumpTable() {
+  Label needs_frame, restore_caller_doubles, call_deopt_entry;
+
+  if (jump_table_.length() > 0) {
+    Comment(";;; -------------------- Jump table --------------------");
+    Address base = jump_table_[0]->address;
+
+    UseScratchRegisterScope temps(masm());
+    Register entry_offset = temps.AcquireX();
+
+    int length = jump_table_.length();
+    for (int i = 0; i < length; i++) {
+      Deoptimizer::JumpTableEntry* table_entry = jump_table_[i];
+      __ Bind(&table_entry->label);
+
+      Address entry = table_entry->address;
+      DeoptComment(table_entry->reason);
+
+      // Second-level deopt table entries are contiguous and small, so instead
+      // of loading the full, absolute address of each one, load the base
+      // address and add an immediate offset.
+      __ Mov(entry_offset, entry - base);
+
+      // The last entry can fall through into `call_deopt_entry`, avoiding a
+      // branch.
+      bool last_entry = (i + 1) == length;
+
+      if (table_entry->needs_frame) {
+        DCHECK(!info()->saves_caller_doubles());
+        if (!needs_frame.is_bound()) {
+          // This variant of deopt can only be used with stubs. Since we don't
+          // have a function pointer to install in the stack frame that we're
+          // building, install a special marker there instead.
+          DCHECK(info()->IsStub());
+
+          UseScratchRegisterScope temps(masm());
+          Register stub_marker = temps.AcquireX();
+          __ Bind(&needs_frame);
+          __ Mov(stub_marker, Smi::FromInt(StackFrame::STUB));
+          __ Push(lr, fp, cp, stub_marker);
+          __ Add(fp, __ StackPointer(), 2 * kPointerSize);
+          if (!last_entry) __ B(&call_deopt_entry);
+        } else {
+          // Reuse the existing needs_frame code.
+          __ B(&needs_frame);
+        }
+      } else if (info()->saves_caller_doubles()) {
+        DCHECK(info()->IsStub());
+        if (!restore_caller_doubles.is_bound()) {
+          __ Bind(&restore_caller_doubles);
+          RestoreCallerDoubles();
+          if (!last_entry) __ B(&call_deopt_entry);
+        } else {
+          // Reuse the existing restore_caller_doubles code.
+          __ B(&restore_caller_doubles);
+        }
+      } else {
+        // There is nothing special to do, so just continue to the second-level
+        // table.
+        if (!last_entry) __ B(&call_deopt_entry);
+      }
+
+      masm()->CheckConstPool(false, last_entry);
+    }
+
+    // Generate common code for calling the second-level deopt table.
+    Register deopt_entry = temps.AcquireX();
+    __ Bind(&call_deopt_entry);
+    __ Mov(deopt_entry, Operand(reinterpret_cast<uint64_t>(base),
+                                RelocInfo::RUNTIME_ENTRY));
+    __ Add(deopt_entry, deopt_entry, entry_offset);
+    __ Call(deopt_entry);
+  }
+
+  // Force constant pool emission at the end of the deopt jump table to make
+  // sure that no constant pools are emitted after.
+  masm()->CheckConstPool(true, false);
+
+  // The deoptimization jump table is the last part of the instruction
+  // sequence. Mark the generated code as done unless we bailed out.
+  if (!is_aborted()) status_ = DONE;
+  return !is_aborted();
+}
+
+
+bool LCodeGen::GenerateSafepointTable() {
+  DCHECK(is_done());
+  // We do not know how much data will be emitted for the safepoint table, so
+  // force emission of the veneer pool.
+  masm()->CheckVeneerPool(true, true);
+  safepoints_.Emit(masm(), GetStackSlotCount());
+  return !is_aborted();
+}
+
+
+void LCodeGen::FinishCode(Handle<Code> code) {
+  DCHECK(is_done());
+  code->set_stack_slots(GetStackSlotCount());
+  code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
+  if (code->is_optimized_code()) RegisterWeakObjectsInOptimizedCode(code);
+  PopulateDeoptimizationData(code);
+}
+
+
+void LCodeGen::PopulateDeoptimizationData(Handle<Code> code) {
+  int length = deoptimizations_.length();
+  if (length == 0) return;
+
+  Handle<DeoptimizationInputData> data =
+      DeoptimizationInputData::New(isolate(), length, TENURED);
+
+  Handle<ByteArray> translations =
+      translations_.CreateByteArray(isolate()->factory());
+  data->SetTranslationByteArray(*translations);
+  data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+  data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
+  if (info_->IsOptimizing()) {
+    // Reference to shared function info does not change between phases.
+    AllowDeferredHandleDereference allow_handle_dereference;
+    data->SetSharedFunctionInfo(*info_->shared_info());
+  } else {
+    data->SetSharedFunctionInfo(Smi::FromInt(0));
+  }
+
+  Handle<FixedArray> literals =
+      factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
+  { AllowDeferredHandleDereference copy_handles;
+    for (int i = 0; i < deoptimization_literals_.length(); i++) {
+      literals->set(i, *deoptimization_literals_[i]);
+    }
+    data->SetLiteralArray(*literals);
+  }
+
+  data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
+  data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
+
+  // Populate the deoptimization entries.
+  for (int i = 0; i < length; i++) {
+    LEnvironment* env = deoptimizations_[i];
+    data->SetAstId(i, env->ast_id());
+    data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
+    data->SetArgumentsStackHeight(i,
+                                  Smi::FromInt(env->arguments_stack_height()));
+    data->SetPc(i, Smi::FromInt(env->pc_offset()));
+  }
+
+  code->set_deoptimization_data(*data);
+}
+
+
+void LCodeGen::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
+  DCHECK(deoptimization_literals_.length() == 0);
+
+  const ZoneList<Handle<JSFunction> >* inlined_closures =
+      chunk()->inlined_closures();
+
+  for (int i = 0, length = inlined_closures->length(); i < length; i++) {
+    DefineDeoptimizationLiteral(inlined_closures->at(i));
+  }
+
+  inlined_function_count_ = deoptimization_literals_.length();
+}
+
+
+void LCodeGen::DeoptimizeBranch(
+    LInstruction* instr, const char* detail, BranchType branch_type,
+    Register reg, int bit, Deoptimizer::BailoutType* override_bailout_type) {
+  LEnvironment* environment = instr->environment();
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
+  Deoptimizer::BailoutType bailout_type =
+    info()->IsStub() ? Deoptimizer::LAZY : Deoptimizer::EAGER;
+
+  if (override_bailout_type != NULL) {
+    bailout_type = *override_bailout_type;
+  }
+
+  DCHECK(environment->HasBeenRegistered());
+  DCHECK(info()->IsOptimizing() || info()->IsStub());
+  int id = environment->deoptimization_index();
+  Address entry =
+      Deoptimizer::GetDeoptimizationEntry(isolate(), id, bailout_type);
+
+  if (entry == NULL) {
+    Abort(kBailoutWasNotPrepared);
+  }
+
+  if (FLAG_deopt_every_n_times != 0 && !info()->IsStub()) {
+    Label not_zero;
+    ExternalReference count = ExternalReference::stress_deopt_count(isolate());
+
+    __ Push(x0, x1, x2);
+    __ Mrs(x2, NZCV);
+    __ Mov(x0, count);
+    __ Ldr(w1, MemOperand(x0));
+    __ Subs(x1, x1, 1);
+    __ B(gt, &not_zero);
+    __ Mov(w1, FLAG_deopt_every_n_times);
+    __ Str(w1, MemOperand(x0));
+    __ Pop(x2, x1, x0);
+    DCHECK(frame_is_built_);
+    __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+    __ Unreachable();
+
+    __ Bind(&not_zero);
+    __ Str(w1, MemOperand(x0));
+    __ Msr(NZCV, x2);
+    __ Pop(x2, x1, x0);
+  }
+
+  if (info()->ShouldTrapOnDeopt()) {
+    Label dont_trap;
+    __ B(&dont_trap, InvertBranchType(branch_type), reg, bit);
+    __ Debug("trap_on_deopt", __LINE__, BREAK);
+    __ Bind(&dont_trap);
+  }
+
+  Deoptimizer::Reason reason(instr->hydrogen_value()->position().raw(),
+                             instr->Mnemonic(), detail);
+  DCHECK(info()->IsStub() || frame_is_built_);
+  // Go through jump table if we need to build frame, or restore caller doubles.
+  if (branch_type == always &&
+      frame_is_built_ && !info()->saves_caller_doubles()) {
+    DeoptComment(reason);
+    __ Call(entry, RelocInfo::RUNTIME_ENTRY);
+  } else {
+    Deoptimizer::JumpTableEntry* table_entry =
+        new (zone()) Deoptimizer::JumpTableEntry(entry, reason, bailout_type,
+                                                 !frame_is_built_);
+    // We often have several deopts to the same entry, reuse the last
+    // jump entry if this is the case.
+    if (jump_table_.is_empty() ||
+        !table_entry->IsEquivalentTo(*jump_table_.last())) {
+      jump_table_.Add(table_entry, zone());
+    }
+    __ B(&jump_table_.last()->label, branch_type, reg, bit);
+  }
+}
+
+
+void LCodeGen::Deoptimize(LInstruction* instr,
+                          Deoptimizer::BailoutType* override_bailout_type,
+                          const char* detail) {
+  DeoptimizeBranch(instr, detail, always, NoReg, -1, override_bailout_type);
+}
+
+
+void LCodeGen::DeoptimizeIf(Condition cond, LInstruction* instr,
+                            const char* detail) {
+  DeoptimizeBranch(instr, detail, static_cast<BranchType>(cond));
+}
+
+
+void LCodeGen::DeoptimizeIfZero(Register rt, LInstruction* instr,
+                                const char* detail) {
+  DeoptimizeBranch(instr, detail, reg_zero, rt);
+}
+
+
+void LCodeGen::DeoptimizeIfNotZero(Register rt, LInstruction* instr,
+                                   const char* detail) {
+  DeoptimizeBranch(instr, detail, reg_not_zero, rt);
+}
+
+
+void LCodeGen::DeoptimizeIfNegative(Register rt, LInstruction* instr,
+                                    const char* detail) {
+  int sign_bit = rt.Is64Bits() ? kXSignBit : kWSignBit;
+  DeoptimizeIfBitSet(rt, sign_bit, instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfSmi(Register rt, LInstruction* instr,
+                               const char* detail) {
+  DeoptimizeIfBitClear(rt, MaskToBit(kSmiTagMask), instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfNotSmi(Register rt, LInstruction* instr,
+                                  const char* detail) {
+  DeoptimizeIfBitSet(rt, MaskToBit(kSmiTagMask), instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfRoot(Register rt, Heap::RootListIndex index,
+                                LInstruction* instr, const char* detail) {
+  __ CompareRoot(rt, index);
+  DeoptimizeIf(eq, instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfNotRoot(Register rt, Heap::RootListIndex index,
+                                   LInstruction* instr, const char* detail) {
+  __ CompareRoot(rt, index);
+  DeoptimizeIf(ne, instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfMinusZero(DoubleRegister input, LInstruction* instr,
+                                     const char* detail) {
+  __ TestForMinusZero(input);
+  DeoptimizeIf(vs, instr, detail);
+}
+
+
+void LCodeGen::DeoptimizeIfNotHeapNumber(Register object, LInstruction* instr) {
+  __ CompareObjectMap(object, Heap::kHeapNumberMapRootIndex);
+  DeoptimizeIf(ne, instr, "not heap number");
+}
+
+
+void LCodeGen::DeoptimizeIfBitSet(Register rt, int bit, LInstruction* instr,
+                                  const char* detail) {
+  DeoptimizeBranch(instr, detail, reg_bit_set, rt, bit);
+}
+
+
+void LCodeGen::DeoptimizeIfBitClear(Register rt, int bit, LInstruction* instr,
+                                    const char* detail) {
+  DeoptimizeBranch(instr, detail, reg_bit_clear, rt, bit);
+}
+
+
+void LCodeGen::EnsureSpaceForLazyDeopt(int space_needed) {
+  if (!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)) {
+      ptrdiff_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;
+      }
+    }
+  }
+  last_lazy_deopt_pc_ = masm()->pc_offset();
+}
+
+
+Register LCodeGen::ToRegister(LOperand* op) const {
+  // TODO(all): support zero register results, as ToRegister32.
+  DCHECK((op != NULL) && op->IsRegister());
+  return Register::FromAllocationIndex(op->index());
+}
+
+
+Register LCodeGen::ToRegister32(LOperand* op) const {
+  DCHECK(op != NULL);
+  if (op->IsConstantOperand()) {
+    // If this is a constant operand, the result must be the zero register.
+    DCHECK(ToInteger32(LConstantOperand::cast(op)) == 0);
+    return wzr;
+  } else {
+    return ToRegister(op).W();
+  }
+}
+
+
+Smi* LCodeGen::ToSmi(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  return Smi::FromInt(constant->Integer32Value());
+}
+
+
+DoubleRegister LCodeGen::ToDoubleRegister(LOperand* op) const {
+  DCHECK((op != NULL) && op->IsDoubleRegister());
+  return DoubleRegister::FromAllocationIndex(op->index());
+}
+
+
+Operand LCodeGen::ToOperand(LOperand* op) {
+  DCHECK(op != NULL);
+  if (op->IsConstantOperand()) {
+    LConstantOperand* const_op = LConstantOperand::cast(op);
+    HConstant* constant = chunk()->LookupConstant(const_op);
+    Representation r = chunk_->LookupLiteralRepresentation(const_op);
+    if (r.IsSmi()) {
+      DCHECK(constant->HasSmiValue());
+      return Operand(Smi::FromInt(constant->Integer32Value()));
+    } else if (r.IsInteger32()) {
+      DCHECK(constant->HasInteger32Value());
+      return Operand(constant->Integer32Value());
+    } else if (r.IsDouble()) {
+      Abort(kToOperandUnsupportedDoubleImmediate);
+    }
+    DCHECK(r.IsTagged());
+    return Operand(constant->handle(isolate()));
+  } else if (op->IsRegister()) {
+    return Operand(ToRegister(op));
+  } else if (op->IsDoubleRegister()) {
+    Abort(kToOperandIsDoubleRegisterUnimplemented);
+    return Operand(0);
+  }
+  // Stack slots not implemented, use ToMemOperand instead.
+  UNREACHABLE();
+  return Operand(0);
+}
+
+
+Operand LCodeGen::ToOperand32(LOperand* op) {
+  DCHECK(op != NULL);
+  if (op->IsRegister()) {
+    return Operand(ToRegister32(op));
+  } else if (op->IsConstantOperand()) {
+    LConstantOperand* const_op = LConstantOperand::cast(op);
+    HConstant* constant = chunk()->LookupConstant(const_op);
+    Representation r = chunk_->LookupLiteralRepresentation(const_op);
+    if (r.IsInteger32()) {
+      return Operand(constant->Integer32Value());
+    } else {
+      // Other constants not implemented.
+      Abort(kToOperand32UnsupportedImmediate);
+    }
+  }
+  // Other cases are not implemented.
+  UNREACHABLE();
+  return Operand(0);
+}
+
+
+static int64_t ArgumentsOffsetWithoutFrame(int index) {
+  DCHECK(index < 0);
+  return -(index + 1) * kPointerSize;
+}
+
+
+MemOperand LCodeGen::ToMemOperand(LOperand* op, StackMode stack_mode) const {
+  DCHECK(op != NULL);
+  DCHECK(!op->IsRegister());
+  DCHECK(!op->IsDoubleRegister());
+  DCHECK(op->IsStackSlot() || op->IsDoubleStackSlot());
+  if (NeedsEagerFrame()) {
+    int fp_offset = StackSlotOffset(op->index());
+    if (op->index() >= 0) {
+      // Loads and stores have a bigger reach in positive offset than negative.
+      // When the load or the store can't be done in one instruction via fp
+      // (too big negative offset), we try to access via jssp (positive offset).
+      // We can reference a stack slot from jssp only if jssp references the end
+      // of the stack slots. It's not the case when:
+      //  - stack_mode != kCanUseStackPointer: this is the case when a deferred
+      //     code saved the registers.
+      //  - after_push_argument_: arguments has been pushed for a call.
+      //  - inlined_arguments_: inlined arguments have been pushed once. All the
+      //     remainder of the function cannot trust jssp any longer.
+      //  - saves_caller_doubles: some double registers have been pushed, jssp
+      //     references the end of the double registers and not the end of the
+      //     stack slots.
+      // Also, if the offset from fp is small enough to make a load/store in
+      // one instruction, we use a fp access.
+      if ((stack_mode == kCanUseStackPointer) && !after_push_argument_ &&
+          !inlined_arguments_ && !is_int9(fp_offset) &&
+          !info()->saves_caller_doubles()) {
+        int jssp_offset =
+            (GetStackSlotCount() - op->index() - 1) * kPointerSize;
+        return MemOperand(masm()->StackPointer(), jssp_offset);
+      }
+    }
+    return MemOperand(fp, fp_offset);
+  } else {
+    // Retrieve parameter without eager stack-frame relative to the
+    // stack-pointer.
+    return MemOperand(masm()->StackPointer(),
+                      ArgumentsOffsetWithoutFrame(op->index()));
+  }
+}
+
+
+Handle<Object> LCodeGen::ToHandle(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  DCHECK(chunk_->LookupLiteralRepresentation(op).IsSmiOrTagged());
+  return constant->handle(isolate());
+}
+
+
+template <class LI>
+Operand LCodeGen::ToShiftedRightOperand32(LOperand* right, LI* shift_info) {
+  if (shift_info->shift() == NO_SHIFT) {
+    return ToOperand32(right);
+  } else {
+    return Operand(
+        ToRegister32(right),
+        shift_info->shift(),
+        JSShiftAmountFromLConstant(shift_info->shift_amount()));
+  }
+}
+
+
+bool LCodeGen::IsSmi(LConstantOperand* op) const {
+  return chunk_->LookupLiteralRepresentation(op).IsSmi();
+}
+
+
+bool LCodeGen::IsInteger32Constant(LConstantOperand* op) const {
+  return chunk_->LookupLiteralRepresentation(op).IsSmiOrInteger32();
+}
+
+
+int32_t LCodeGen::ToInteger32(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  return constant->Integer32Value();
+}
+
+
+double LCodeGen::ToDouble(LConstantOperand* op) const {
+  HConstant* constant = chunk_->LookupConstant(op);
+  DCHECK(constant->HasDoubleValue());
+  return constant->DoubleValue();
+}
+
+
+Condition LCodeGen::TokenToCondition(Token::Value op, bool is_unsigned) {
+  Condition cond = nv;
+  switch (op) {
+    case Token::EQ:
+    case Token::EQ_STRICT:
+      cond = eq;
+      break;
+    case Token::NE:
+    case Token::NE_STRICT:
+      cond = ne;
+      break;
+    case Token::LT:
+      cond = is_unsigned ? lo : lt;
+      break;
+    case Token::GT:
+      cond = is_unsigned ? hi : gt;
+      break;
+    case Token::LTE:
+      cond = is_unsigned ? ls : le;
+      break;
+    case Token::GTE:
+      cond = is_unsigned ? hs : ge;
+      break;
+    case Token::IN:
+    case Token::INSTANCEOF:
+    default:
+      UNREACHABLE();
+  }
+  return cond;
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitBranchGeneric(InstrType instr,
+                                 const BranchGenerator& branch) {
+  int left_block = instr->TrueDestination(chunk_);
+  int right_block = instr->FalseDestination(chunk_);
+
+  int next_block = GetNextEmittedBlock();
+
+  if (right_block == left_block) {
+    EmitGoto(left_block);
+  } else if (left_block == next_block) {
+    branch.EmitInverted(chunk_->GetAssemblyLabel(right_block));
+  } else {
+    branch.Emit(chunk_->GetAssemblyLabel(left_block));
+    if (right_block != next_block) {
+      __ B(chunk_->GetAssemblyLabel(right_block));
+    }
+  }
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitBranch(InstrType instr, Condition condition) {
+  DCHECK((condition != al) && (condition != nv));
+  BranchOnCondition branch(this, condition);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitCompareAndBranch(InstrType instr,
+                                    Condition condition,
+                                    const Register& lhs,
+                                    const Operand& rhs) {
+  DCHECK((condition != al) && (condition != nv));
+  CompareAndBranch branch(this, condition, lhs, rhs);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitTestAndBranch(InstrType instr,
+                                 Condition condition,
+                                 const Register& value,
+                                 uint64_t mask) {
+  DCHECK((condition != al) && (condition != nv));
+  TestAndBranch branch(this, condition, value, mask);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitBranchIfNonZeroNumber(InstrType instr,
+                                         const FPRegister& value,
+                                         const FPRegister& scratch) {
+  BranchIfNonZeroNumber branch(this, value, scratch);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitBranchIfHeapNumber(InstrType instr,
+                                      const Register& value) {
+  BranchIfHeapNumber branch(this, value);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+template<class InstrType>
+void LCodeGen::EmitBranchIfRoot(InstrType instr,
+                                const Register& value,
+                                Heap::RootListIndex index) {
+  BranchIfRoot branch(this, value, index);
+  EmitBranchGeneric(instr, branch);
+}
+
+
+void LCodeGen::DoGap(LGap* gap) {
+  for (int i = LGap::FIRST_INNER_POSITION;
+       i <= LGap::LAST_INNER_POSITION;
+       i++) {
+    LGap::InnerPosition inner_pos = static_cast<LGap::InnerPosition>(i);
+    LParallelMove* move = gap->GetParallelMove(inner_pos);
+    if (move != NULL) {
+      resolver_.Resolve(move);
+    }
+  }
+}
+
+
+void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
+  Register arguments = ToRegister(instr->arguments());
+  Register result = ToRegister(instr->result());
+
+  // The pointer to the arguments array come from DoArgumentsElements.
+  // It does not point directly to the arguments and there is an offest of
+  // two words that we must take into account when accessing an argument.
+  // Subtracting the index from length accounts for one, so we add one more.
+
+  if (instr->length()->IsConstantOperand() &&
+      instr->index()->IsConstantOperand()) {
+    int index = ToInteger32(LConstantOperand::cast(instr->index()));
+    int length = ToInteger32(LConstantOperand::cast(instr->length()));
+    int offset = ((length - index) + 1) * kPointerSize;
+    __ Ldr(result, MemOperand(arguments, offset));
+  } else if (instr->index()->IsConstantOperand()) {
+    Register length = ToRegister32(instr->length());
+    int index = ToInteger32(LConstantOperand::cast(instr->index()));
+    int loc = index - 1;
+    if (loc != 0) {
+      __ Sub(result.W(), length, loc);
+      __ Ldr(result, MemOperand(arguments, result, UXTW, kPointerSizeLog2));
+    } else {
+      __ Ldr(result, MemOperand(arguments, length, UXTW, kPointerSizeLog2));
+    }
+  } else {
+    Register length = ToRegister32(instr->length());
+    Operand index = ToOperand32(instr->index());
+    __ Sub(result.W(), length, index);
+    __ Add(result.W(), result.W(), 1);
+    __ Ldr(result, MemOperand(arguments, result, UXTW, kPointerSizeLog2));
+  }
+}
+
+
+void LCodeGen::DoAddE(LAddE* instr) {
+  Register result = ToRegister(instr->result());
+  Register left = ToRegister(instr->left());
+  Operand right = (instr->right()->IsConstantOperand())
+      ? ToInteger32(LConstantOperand::cast(instr->right()))
+      : Operand(ToRegister32(instr->right()), SXTW);
+
+  DCHECK(!instr->hydrogen()->CheckFlag(HValue::kCanOverflow));
+  __ Add(result, left, right);
+}
+
+
+void LCodeGen::DoAddI(LAddI* instr) {
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  Register result = ToRegister32(instr->result());
+  Register left = ToRegister32(instr->left());
+  Operand right = ToShiftedRightOperand32(instr->right(), instr);
+
+  if (can_overflow) {
+    __ Adds(result, left, right);
+    DeoptimizeIf(vs, instr);
+  } else {
+    __ Add(result, left, right);
+  }
+}
+
+
+void LCodeGen::DoAddS(LAddS* instr) {
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  Register result = ToRegister(instr->result());
+  Register left = ToRegister(instr->left());
+  Operand right = ToOperand(instr->right());
+  if (can_overflow) {
+    __ Adds(result, left, right);
+    DeoptimizeIf(vs, instr);
+  } else {
+    __ Add(result, left, right);
+  }
+}
+
+
+void LCodeGen::DoAllocate(LAllocate* instr) {
+  class DeferredAllocate: public LDeferredCode {
+   public:
+    DeferredAllocate(LCodeGen* codegen, LAllocate* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredAllocate(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LAllocate* instr_;
+  };
+
+  DeferredAllocate* deferred = new(zone()) DeferredAllocate(this, instr);
+
+  Register result = ToRegister(instr->result());
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  // Allocate memory for the object.
+  AllocationFlags flags = TAG_OBJECT;
+  if (instr->hydrogen()->MustAllocateDoubleAligned()) {
+    flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT);
+  }
+
+  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_POINTER_SPACE);
+  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = static_cast<AllocationFlags>(flags | PRETENURE_OLD_DATA_SPACE);
+  }
+
+  if (instr->size()->IsConstantOperand()) {
+    int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
+    if (size <= Page::kMaxRegularHeapObjectSize) {
+      __ Allocate(size, result, temp1, temp2, deferred->entry(), flags);
+    } else {
+      __ B(deferred->entry());
+    }
+  } else {
+    Register size = ToRegister32(instr->size());
+    __ Sxtw(size.X(), size);
+    __ Allocate(size.X(), result, temp1, temp2, deferred->entry(), flags);
+  }
+
+  __ Bind(deferred->exit());
+
+  if (instr->hydrogen()->MustPrefillWithFiller()) {
+    Register filler_count = temp1;
+    Register filler = temp2;
+    Register untagged_result = ToRegister(instr->temp3());
+
+    if (instr->size()->IsConstantOperand()) {
+      int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
+      __ Mov(filler_count, size / kPointerSize);
+    } else {
+      __ Lsr(filler_count.W(), ToRegister32(instr->size()), kPointerSizeLog2);
+    }
+
+    __ Sub(untagged_result, result, kHeapObjectTag);
+    __ Mov(filler, Operand(isolate()->factory()->one_pointer_filler_map()));
+    __ FillFields(untagged_result, filler_count, filler);
+  } else {
+    DCHECK(instr->temp3() == NULL);
+  }
+}
+
+
+void LCodeGen::DoDeferredAllocate(LAllocate* instr) {
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ Mov(ToRegister(instr->result()), Smi::FromInt(0));
+
+  PushSafepointRegistersScope scope(this);
+  // We're in a SafepointRegistersScope so we can use any scratch registers.
+  Register size = x0;
+  if (instr->size()->IsConstantOperand()) {
+    __ Mov(size, ToSmi(LConstantOperand::cast(instr->size())));
+  } else {
+    __ SmiTag(size, ToRegister32(instr->size()).X());
+  }
+  int flags = AllocateDoubleAlignFlag::encode(
+      instr->hydrogen()->MustAllocateDoubleAligned());
+  if (instr->hydrogen()->IsOldPointerSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsOldDataSpaceAllocation());
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = AllocateTargetSpace::update(flags, OLD_POINTER_SPACE);
+  } else if (instr->hydrogen()->IsOldDataSpaceAllocation()) {
+    DCHECK(!instr->hydrogen()->IsNewSpaceAllocation());
+    flags = AllocateTargetSpace::update(flags, OLD_DATA_SPACE);
+  } else {
+    flags = AllocateTargetSpace::update(flags, NEW_SPACE);
+  }
+  __ Mov(x10, Smi::FromInt(flags));
+  __ Push(size, x10);
+
+  CallRuntimeFromDeferred(
+      Runtime::kAllocateInTargetSpace, 2, instr, instr->context());
+  __ StoreToSafepointRegisterSlot(x0, ToRegister(instr->result()));
+}
+
+
+void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register function = ToRegister(instr->function());
+  Register length = ToRegister32(instr->length());
+
+  Register elements = ToRegister(instr->elements());
+  Register scratch = x5;
+  DCHECK(receiver.Is(x0));  // Used for parameter count.
+  DCHECK(function.Is(x1));  // Required by InvokeFunction.
+  DCHECK(ToRegister(instr->result()).Is(x0));
+  DCHECK(instr->IsMarkedAsCall());
+
+  // Copy the arguments to this function possibly from the
+  // adaptor frame below it.
+  const uint32_t kArgumentsLimit = 1 * KB;
+  __ Cmp(length, kArgumentsLimit);
+  DeoptimizeIf(hi, instr);
+
+  // Push the receiver and use the register to keep the original
+  // number of arguments.
+  __ Push(receiver);
+  Register argc = receiver;
+  receiver = NoReg;
+  __ Sxtw(argc, length);
+  // The arguments are at a one pointer size offset from elements.
+  __ Add(elements, elements, 1 * kPointerSize);
+
+  // Loop through the arguments pushing them onto the execution
+  // stack.
+  Label invoke, loop;
+  // length is a small non-negative integer, due to the test above.
+  __ Cbz(length, &invoke);
+  __ Bind(&loop);
+  __ Ldr(scratch, MemOperand(elements, length, SXTW, kPointerSizeLog2));
+  __ Push(scratch);
+  __ Subs(length, length, 1);
+  __ B(ne, &loop);
+
+  __ Bind(&invoke);
+  DCHECK(instr->HasPointerMap());
+  LPointerMap* pointers = instr->pointer_map();
+  SafepointGenerator safepoint_generator(this, pointers, Safepoint::kLazyDeopt);
+  // The number of arguments is stored in argc (receiver) which is x0, as
+  // expected by InvokeFunction.
+  ParameterCount actual(argc);
+  __ InvokeFunction(function, actual, CALL_FUNCTION, safepoint_generator);
+}
+
+
+void LCodeGen::DoArgumentsElements(LArgumentsElements* instr) {
+  // We push some arguments and they will be pop in an other block. We can't
+  // trust that jssp references the end of the stack slots until the end of
+  // the function.
+  inlined_arguments_ = true;
+  Register result = ToRegister(instr->result());
+
+  if (instr->hydrogen()->from_inlined()) {
+    // When we are inside an inlined function, the arguments are the last things
+    // that have been pushed on the stack. Therefore the arguments array can be
+    // accessed directly from jssp.
+    // However in the normal case, it is accessed via fp but there are two words
+    // on the stack between fp and the arguments (the saved lr and fp) and the
+    // LAccessArgumentsAt implementation take that into account.
+    // In the inlined case we need to subtract the size of 2 words to jssp to
+    // get a pointer which will work well with LAccessArgumentsAt.
+    DCHECK(masm()->StackPointer().Is(jssp));
+    __ Sub(result, jssp, 2 * kPointerSize);
+  } else {
+    DCHECK(instr->temp() != NULL);
+    Register previous_fp = ToRegister(instr->temp());
+
+    __ Ldr(previous_fp,
+           MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+    __ Ldr(result,
+           MemOperand(previous_fp, StandardFrameConstants::kContextOffset));
+    __ Cmp(result, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+    __ Csel(result, fp, previous_fp, ne);
+  }
+}
+
+
+void LCodeGen::DoArgumentsLength(LArgumentsLength* instr) {
+  Register elements = ToRegister(instr->elements());
+  Register result = ToRegister32(instr->result());
+  Label done;
+
+  // If no arguments adaptor frame the number of arguments is fixed.
+  __ Cmp(fp, elements);
+  __ Mov(result, scope()->num_parameters());
+  __ B(eq, &done);
+
+  // Arguments adaptor frame present. Get argument length from there.
+  __ Ldr(result.X(), MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+  __ Ldr(result,
+         UntagSmiMemOperand(result.X(),
+                            ArgumentsAdaptorFrameConstants::kLengthOffset));
+
+  // Argument length is in result register.
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
+  DoubleRegister left = ToDoubleRegister(instr->left());
+  DoubleRegister right = ToDoubleRegister(instr->right());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+
+  switch (instr->op()) {
+    case Token::ADD: __ Fadd(result, left, right); break;
+    case Token::SUB: __ Fsub(result, left, right); break;
+    case Token::MUL: __ Fmul(result, left, right); break;
+    case Token::DIV: __ Fdiv(result, left, right); break;
+    case Token::MOD: {
+      // The ECMA-262 remainder operator is the remainder from a truncating
+      // (round-towards-zero) division. Note that this differs from IEEE-754.
+      //
+      // TODO(jbramley): See if it's possible to do this inline, rather than by
+      // calling a helper function. With frintz (to produce the intermediate
+      // quotient) and fmsub (to calculate the remainder without loss of
+      // precision), it should be possible. However, we would need support for
+      // fdiv in round-towards-zero mode, and the ARM64 simulator doesn't
+      // support that yet.
+      DCHECK(left.Is(d0));
+      DCHECK(right.Is(d1));
+      __ CallCFunction(
+          ExternalReference::mod_two_doubles_operation(isolate()),
+          0, 2);
+      DCHECK(result.Is(d0));
+      break;
+    }
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void LCodeGen::DoArithmeticT(LArithmeticT* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->left()).is(x1));
+  DCHECK(ToRegister(instr->right()).is(x0));
+  DCHECK(ToRegister(instr->result()).is(x0));
+
+  Handle<Code> code =
+      CodeFactory::BinaryOpIC(isolate(), instr->op(), NO_OVERWRITE).code();
+  CallCode(code, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoBitI(LBitI* instr) {
+  Register result = ToRegister32(instr->result());
+  Register left = ToRegister32(instr->left());
+  Operand right = ToShiftedRightOperand32(instr->right(), instr);
+
+  switch (instr->op()) {
+    case Token::BIT_AND: __ And(result, left, right); break;
+    case Token::BIT_OR:  __ Orr(result, left, right); break;
+    case Token::BIT_XOR: __ Eor(result, left, right); break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void LCodeGen::DoBitS(LBitS* instr) {
+  Register result = ToRegister(instr->result());
+  Register left = ToRegister(instr->left());
+  Operand right = ToOperand(instr->right());
+
+  switch (instr->op()) {
+    case Token::BIT_AND: __ And(result, left, right); break;
+    case Token::BIT_OR:  __ Orr(result, left, right); break;
+    case Token::BIT_XOR: __ Eor(result, left, right); break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void LCodeGen::DoBoundsCheck(LBoundsCheck *instr) {
+  Condition cond = instr->hydrogen()->allow_equality() ? hi : hs;
+  DCHECK(instr->hydrogen()->index()->representation().IsInteger32());
+  DCHECK(instr->hydrogen()->length()->representation().IsInteger32());
+  if (instr->index()->IsConstantOperand()) {
+    Operand index = ToOperand32(instr->index());
+    Register length = ToRegister32(instr->length());
+    __ Cmp(length, index);
+    cond = CommuteCondition(cond);
+  } else {
+    Register index = ToRegister32(instr->index());
+    Operand length = ToOperand32(instr->length());
+    __ Cmp(index, length);
+  }
+  if (FLAG_debug_code && instr->hydrogen()->skip_check()) {
+    __ Assert(NegateCondition(cond), kEliminatedBoundsCheckFailed);
+  } else {
+    DeoptimizeIf(cond, instr);
+  }
+}
+
+
+void LCodeGen::DoBranch(LBranch* instr) {
+  Representation r = instr->hydrogen()->value()->representation();
+  Label* true_label = instr->TrueLabel(chunk_);
+  Label* false_label = instr->FalseLabel(chunk_);
+
+  if (r.IsInteger32()) {
+    DCHECK(!info()->IsStub());
+    EmitCompareAndBranch(instr, ne, ToRegister32(instr->value()), 0);
+  } else if (r.IsSmi()) {
+    DCHECK(!info()->IsStub());
+    STATIC_ASSERT(kSmiTag == 0);
+    EmitCompareAndBranch(instr, ne, ToRegister(instr->value()), 0);
+  } else if (r.IsDouble()) {
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    // Test the double value. Zero and NaN are false.
+    EmitBranchIfNonZeroNumber(instr, value, double_scratch());
+  } else {
+    DCHECK(r.IsTagged());
+    Register value = ToRegister(instr->value());
+    HType type = instr->hydrogen()->value()->type();
+
+    if (type.IsBoolean()) {
+      DCHECK(!info()->IsStub());
+      __ CompareRoot(value, Heap::kTrueValueRootIndex);
+      EmitBranch(instr, eq);
+    } else if (type.IsSmi()) {
+      DCHECK(!info()->IsStub());
+      EmitCompareAndBranch(instr, ne, value, Smi::FromInt(0));
+    } else if (type.IsJSArray()) {
+      DCHECK(!info()->IsStub());
+      EmitGoto(instr->TrueDestination(chunk()));
+    } else if (type.IsHeapNumber()) {
+      DCHECK(!info()->IsStub());
+      __ Ldr(double_scratch(), FieldMemOperand(value,
+                                               HeapNumber::kValueOffset));
+      // Test the double value. Zero and NaN are false.
+      EmitBranchIfNonZeroNumber(instr, double_scratch(), double_scratch());
+    } else if (type.IsString()) {
+      DCHECK(!info()->IsStub());
+      Register temp = ToRegister(instr->temp1());
+      __ Ldr(temp, FieldMemOperand(value, String::kLengthOffset));
+      EmitCompareAndBranch(instr, ne, temp, 0);
+    } else {
+      ToBooleanStub::Types expected = instr->hydrogen()->expected_input_types();
+      // Avoid deopts in the case where we've never executed this path before.
+      if (expected.IsEmpty()) expected = ToBooleanStub::Types::Generic();
+
+      if (expected.Contains(ToBooleanStub::UNDEFINED)) {
+        // undefined -> false.
+        __ JumpIfRoot(
+            value, Heap::kUndefinedValueRootIndex, false_label);
+      }
+
+      if (expected.Contains(ToBooleanStub::BOOLEAN)) {
+        // Boolean -> its value.
+        __ JumpIfRoot(
+            value, Heap::kTrueValueRootIndex, true_label);
+        __ JumpIfRoot(
+            value, Heap::kFalseValueRootIndex, false_label);
+      }
+
+      if (expected.Contains(ToBooleanStub::NULL_TYPE)) {
+        // 'null' -> false.
+        __ JumpIfRoot(
+            value, Heap::kNullValueRootIndex, false_label);
+      }
+
+      if (expected.Contains(ToBooleanStub::SMI)) {
+        // Smis: 0 -> false, all other -> true.
+        DCHECK(Smi::FromInt(0) == 0);
+        __ Cbz(value, false_label);
+        __ JumpIfSmi(value, true_label);
+      } else if (expected.NeedsMap()) {
+        // If we need a map later and have a smi, deopt.
+        DeoptimizeIfSmi(value, instr);
+      }
+
+      Register map = NoReg;
+      Register scratch = NoReg;
+
+      if (expected.NeedsMap()) {
+        DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL));
+        map = ToRegister(instr->temp1());
+        scratch = ToRegister(instr->temp2());
+
+        __ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
+
+        if (expected.CanBeUndetectable()) {
+          // Undetectable -> false.
+          __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+          __ TestAndBranchIfAnySet(
+              scratch, 1 << Map::kIsUndetectable, false_label);
+        }
+      }
+
+      if (expected.Contains(ToBooleanStub::SPEC_OBJECT)) {
+        // spec object -> true.
+        __ CompareInstanceType(map, scratch, FIRST_SPEC_OBJECT_TYPE);
+        __ B(ge, true_label);
+      }
+
+      if (expected.Contains(ToBooleanStub::STRING)) {
+        // String value -> false iff empty.
+        Label not_string;
+        __ CompareInstanceType(map, scratch, FIRST_NONSTRING_TYPE);
+        __ B(ge, &not_string);
+        __ Ldr(scratch, FieldMemOperand(value, String::kLengthOffset));
+        __ Cbz(scratch, false_label);
+        __ B(true_label);
+        __ Bind(&not_string);
+      }
+
+      if (expected.Contains(ToBooleanStub::SYMBOL)) {
+        // Symbol value -> true.
+        __ CompareInstanceType(map, scratch, SYMBOL_TYPE);
+        __ B(eq, true_label);
+      }
+
+      if (expected.Contains(ToBooleanStub::HEAP_NUMBER)) {
+        Label not_heap_number;
+        __ JumpIfNotRoot(map, Heap::kHeapNumberMapRootIndex, &not_heap_number);
+
+        __ Ldr(double_scratch(),
+               FieldMemOperand(value, HeapNumber::kValueOffset));
+        __ Fcmp(double_scratch(), 0.0);
+        // If we got a NaN (overflow bit is set), jump to the false branch.
+        __ B(vs, false_label);
+        __ B(eq, false_label);
+        __ B(true_label);
+        __ Bind(&not_heap_number);
+      }
+
+      if (!expected.IsGeneric()) {
+        // We've seen something for the first time -> deopt.
+        // This can only happen if we are not generic already.
+        Deoptimize(instr);
+      }
+    }
+  }
+}
+
+
+void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
+                                 int formal_parameter_count,
+                                 int arity,
+                                 LInstruction* instr,
+                                 Register function_reg) {
+  bool dont_adapt_arguments =
+      formal_parameter_count == SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+  bool can_invoke_directly =
+      dont_adapt_arguments || formal_parameter_count == arity;
+
+  // The function interface relies on the following register assignments.
+  DCHECK(function_reg.Is(x1) || function_reg.IsNone());
+  Register arity_reg = x0;
+
+  LPointerMap* pointers = instr->pointer_map();
+
+  // If necessary, load the function object.
+  if (function_reg.IsNone()) {
+    function_reg = x1;
+    __ LoadObject(function_reg, function);
+  }
+
+  if (FLAG_debug_code) {
+    Label is_not_smi;
+    // Try to confirm that function_reg (x1) is a tagged pointer.
+    __ JumpIfNotSmi(function_reg, &is_not_smi);
+    __ Abort(kExpectedFunctionObject);
+    __ Bind(&is_not_smi);
+  }
+
+  if (can_invoke_directly) {
+    // Change context.
+    __ Ldr(cp, FieldMemOperand(function_reg, JSFunction::kContextOffset));
+
+    // Set the arguments count if adaption is not needed. Assumes that x0 is
+    // available to write to at this point.
+    if (dont_adapt_arguments) {
+      __ Mov(arity_reg, arity);
+    }
+
+    // Invoke function.
+    __ Ldr(x10, FieldMemOperand(function_reg, JSFunction::kCodeEntryOffset));
+    __ Call(x10);
+
+    // Set up deoptimization.
+    RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+  } else {
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+    ParameterCount count(arity);
+    ParameterCount expected(formal_parameter_count);
+    __ InvokeFunction(function_reg, expected, count, CALL_FUNCTION, generator);
+  }
+}
+
+
+void LCodeGen::DoTailCallThroughMegamorphicCache(
+    LTailCallThroughMegamorphicCache* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register name = ToRegister(instr->name());
+  DCHECK(receiver.is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(name.is(LoadDescriptor::NameRegister()));
+  DCHECK(receiver.is(x1));
+  DCHECK(name.is(x2));
+
+  Register scratch = x3;
+  Register extra = x4;
+  Register extra2 = x5;
+  Register extra3 = x6;
+
+  // Important for the tail-call.
+  bool must_teardown_frame = NeedsEagerFrame();
+
+  // The probe will tail call to a handler if found.
+  isolate()->stub_cache()->GenerateProbe(masm(), instr->hydrogen()->flags(),
+                                         must_teardown_frame, receiver, name,
+                                         scratch, extra, extra2, extra3);
+
+  // Tail call to miss if we ended up here.
+  if (must_teardown_frame) __ LeaveFrame(StackFrame::INTERNAL);
+  LoadIC::GenerateMiss(masm());
+}
+
+
+void LCodeGen::DoCallWithDescriptor(LCallWithDescriptor* instr) {
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(ToRegister(instr->result()).Is(x0));
+
+  LPointerMap* pointers = instr->pointer_map();
+  SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+
+  if (instr->target()->IsConstantOperand()) {
+    LConstantOperand* target = LConstantOperand::cast(instr->target());
+    Handle<Code> code = Handle<Code>::cast(ToHandle(target));
+    generator.BeforeCall(__ CallSize(code, RelocInfo::CODE_TARGET));
+    // TODO(all): on ARM we use a call descriptor to specify a storage mode
+    // but on ARM64 we only have one storage mode so it isn't necessary. Check
+    // this understanding is correct.
+    __ Call(code, RelocInfo::CODE_TARGET, TypeFeedbackId::None());
+  } else {
+    DCHECK(instr->target()->IsRegister());
+    Register target = ToRegister(instr->target());
+    generator.BeforeCall(__ CallSize(target));
+    __ Add(target, target, Code::kHeaderSize - kHeapObjectTag);
+    __ Call(target);
+  }
+  generator.AfterCall();
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoCallJSFunction(LCallJSFunction* instr) {
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(ToRegister(instr->function()).is(x1));
+
+  if (instr->hydrogen()->pass_argument_count()) {
+    __ Mov(x0, Operand(instr->arity()));
+  }
+
+  // Change context.
+  __ Ldr(cp, FieldMemOperand(x1, JSFunction::kContextOffset));
+
+  // Load the code entry address
+  __ Ldr(x10, FieldMemOperand(x1, JSFunction::kCodeEntryOffset));
+  __ Call(x10);
+
+  RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
+  CallRuntime(instr->function(), instr->arity(), instr);
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoCallStub(LCallStub* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->result()).is(x0));
+  switch (instr->hydrogen()->major_key()) {
+    case CodeStub::RegExpExec: {
+      RegExpExecStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    case CodeStub::SubString: {
+      SubStringStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    case CodeStub::StringCompare: {
+      StringCompareStub stub(isolate());
+      CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoUnknownOSRValue(LUnknownOSRValue* instr) {
+  GenerateOsrPrologue();
+}
+
+
+void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
+  Register temp = ToRegister(instr->temp());
+  {
+    PushSafepointRegistersScope scope(this);
+    __ Push(object);
+    __ Mov(cp, 0);
+    __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(x0, temp);
+  }
+  DeoptimizeIfSmi(temp, instr);
+}
+
+
+void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
+  class DeferredCheckMaps: public LDeferredCode {
+   public:
+    DeferredCheckMaps(LCodeGen* codegen, LCheckMaps* instr, Register object)
+        : LDeferredCode(codegen), instr_(instr), object_(object) {
+      SetExit(check_maps());
+    }
+    virtual void Generate() {
+      codegen()->DoDeferredInstanceMigration(instr_, object_);
+    }
+    Label* check_maps() { return &check_maps_; }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LCheckMaps* instr_;
+    Label check_maps_;
+    Register object_;
+  };
+
+  if (instr->hydrogen()->IsStabilityCheck()) {
+    const UniqueSet<Map>* maps = instr->hydrogen()->maps();
+    for (int i = 0; i < maps->size(); ++i) {
+      AddStabilityDependency(maps->at(i).handle());
+    }
+    return;
+  }
+
+  Register object = ToRegister(instr->value());
+  Register map_reg = ToRegister(instr->temp());
+
+  __ Ldr(map_reg, FieldMemOperand(object, HeapObject::kMapOffset));
+
+  DeferredCheckMaps* deferred = NULL;
+  if (instr->hydrogen()->HasMigrationTarget()) {
+    deferred = new(zone()) DeferredCheckMaps(this, instr, object);
+    __ Bind(deferred->check_maps());
+  }
+
+  const UniqueSet<Map>* maps = instr->hydrogen()->maps();
+  Label success;
+  for (int i = 0; i < maps->size() - 1; i++) {
+    Handle<Map> map = maps->at(i).handle();
+    __ CompareMap(map_reg, map);
+    __ B(eq, &success);
+  }
+  Handle<Map> map = maps->at(maps->size() - 1).handle();
+  __ CompareMap(map_reg, map);
+
+  // We didn't match a map.
+  if (instr->hydrogen()->HasMigrationTarget()) {
+    __ B(ne, deferred->entry());
+  } else {
+    DeoptimizeIf(ne, instr);
+  }
+
+  __ Bind(&success);
+}
+
+
+void LCodeGen::DoCheckNonSmi(LCheckNonSmi* instr) {
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    DeoptimizeIfSmi(ToRegister(instr->value()), instr);
+  }
+}
+
+
+void LCodeGen::DoCheckSmi(LCheckSmi* instr) {
+  Register value = ToRegister(instr->value());
+  DCHECK(!instr->result() || ToRegister(instr->result()).Is(value));
+  DeoptimizeIfNotSmi(value, instr);
+}
+
+
+void LCodeGen::DoCheckInstanceType(LCheckInstanceType* instr) {
+  Register input = ToRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
+
+  __ Ldr(scratch, FieldMemOperand(input, HeapObject::kMapOffset));
+  __ Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+  if (instr->hydrogen()->is_interval_check()) {
+    InstanceType first, last;
+    instr->hydrogen()->GetCheckInterval(&first, &last);
+
+    __ Cmp(scratch, first);
+    if (first == last) {
+      // If there is only one type in the interval check for equality.
+      DeoptimizeIf(ne, instr);
+    } else if (last == LAST_TYPE) {
+      // We don't need to compare with the higher bound of the interval.
+      DeoptimizeIf(lo, instr);
+    } else {
+      // If we are below the lower bound, set the C flag and clear the Z flag
+      // to force a deopt.
+      __ Ccmp(scratch, last, CFlag, hs);
+      DeoptimizeIf(hi, instr);
+    }
+  } else {
+    uint8_t mask;
+    uint8_t tag;
+    instr->hydrogen()->GetCheckMaskAndTag(&mask, &tag);
+
+    if (base::bits::IsPowerOfTwo32(mask)) {
+      DCHECK((tag == 0) || (tag == mask));
+      if (tag == 0) {
+        DeoptimizeIfBitSet(scratch, MaskToBit(mask), instr);
+      } else {
+        DeoptimizeIfBitClear(scratch, MaskToBit(mask), instr);
+      }
+    } else {
+      if (tag == 0) {
+        __ Tst(scratch, mask);
+      } else {
+        __ And(scratch, scratch, mask);
+        __ Cmp(scratch, tag);
+      }
+      DeoptimizeIf(ne, instr);
+    }
+  }
+}
+
+
+void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->unclamped());
+  Register result = ToRegister32(instr->result());
+  __ ClampDoubleToUint8(result, input, double_scratch());
+}
+
+
+void LCodeGen::DoClampIToUint8(LClampIToUint8* instr) {
+  Register input = ToRegister32(instr->unclamped());
+  Register result = ToRegister32(instr->result());
+  __ ClampInt32ToUint8(result, input);
+}
+
+
+void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
+  Register input = ToRegister(instr->unclamped());
+  Register result = ToRegister32(instr->result());
+  Label done;
+
+  // Both smi and heap number cases are handled.
+  Label is_not_smi;
+  __ JumpIfNotSmi(input, &is_not_smi);
+  __ SmiUntag(result.X(), input);
+  __ ClampInt32ToUint8(result);
+  __ B(&done);
+
+  __ Bind(&is_not_smi);
+
+  // Check for heap number.
+  Label is_heap_number;
+  __ JumpIfHeapNumber(input, &is_heap_number);
+
+  // Check for undefined. Undefined is coverted to zero for clamping conversion.
+  DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+  __ Mov(result, 0);
+  __ B(&done);
+
+  // Heap number case.
+  __ Bind(&is_heap_number);
+  DoubleRegister dbl_scratch = double_scratch();
+  DoubleRegister dbl_scratch2 = ToDoubleRegister(instr->temp1());
+  __ Ldr(dbl_scratch, FieldMemOperand(input, HeapNumber::kValueOffset));
+  __ ClampDoubleToUint8(result, dbl_scratch, dbl_scratch2);
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
+  DoubleRegister value_reg = ToDoubleRegister(instr->value());
+  Register result_reg = ToRegister(instr->result());
+  if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
+    __ Fmov(result_reg, value_reg);
+    __ Lsr(result_reg, result_reg, 32);
+  } else {
+    __ Fmov(result_reg.W(), value_reg.S());
+  }
+}
+
+
+void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
+  Register hi_reg = ToRegister(instr->hi());
+  Register lo_reg = ToRegister(instr->lo());
+  DoubleRegister result_reg = ToDoubleRegister(instr->result());
+
+  // Insert the least significant 32 bits of hi_reg into the most significant
+  // 32 bits of lo_reg, and move to a floating point register.
+  __ Bfi(lo_reg, hi_reg, 32, 32);
+  __ Fmov(result_reg, lo_reg);
+}
+
+
+void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
+  Handle<String> class_name = instr->hydrogen()->class_name();
+  Label* true_label = instr->TrueLabel(chunk_);
+  Label* false_label = instr->FalseLabel(chunk_);
+  Register input = ToRegister(instr->value());
+  Register scratch1 = ToRegister(instr->temp1());
+  Register scratch2 = ToRegister(instr->temp2());
+
+  __ JumpIfSmi(input, false_label);
+
+  Register map = scratch2;
+  if (String::Equals(isolate()->factory()->Function_string(), class_name)) {
+    // Assuming the following assertions, we can use the same compares to test
+    // for both being a function type and being in the object type range.
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  FIRST_SPEC_OBJECT_TYPE + 1);
+    STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
+                  LAST_SPEC_OBJECT_TYPE - 1);
+    STATIC_ASSERT(LAST_SPEC_OBJECT_TYPE == LAST_TYPE);
+
+    // We expect CompareObjectType to load the object instance type in scratch1.
+    __ CompareObjectType(input, map, scratch1, FIRST_SPEC_OBJECT_TYPE);
+    __ B(lt, false_label);
+    __ B(eq, true_label);
+    __ Cmp(scratch1, LAST_SPEC_OBJECT_TYPE);
+    __ B(eq, true_label);
+  } else {
+    __ IsObjectJSObjectType(input, map, scratch1, false_label);
+  }
+
+  // Now we are in the FIRST-LAST_NONCALLABLE_SPEC_OBJECT_TYPE range.
+  // Check if the constructor in the map is a function.
+  __ Ldr(scratch1, FieldMemOperand(map, Map::kConstructorOffset));
+
+  // Objects with a non-function constructor have class 'Object'.
+  if (String::Equals(class_name, isolate()->factory()->Object_string())) {
+    __ JumpIfNotObjectType(
+        scratch1, scratch2, scratch2, JS_FUNCTION_TYPE, true_label);
+  } else {
+    __ JumpIfNotObjectType(
+        scratch1, scratch2, scratch2, JS_FUNCTION_TYPE, false_label);
+  }
+
+  // The constructor function is in scratch1. Get its instance class name.
+  __ Ldr(scratch1,
+         FieldMemOperand(scratch1, JSFunction::kSharedFunctionInfoOffset));
+  __ Ldr(scratch1,
+         FieldMemOperand(scratch1,
+                         SharedFunctionInfo::kInstanceClassNameOffset));
+
+  // The class name we are testing against is internalized since it's a literal.
+  // The name in the constructor is internalized because of the way the context
+  // is booted. This routine isn't expected to work for random API-created
+  // classes and it doesn't have to because you can't access it with natives
+  // syntax. Since both sides are internalized it is sufficient to use an
+  // identity comparison.
+  EmitCompareAndBranch(instr, eq, scratch1, Operand(class_name));
+}
+
+
+void LCodeGen::DoCmpHoleAndBranchD(LCmpHoleAndBranchD* instr) {
+  DCHECK(instr->hydrogen()->representation().IsDouble());
+  FPRegister object = ToDoubleRegister(instr->object());
+  Register temp = ToRegister(instr->temp());
+
+  // If we don't have a NaN, we don't have the hole, so branch now to avoid the
+  // (relatively expensive) hole-NaN check.
+  __ Fcmp(object, object);
+  __ B(vc, instr->FalseLabel(chunk_));
+
+  // We have a NaN, but is it the hole?
+  __ Fmov(temp, object);
+  EmitCompareAndBranch(instr, eq, temp, kHoleNanInt64);
+}
+
+
+void LCodeGen::DoCmpHoleAndBranchT(LCmpHoleAndBranchT* instr) {
+  DCHECK(instr->hydrogen()->representation().IsTagged());
+  Register object = ToRegister(instr->object());
+
+  EmitBranchIfRoot(instr, object, Heap::kTheHoleValueRootIndex);
+}
+
+
+void LCodeGen::DoCmpMapAndBranch(LCmpMapAndBranch* instr) {
+  Register value = ToRegister(instr->value());
+  Register map = ToRegister(instr->temp());
+
+  __ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
+  EmitCompareAndBranch(instr, eq, map, Operand(instr->map()));
+}
+
+
+void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
+  Representation rep = instr->hydrogen()->value()->representation();
+  DCHECK(!rep.IsInteger32());
+  Register scratch = ToRegister(instr->temp());
+
+  if (rep.IsDouble()) {
+    __ JumpIfMinusZero(ToDoubleRegister(instr->value()),
+                       instr->TrueLabel(chunk()));
+  } else {
+    Register value = ToRegister(instr->value());
+    __ JumpIfNotHeapNumber(value, instr->FalseLabel(chunk()), DO_SMI_CHECK);
+    __ Ldr(scratch, FieldMemOperand(value, HeapNumber::kValueOffset));
+    __ JumpIfMinusZero(scratch, instr->TrueLabel(chunk()));
+  }
+  EmitGoto(instr->FalseDestination(chunk()));
+}
+
+
+void LCodeGen::DoCompareNumericAndBranch(LCompareNumericAndBranch* instr) {
+  LOperand* left = instr->left();
+  LOperand* right = instr->right();
+  bool is_unsigned =
+      instr->hydrogen()->left()->CheckFlag(HInstruction::kUint32) ||
+      instr->hydrogen()->right()->CheckFlag(HInstruction::kUint32);
+  Condition cond = TokenToCondition(instr->op(), is_unsigned);
+
+  if (left->IsConstantOperand() && right->IsConstantOperand()) {
+    // We can statically evaluate the comparison.
+    double left_val = ToDouble(LConstantOperand::cast(left));
+    double right_val = ToDouble(LConstantOperand::cast(right));
+    int next_block = EvalComparison(instr->op(), left_val, right_val) ?
+        instr->TrueDestination(chunk_) : instr->FalseDestination(chunk_);
+    EmitGoto(next_block);
+  } else {
+    if (instr->is_double()) {
+      __ Fcmp(ToDoubleRegister(left), ToDoubleRegister(right));
+
+      // If a NaN is involved, i.e. the result is unordered (V set),
+      // jump to false block label.
+      __ B(vs, instr->FalseLabel(chunk_));
+      EmitBranch(instr, cond);
+    } else {
+      if (instr->hydrogen_value()->representation().IsInteger32()) {
+        if (right->IsConstantOperand()) {
+          EmitCompareAndBranch(instr, cond, ToRegister32(left),
+                               ToOperand32(right));
+        } else {
+          // Commute the operands and the condition.
+          EmitCompareAndBranch(instr, CommuteCondition(cond),
+                               ToRegister32(right), ToOperand32(left));
+        }
+      } else {
+        DCHECK(instr->hydrogen_value()->representation().IsSmi());
+        if (right->IsConstantOperand()) {
+          int32_t value = ToInteger32(LConstantOperand::cast(right));
+          EmitCompareAndBranch(instr,
+                               cond,
+                               ToRegister(left),
+                               Operand(Smi::FromInt(value)));
+        } else if (left->IsConstantOperand()) {
+          // Commute the operands and the condition.
+          int32_t value = ToInteger32(LConstantOperand::cast(left));
+          EmitCompareAndBranch(instr,
+                               CommuteCondition(cond),
+                               ToRegister(right),
+                               Operand(Smi::FromInt(value)));
+        } else {
+          EmitCompareAndBranch(instr,
+                               cond,
+                               ToRegister(left),
+                               ToRegister(right));
+        }
+      }
+    }
+  }
+}
+
+
+void LCodeGen::DoCmpObjectEqAndBranch(LCmpObjectEqAndBranch* instr) {
+  Register left = ToRegister(instr->left());
+  Register right = ToRegister(instr->right());
+  EmitCompareAndBranch(instr, eq, left, right);
+}
+
+
+void LCodeGen::DoCmpT(LCmpT* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Token::Value op = instr->op();
+  Condition cond = TokenToCondition(op, false);
+
+  DCHECK(ToRegister(instr->left()).Is(x1));
+  DCHECK(ToRegister(instr->right()).Is(x0));
+  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+  // Signal that we don't inline smi code before this stub.
+  InlineSmiCheckInfo::EmitNotInlined(masm());
+
+  // Return true or false depending on CompareIC result.
+  // This instruction is marked as call. We can clobber any register.
+  DCHECK(instr->IsMarkedAsCall());
+  __ LoadTrueFalseRoots(x1, x2);
+  __ Cmp(x0, 0);
+  __ Csel(ToRegister(instr->result()), x1, x2, cond);
+}
+
+
+void LCodeGen::DoConstantD(LConstantD* instr) {
+  DCHECK(instr->result()->IsDoubleRegister());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  if (instr->value() == 0) {
+    if (copysign(1.0, instr->value()) == 1.0) {
+      __ Fmov(result, fp_zero);
+    } else {
+      __ Fneg(result, fp_zero);
+    }
+  } else {
+    __ Fmov(result, instr->value());
+  }
+}
+
+
+void LCodeGen::DoConstantE(LConstantE* instr) {
+  __ Mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantI(LConstantI* instr) {
+  DCHECK(is_int32(instr->value()));
+  // Cast the value here to ensure that the value isn't sign extended by the
+  // implicit Operand constructor.
+  __ Mov(ToRegister32(instr->result()), static_cast<uint32_t>(instr->value()));
+}
+
+
+void LCodeGen::DoConstantS(LConstantS* instr) {
+  __ Mov(ToRegister(instr->result()), Operand(instr->value()));
+}
+
+
+void LCodeGen::DoConstantT(LConstantT* instr) {
+  Handle<Object> object = instr->value(isolate());
+  AllowDeferredHandleDereference smi_check;
+  __ LoadObject(ToRegister(instr->result()), object);
+}
+
+
+void LCodeGen::DoContext(LContext* instr) {
+  // If there is a non-return use, the context must be moved to a register.
+  Register result = ToRegister(instr->result());
+  if (info()->IsOptimizing()) {
+    __ Ldr(result, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  } else {
+    // If there is no frame, the context must be in cp.
+    DCHECK(result.is(cp));
+  }
+}
+
+
+void LCodeGen::DoCheckValue(LCheckValue* instr) {
+  Register reg = ToRegister(instr->value());
+  Handle<HeapObject> object = instr->hydrogen()->object().handle();
+  AllowDeferredHandleDereference smi_check;
+  if (isolate()->heap()->InNewSpace(*object)) {
+    UseScratchRegisterScope temps(masm());
+    Register temp = temps.AcquireX();
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
+    __ Mov(temp, Operand(Handle<Object>(cell)));
+    __ Ldr(temp, FieldMemOperand(temp, Cell::kValueOffset));
+    __ Cmp(reg, temp);
+  } else {
+    __ Cmp(reg, Operand(object));
+  }
+  DeoptimizeIf(ne, instr);
+}
+
+
+void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
+  last_lazy_deopt_pc_ = masm()->pc_offset();
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+}
+
+
+void LCodeGen::DoDateField(LDateField* instr) {
+  Register object = ToRegister(instr->date());
+  Register result = ToRegister(instr->result());
+  Register temp1 = x10;
+  Register temp2 = x11;
+  Smi* index = instr->index();
+  Label runtime, done;
+
+  DCHECK(object.is(result) && object.Is(x0));
+  DCHECK(instr->IsMarkedAsCall());
+
+  DeoptimizeIfSmi(object, instr);
+  __ CompareObjectType(object, temp1, temp1, JS_DATE_TYPE);
+  DeoptimizeIf(ne, instr);
+
+  if (index->value() == 0) {
+    __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
+  } else {
+    if (index->value() < JSDate::kFirstUncachedField) {
+      ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
+      __ Mov(temp1, Operand(stamp));
+      __ Ldr(temp1, MemOperand(temp1));
+      __ Ldr(temp2, FieldMemOperand(object, JSDate::kCacheStampOffset));
+      __ Cmp(temp1, temp2);
+      __ B(ne, &runtime);
+      __ Ldr(result, FieldMemOperand(object, JSDate::kValueOffset +
+                                             kPointerSize * index->value()));
+      __ B(&done);
+    }
+
+    __ Bind(&runtime);
+    __ Mov(x1, Operand(index));
+    __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
+  }
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
+  Deoptimizer::BailoutType type = instr->hydrogen()->type();
+  // TODO(danno): Stubs expect all deopts to be lazy for historical reasons (the
+  // needed return address), even though the implementation of LAZY and EAGER is
+  // now identical. When LAZY is eventually completely folded into EAGER, remove
+  // the special case below.
+  if (info()->IsStub() && (type == Deoptimizer::EAGER)) {
+    type = Deoptimizer::LAZY;
+  }
+
+  Deoptimize(instr, &type, instr->hydrogen()->reason());
+}
+
+
+void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister32(instr->result());
+  DCHECK(divisor == kMinInt || base::bits::IsPowerOfTwo32(Abs(divisor)));
+  DCHECK(!result.is(dividend));
+
+  // Check for (0 / -x) that will produce negative zero.
+  HDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    DeoptimizeIfZero(dividend, instr);
+  }
+  // Check for (kMinInt / -1).
+  if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
+    // Test dividend for kMinInt by subtracting one (cmp) and checking for
+    // overflow.
+    __ Cmp(dividend, 1);
+    DeoptimizeIf(vs, instr);
+  }
+  // Deoptimize if remainder will not be 0.
+  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
+      divisor != 1 && divisor != -1) {
+    int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
+    __ Tst(dividend, mask);
+    DeoptimizeIf(ne, instr);
+  }
+
+  if (divisor == -1) {  // Nice shortcut, not needed for correctness.
+    __ Neg(result, dividend);
+    return;
+  }
+  int32_t shift = WhichPowerOf2Abs(divisor);
+  if (shift == 0) {
+    __ Mov(result, dividend);
+  } else if (shift == 1) {
+    __ Add(result, dividend, Operand(dividend, LSR, 31));
+  } else {
+    __ Mov(result, Operand(dividend, ASR, 31));
+    __ Add(result, dividend, Operand(result, LSR, 32 - shift));
+  }
+  if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
+  if (divisor < 0) __ Neg(result, result);
+}
+
+
+void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister32(instr->result());
+  DCHECK(!AreAliased(dividend, result));
+
+  if (divisor == 0) {
+    Deoptimize(instr);
+    return;
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  HDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    DeoptimizeIfZero(dividend, instr);
+  }
+
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  if (divisor < 0) __ Neg(result, result);
+
+  if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
+    Register temp = ToRegister32(instr->temp());
+    DCHECK(!AreAliased(dividend, result, temp));
+    __ Sxtw(dividend.X(), dividend);
+    __ Mov(temp, divisor);
+    __ Smsubl(temp.X(), result, temp, dividend.X());
+    DeoptimizeIfNotZero(temp, instr);
+  }
+}
+
+
+// TODO(svenpanne) Refactor this to avoid code duplication with DoFlooringDivI.
+void LCodeGen::DoDivI(LDivI* instr) {
+  HBinaryOperation* hdiv = instr->hydrogen();
+  Register dividend = ToRegister32(instr->dividend());
+  Register divisor = ToRegister32(instr->divisor());
+  Register result = ToRegister32(instr->result());
+
+  // Issue the division first, and then check for any deopt cases whilst the
+  // result is computed.
+  __ Sdiv(result, dividend, divisor);
+
+  if (hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
+    DCHECK_EQ(NULL, instr->temp());
+    return;
+  }
+
+  // Check for x / 0.
+  if (hdiv->CheckFlag(HValue::kCanBeDivByZero)) {
+    DeoptimizeIfZero(divisor, instr);
+  }
+
+  // Check for (0 / -x) as that will produce negative zero.
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    __ Cmp(divisor, 0);
+
+    // If the divisor < 0 (mi), compare the dividend, and deopt if it is
+    // zero, ie. zero dividend with negative divisor deopts.
+    // If the divisor >= 0 (pl, the opposite of mi) set the flags to
+    // condition ne, so we don't deopt, ie. positive divisor doesn't deopt.
+    __ Ccmp(dividend, 0, NoFlag, mi);
+    DeoptimizeIf(eq, instr);
+  }
+
+  // Check for (kMinInt / -1).
+  if (hdiv->CheckFlag(HValue::kCanOverflow)) {
+    // Test dividend for kMinInt by subtracting one (cmp) and checking for
+    // overflow.
+    __ Cmp(dividend, 1);
+    // If overflow is set, ie. dividend = kMinInt, compare the divisor with
+    // -1. If overflow is clear, set the flags for condition ne, as the
+    // dividend isn't -1, and thus we shouldn't deopt.
+    __ Ccmp(divisor, -1, NoFlag, vs);
+    DeoptimizeIf(eq, instr);
+  }
+
+  // Compute remainder and deopt if it's not zero.
+  Register remainder = ToRegister32(instr->temp());
+  __ Msub(remainder, result, divisor, dividend);
+  DeoptimizeIfNotZero(remainder, instr);
+}
+
+
+void LCodeGen::DoDoubleToIntOrSmi(LDoubleToIntOrSmi* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister32(instr->result());
+
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    DeoptimizeIfMinusZero(input, instr);
+  }
+
+  __ TryRepresentDoubleAsInt32(result, input, double_scratch());
+  DeoptimizeIf(ne, instr);
+
+  if (instr->tag_result()) {
+    __ SmiTag(result.X());
+  }
+}
+
+
+void LCodeGen::DoDrop(LDrop* instr) {
+  __ Drop(instr->count());
+}
+
+
+void LCodeGen::DoDummy(LDummy* instr) {
+  // Nothing to see here, move on!
+}
+
+
+void LCodeGen::DoDummyUse(LDummyUse* instr) {
+  // Nothing to see here, move on!
+}
+
+
+void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  // FunctionLiteral instruction is marked as call, we can trash any register.
+  DCHECK(instr->IsMarkedAsCall());
+
+  // Use the fast case closure allocation code that allocates in new
+  // space for nested functions that don't need literals cloning.
+  bool pretenure = instr->hydrogen()->pretenure();
+  if (!pretenure && instr->hydrogen()->has_no_literals()) {
+    FastNewClosureStub stub(isolate(), instr->hydrogen()->strict_mode(),
+                            instr->hydrogen()->kind());
+    __ Mov(x2, Operand(instr->hydrogen()->shared_info()));
+    CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+  } else {
+    __ Mov(x2, Operand(instr->hydrogen()->shared_info()));
+    __ Mov(x1, Operand(pretenure ? factory()->true_value()
+                                 : factory()->false_value()));
+    __ Push(cp, x2, x1);
+    CallRuntime(Runtime::kNewClosure, 3, instr);
+  }
+}
+
+
+void LCodeGen::DoForInCacheArray(LForInCacheArray* instr) {
+  Register map = ToRegister(instr->map());
+  Register result = ToRegister(instr->result());
+  Label load_cache, done;
+
+  __ EnumLengthUntagged(result, map);
+  __ Cbnz(result, &load_cache);
+
+  __ Mov(result, Operand(isolate()->factory()->empty_fixed_array()));
+  __ B(&done);
+
+  __ Bind(&load_cache);
+  __ LoadInstanceDescriptors(map, result);
+  __ Ldr(result, FieldMemOperand(result, DescriptorArray::kEnumCacheOffset));
+  __ Ldr(result, FieldMemOperand(result, FixedArray::SizeFor(instr->idx())));
+  DeoptimizeIfZero(result, instr);
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoForInPrepareMap(LForInPrepareMap* instr) {
+  Register object = ToRegister(instr->object());
+  Register null_value = x5;
+
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(object.Is(x0));
+
+  DeoptimizeIfRoot(object, Heap::kUndefinedValueRootIndex, instr);
+
+  __ LoadRoot(null_value, Heap::kNullValueRootIndex);
+  __ Cmp(object, null_value);
+  DeoptimizeIf(eq, instr);
+
+  DeoptimizeIfSmi(object, instr);
+
+  STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
+  __ CompareObjectType(object, x1, x1, LAST_JS_PROXY_TYPE);
+  DeoptimizeIf(le, instr);
+
+  Label use_cache, call_runtime;
+  __ CheckEnumCache(object, null_value, x1, x2, x3, x4, &call_runtime);
+
+  __ Ldr(object, FieldMemOperand(object, HeapObject::kMapOffset));
+  __ B(&use_cache);
+
+  // Get the set of properties to enumerate.
+  __ Bind(&call_runtime);
+  __ Push(object);
+  CallRuntime(Runtime::kGetPropertyNamesFast, 1, instr);
+
+  __ Ldr(x1, FieldMemOperand(object, HeapObject::kMapOffset));
+  DeoptimizeIfNotRoot(x1, Heap::kMetaMapRootIndex, instr);
+
+  __ Bind(&use_cache);
+}
+
+
+void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+
+  __ AssertString(input);
+
+  // Assert that we can use a W register load to get the hash.
+  DCHECK((String::kHashShift + String::kArrayIndexValueBits) < kWRegSizeInBits);
+  __ Ldr(result.W(), FieldMemOperand(input, String::kHashFieldOffset));
+  __ IndexFromHash(result, result);
+}
+
+
+void LCodeGen::EmitGoto(int block) {
+  // Do not emit jump if we are emitting a goto to the next block.
+  if (!IsNextEmittedBlock(block)) {
+    __ B(chunk_->GetAssemblyLabel(LookupDestination(block)));
+  }
+}
+
+
+void LCodeGen::DoGoto(LGoto* instr) {
+  EmitGoto(instr->block_id());
+}
+
+
+void LCodeGen::DoHasCachedArrayIndexAndBranch(
+    LHasCachedArrayIndexAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register temp = ToRegister32(instr->temp());
+
+  // Assert that the cache status bits fit in a W register.
+  DCHECK(is_uint32(String::kContainsCachedArrayIndexMask));
+  __ Ldr(temp, FieldMemOperand(input, String::kHashFieldOffset));
+  __ Tst(temp, String::kContainsCachedArrayIndexMask);
+  EmitBranch(instr, eq);
+}
+
+
+// HHasInstanceTypeAndBranch instruction is built with an interval of type
+// to test but is only used in very restricted ways. The only possible kinds
+// of intervals are:
+//  - [ FIRST_TYPE, instr->to() ]
+//  - [ instr->form(), LAST_TYPE ]
+//  - instr->from() == instr->to()
+//
+// These kinds of intervals can be check with only one compare instruction
+// providing the correct value and test condition are used.
+//
+// TestType() will return the value to use in the compare instruction and
+// BranchCondition() will return the condition to use depending on the kind
+// of interval actually specified in the instruction.
+static InstanceType TestType(HHasInstanceTypeAndBranch* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == FIRST_TYPE) return to;
+  DCHECK((from == to) || (to == LAST_TYPE));
+  return from;
+}
+
+
+// See comment above TestType function for what this function does.
+static Condition BranchCondition(HHasInstanceTypeAndBranch* instr) {
+  InstanceType from = instr->from();
+  InstanceType to = instr->to();
+  if (from == to) return eq;
+  if (to == LAST_TYPE) return hs;
+  if (from == FIRST_TYPE) return ls;
+  UNREACHABLE();
+  return eq;
+}
+
+
+void LCodeGen::DoHasInstanceTypeAndBranch(LHasInstanceTypeAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
+
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    __ JumpIfSmi(input, instr->FalseLabel(chunk_));
+  }
+  __ CompareObjectType(input, scratch, scratch, TestType(instr->hydrogen()));
+  EmitBranch(instr, BranchCondition(instr->hydrogen()));
+}
+
+
+void LCodeGen::DoInnerAllocatedObject(LInnerAllocatedObject* instr) {
+  Register result = ToRegister(instr->result());
+  Register base = ToRegister(instr->base_object());
+  if (instr->offset()->IsConstantOperand()) {
+    __ Add(result, base, ToOperand32(instr->offset()));
+  } else {
+    __ Add(result, base, Operand(ToRegister32(instr->offset()), SXTW));
+  }
+}
+
+
+void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  // Assert that the arguments are in the registers expected by InstanceofStub.
+  DCHECK(ToRegister(instr->left()).Is(InstanceofStub::left()));
+  DCHECK(ToRegister(instr->right()).Is(InstanceofStub::right()));
+
+  InstanceofStub stub(isolate(), InstanceofStub::kArgsInRegisters);
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+
+  // InstanceofStub returns a result in x0:
+  //   0     => not an instance
+  //   smi 1 => instance.
+  __ Cmp(x0, 0);
+  __ LoadTrueFalseRoots(x0, x1);
+  __ Csel(x0, x0, x1, eq);
+}
+
+
+void LCodeGen::DoInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
+  class DeferredInstanceOfKnownGlobal: public LDeferredCode {
+   public:
+    DeferredInstanceOfKnownGlobal(LCodeGen* codegen,
+                                  LInstanceOfKnownGlobal* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredInstanceOfKnownGlobal(instr_);
+    }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LInstanceOfKnownGlobal* instr_;
+  };
+
+  DeferredInstanceOfKnownGlobal* deferred =
+      new(zone()) DeferredInstanceOfKnownGlobal(this, instr);
+
+  Label map_check, return_false, cache_miss, done;
+  Register object = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  // x4 is expected in the associated deferred code and stub.
+  Register map_check_site = x4;
+  Register map = x5;
+
+  // This instruction is marked as call. We can clobber any register.
+  DCHECK(instr->IsMarkedAsCall());
+
+  // We must take into account that object is in x11.
+  DCHECK(object.Is(x11));
+  Register scratch = x10;
+
+  // A Smi is not instance of anything.
+  __ JumpIfSmi(object, &return_false);
+
+  // This is the inlined call site instanceof cache. The two occurences of the
+  // hole value will be patched to the last map/result pair generated by the
+  // instanceof stub.
+  __ Ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  {
+    // Below we use Factory::the_hole_value() on purpose instead of loading from
+    // the root array to force relocation and later be able to patch with a
+    // custom value.
+    InstructionAccurateScope scope(masm(), 5);
+    __ bind(&map_check);
+    // Will be patched with the cached map.
+    Handle<Cell> cell = factory()->NewCell(factory()->the_hole_value());
+    __ ldr(scratch, Immediate(Handle<Object>(cell)));
+    __ ldr(scratch, FieldMemOperand(scratch, PropertyCell::kValueOffset));
+    __ cmp(map, scratch);
+    __ b(&cache_miss, ne);
+    // The address of this instruction is computed relative to the map check
+    // above, so check the size of the code generated.
+    DCHECK(masm()->InstructionsGeneratedSince(&map_check) == 4);
+    // Will be patched with the cached result.
+    __ ldr(result, Immediate(factory()->the_hole_value()));
+  }
+  __ B(&done);
+
+  // The inlined call site cache did not match.
+  // Check null and string before calling the deferred code.
+  __ Bind(&cache_miss);
+  // Compute the address of the map check. It must not be clobbered until the
+  // InstanceOfStub has used it.
+  __ Adr(map_check_site, &map_check);
+  // Null is not instance of anything.
+  __ JumpIfRoot(object, Heap::kNullValueRootIndex, &return_false);
+
+  // String values are not instances of anything.
+  // Return false if the object is a string. Otherwise, jump to the deferred
+  // code.
+  // Note that we can't jump directly to deferred code from
+  // IsObjectJSStringType, because it uses tbz for the jump and the deferred
+  // code can be out of range.
+  __ IsObjectJSStringType(object, scratch, NULL, &return_false);
+  __ B(deferred->entry());
+
+  __ Bind(&return_false);
+  __ LoadRoot(result, Heap::kFalseValueRootIndex);
+
+  // Here result is either true or false.
+  __ Bind(deferred->exit());
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr) {
+  Register result = ToRegister(instr->result());
+  DCHECK(result.Is(x0));  // InstanceofStub returns its result in x0.
+  InstanceofStub::Flags flags = InstanceofStub::kNoFlags;
+  flags = static_cast<InstanceofStub::Flags>(
+      flags | InstanceofStub::kArgsInRegisters);
+  flags = static_cast<InstanceofStub::Flags>(
+      flags | InstanceofStub::kReturnTrueFalseObject);
+  flags = static_cast<InstanceofStub::Flags>(
+      flags | InstanceofStub::kCallSiteInlineCheck);
+
+  PushSafepointRegistersScope scope(this);
+  LoadContextFromDeferred(instr->context());
+
+  // Prepare InstanceofStub arguments.
+  DCHECK(ToRegister(instr->value()).Is(InstanceofStub::left()));
+  __ LoadObject(InstanceofStub::right(), instr->function());
+
+  InstanceofStub stub(isolate(), flags);
+  CallCodeGeneric(stub.GetCode(),
+                  RelocInfo::CODE_TARGET,
+                  instr,
+                  RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  LEnvironment* env = instr->GetDeferredLazyDeoptimizationEnvironment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+
+  // Put the result value into the result register slot.
+  __ StoreToSafepointRegisterSlot(result, result);
+}
+
+
+void LCodeGen::DoInstructionGap(LInstructionGap* instr) {
+  DoGap(instr);
+}
+
+
+void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
+  Register value = ToRegister32(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  __ Scvtf(result, value);
+}
+
+
+void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  // The function is required to be in x1.
+  DCHECK(ToRegister(instr->function()).is(x1));
+  DCHECK(instr->HasPointerMap());
+
+  Handle<JSFunction> known_function = instr->hydrogen()->known_function();
+  if (known_function.is_null()) {
+    LPointerMap* pointers = instr->pointer_map();
+    SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
+    ParameterCount count(instr->arity());
+    __ InvokeFunction(x1, count, CALL_FUNCTION, generator);
+  } else {
+    CallKnownFunction(known_function,
+                      instr->hydrogen()->formal_parameter_count(),
+                      instr->arity(),
+                      instr,
+                      x1);
+  }
+  after_push_argument_ = false;
+}
+
+
+void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  // Get the frame pointer for the calling frame.
+  __ Ldr(temp1, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
+
+  // Skip the arguments adaptor frame if it exists.
+  Label check_frame_marker;
+  __ Ldr(temp2, MemOperand(temp1, StandardFrameConstants::kContextOffset));
+  __ Cmp(temp2, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
+  __ B(ne, &check_frame_marker);
+  __ Ldr(temp1, MemOperand(temp1, StandardFrameConstants::kCallerFPOffset));
+
+  // Check the marker in the calling frame.
+  __ Bind(&check_frame_marker);
+  __ Ldr(temp1, MemOperand(temp1, StandardFrameConstants::kMarkerOffset));
+
+  EmitCompareAndBranch(
+      instr, eq, temp1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
+}
+
+
+void LCodeGen::DoIsObjectAndBranch(LIsObjectAndBranch* instr) {
+  Label* is_object = instr->TrueLabel(chunk_);
+  Label* is_not_object = instr->FalseLabel(chunk_);
+  Register value = ToRegister(instr->value());
+  Register map = ToRegister(instr->temp1());
+  Register scratch = ToRegister(instr->temp2());
+
+  __ JumpIfSmi(value, is_not_object);
+  __ JumpIfRoot(value, Heap::kNullValueRootIndex, is_object);
+
+  __ Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
+
+  // Check for undetectable objects.
+  __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+  __ TestAndBranchIfAnySet(scratch, 1 << Map::kIsUndetectable, is_not_object);
+
+  // Check that instance type is in object type range.
+  __ IsInstanceJSObjectType(map, scratch, NULL);
+  // Flags have been updated by IsInstanceJSObjectType. We can now test the
+  // flags for "le" condition to check if the object's type is a valid
+  // JS object type.
+  EmitBranch(instr, le);
+}
+
+
+Condition LCodeGen::EmitIsString(Register input,
+                                 Register temp1,
+                                 Label* is_not_string,
+                                 SmiCheck check_needed = INLINE_SMI_CHECK) {
+  if (check_needed == INLINE_SMI_CHECK) {
+    __ JumpIfSmi(input, is_not_string);
+  }
+  __ CompareObjectType(input, temp1, temp1, FIRST_NONSTRING_TYPE);
+
+  return lt;
+}
+
+
+void LCodeGen::DoIsStringAndBranch(LIsStringAndBranch* instr) {
+  Register val = ToRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
+
+  SmiCheck check_needed =
+      instr->hydrogen()->value()->type().IsHeapObject()
+          ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
+  Condition true_cond =
+      EmitIsString(val, scratch, instr->FalseLabel(chunk_), check_needed);
+
+  EmitBranch(instr, true_cond);
+}
+
+
+void LCodeGen::DoIsSmiAndBranch(LIsSmiAndBranch* instr) {
+  Register value = ToRegister(instr->value());
+  STATIC_ASSERT(kSmiTag == 0);
+  EmitTestAndBranch(instr, eq, value, kSmiTagMask);
+}
+
+
+void LCodeGen::DoIsUndetectableAndBranch(LIsUndetectableAndBranch* instr) {
+  Register input = ToRegister(instr->value());
+  Register temp = ToRegister(instr->temp());
+
+  if (!instr->hydrogen()->value()->type().IsHeapObject()) {
+    __ JumpIfSmi(input, instr->FalseLabel(chunk_));
+  }
+  __ Ldr(temp, FieldMemOperand(input, HeapObject::kMapOffset));
+  __ Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
+
+  EmitTestAndBranch(instr, ne, temp, 1 << Map::kIsUndetectable);
+}
+
+
+static const char* LabelType(LLabel* label) {
+  if (label->is_loop_header()) return " (loop header)";
+  if (label->is_osr_entry()) return " (OSR entry)";
+  return "";
+}
+
+
+void LCodeGen::DoLabel(LLabel* label) {
+  Comment(";;; <@%d,#%d> -------------------- B%d%s --------------------",
+          current_instruction_,
+          label->hydrogen_value()->id(),
+          label->block_id(),
+          LabelType(label));
+
+  __ Bind(label->label());
+  current_block_ = label->block_id();
+  DoGap(label);
+}
+
+
+void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
+  Register context = ToRegister(instr->context());
+  Register result = ToRegister(instr->result());
+  __ Ldr(result, ContextMemOperand(context, instr->slot_index()));
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+    } else {
+      Label not_the_hole;
+      __ JumpIfNotRoot(result, Heap::kTheHoleValueRootIndex, &not_the_hole);
+      __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
+      __ Bind(&not_the_hole);
+    }
+  }
+}
+
+
+void LCodeGen::DoLoadFunctionPrototype(LLoadFunctionPrototype* instr) {
+  Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
+  Register temp = ToRegister(instr->temp());
+
+  // Get the prototype or initial map from the function.
+  __ Ldr(result, FieldMemOperand(function,
+                                 JSFunction::kPrototypeOrInitialMapOffset));
+
+  // Check that the function has a prototype or an initial map.
+  DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  __ CompareObjectType(result, temp, temp, MAP_TYPE);
+  __ B(ne, &done);
+
+  // Get the prototype from the initial map.
+  __ Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
+
+  // All done.
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoLoadGlobalCell(LLoadGlobalCell* instr) {
+  Register result = ToRegister(instr->result());
+  __ Mov(result, Operand(Handle<Object>(instr->hydrogen()->cell().handle())));
+  __ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+  }
+}
+
+
+template <class T>
+void LCodeGen::EmitVectorLoadICRegisters(T* instr) {
+  DCHECK(FLAG_vector_ics);
+  Register vector = ToRegister(instr->temp_vector());
+  DCHECK(vector.is(VectorLoadICDescriptor::VectorRegister()));
+  __ Mov(vector, instr->hydrogen()->feedback_vector());
+  // No need to allocate this register.
+  DCHECK(VectorLoadICDescriptor::SlotRegister().is(x0));
+  __ Mov(VectorLoadICDescriptor::SlotRegister(),
+         Smi::FromInt(instr->hydrogen()->slot()));
+}
+
+
+void LCodeGen::DoLoadGlobalGeneric(LLoadGlobalGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->global_object())
+             .is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->result()).Is(x0));
+  __ Mov(LoadDescriptor::NameRegister(), Operand(instr->name()));
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadGlobalGeneric>(instr);
+  }
+  ContextualMode mode = instr->for_typeof() ? NOT_CONTEXTUAL : CONTEXTUAL;
+  Handle<Code> ic = CodeFactory::LoadIC(isolate(), mode).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+MemOperand LCodeGen::PrepareKeyedExternalArrayOperand(
+    Register key,
+    Register base,
+    Register scratch,
+    bool key_is_smi,
+    bool key_is_constant,
+    int constant_key,
+    ElementsKind elements_kind,
+    int base_offset) {
+  int element_size_shift = ElementsKindToShiftSize(elements_kind);
+
+  if (key_is_constant) {
+    int key_offset = constant_key << element_size_shift;
+    return MemOperand(base, key_offset + base_offset);
+  }
+
+  if (key_is_smi) {
+    __ Add(scratch, base, Operand::UntagSmiAndScale(key, element_size_shift));
+    return MemOperand(scratch, base_offset);
+  }
+
+  if (base_offset == 0) {
+    return MemOperand(base, key, SXTW, element_size_shift);
+  }
+
+  DCHECK(!AreAliased(scratch, key));
+  __ Add(scratch, base, base_offset);
+  return MemOperand(scratch, key, SXTW, element_size_shift);
+}
+
+
+void LCodeGen::DoLoadKeyedExternal(LLoadKeyedExternal* instr) {
+  Register ext_ptr = ToRegister(instr->elements());
+  Register scratch;
+  ElementsKind elements_kind = instr->elements_kind();
+
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  Register key = no_reg;
+  int constant_key = 0;
+  if (key_is_constant) {
+    DCHECK(instr->temp() == NULL);
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xf0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    scratch = ToRegister(instr->temp());
+    key = ToRegister(instr->key());
+  }
+
+  MemOperand mem_op =
+      PrepareKeyedExternalArrayOperand(key, ext_ptr, scratch, key_is_smi,
+                                       key_is_constant, constant_key,
+                                       elements_kind,
+                                       instr->base_offset());
+
+  if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) ||
+      (elements_kind == FLOAT32_ELEMENTS)) {
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    __ Ldr(result.S(), mem_op);
+    __ Fcvt(result, result.S());
+  } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) ||
+             (elements_kind == FLOAT64_ELEMENTS)) {
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    __ Ldr(result, mem_op);
+  } else {
+    Register result = ToRegister(instr->result());
+
+    switch (elements_kind) {
+      case EXTERNAL_INT8_ELEMENTS:
+      case INT8_ELEMENTS:
+        __ Ldrsb(result, mem_op);
+        break;
+      case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+      case EXTERNAL_UINT8_ELEMENTS:
+      case UINT8_ELEMENTS:
+      case UINT8_CLAMPED_ELEMENTS:
+        __ Ldrb(result, mem_op);
+        break;
+      case EXTERNAL_INT16_ELEMENTS:
+      case INT16_ELEMENTS:
+        __ Ldrsh(result, mem_op);
+        break;
+      case EXTERNAL_UINT16_ELEMENTS:
+      case UINT16_ELEMENTS:
+        __ Ldrh(result, mem_op);
+        break;
+      case EXTERNAL_INT32_ELEMENTS:
+      case INT32_ELEMENTS:
+        __ Ldrsw(result, mem_op);
+        break;
+      case EXTERNAL_UINT32_ELEMENTS:
+      case UINT32_ELEMENTS:
+        __ Ldr(result.W(), mem_op);
+        if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) {
+          // Deopt if value > 0x80000000.
+          __ Tst(result, 0xFFFFFFFF80000000);
+          DeoptimizeIf(ne, instr);
+        }
+        break;
+      case FLOAT32_ELEMENTS:
+      case FLOAT64_ELEMENTS:
+      case EXTERNAL_FLOAT32_ELEMENTS:
+      case EXTERNAL_FLOAT64_ELEMENTS:
+      case FAST_HOLEY_DOUBLE_ELEMENTS:
+      case FAST_HOLEY_ELEMENTS:
+      case FAST_HOLEY_SMI_ELEMENTS:
+      case FAST_DOUBLE_ELEMENTS:
+      case FAST_ELEMENTS:
+      case FAST_SMI_ELEMENTS:
+      case DICTIONARY_ELEMENTS:
+      case SLOPPY_ARGUMENTS_ELEMENTS:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+MemOperand LCodeGen::PrepareKeyedArrayOperand(Register base,
+                                              Register elements,
+                                              Register key,
+                                              bool key_is_tagged,
+                                              ElementsKind elements_kind,
+                                              Representation representation,
+                                              int base_offset) {
+  STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
+  STATIC_ASSERT(kSmiTag == 0);
+  int element_size_shift = ElementsKindToShiftSize(elements_kind);
+
+  // Even though the HLoad/StoreKeyed instructions force the input
+  // representation for the key to be an integer, the input gets replaced during
+  // bounds check elimination with the index argument to the bounds check, which
+  // can be tagged, so that case must be handled here, too.
+  if (key_is_tagged) {
+    __ Add(base, elements, Operand::UntagSmiAndScale(key, element_size_shift));
+    if (representation.IsInteger32()) {
+      DCHECK(elements_kind == FAST_SMI_ELEMENTS);
+      // Read or write only the smi payload in the case of fast smi arrays.
+      return UntagSmiMemOperand(base, base_offset);
+    } else {
+      return MemOperand(base, base_offset);
+    }
+  } else {
+    // Sign extend key because it could be a 32-bit negative value or contain
+    // garbage in the top 32-bits. The address computation happens in 64-bit.
+    DCHECK((element_size_shift >= 0) && (element_size_shift <= 4));
+    if (representation.IsInteger32()) {
+      DCHECK(elements_kind == FAST_SMI_ELEMENTS);
+      // Read or write only the smi payload in the case of fast smi arrays.
+      __ Add(base, elements, Operand(key, SXTW, element_size_shift));
+      return UntagSmiMemOperand(base, base_offset);
+    } else {
+      __ Add(base, elements, base_offset);
+      return MemOperand(base, key, SXTW, element_size_shift);
+    }
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedFixedDouble(LLoadKeyedFixedDouble* instr) {
+  Register elements = ToRegister(instr->elements());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  MemOperand mem_op;
+
+  if (instr->key()->IsConstantOperand()) {
+    DCHECK(instr->hydrogen()->RequiresHoleCheck() ||
+           (instr->temp() == NULL));
+
+    int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xf0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+    int offset = instr->base_offset() + constant_key * kDoubleSize;
+    mem_op = MemOperand(elements, offset);
+  } else {
+    Register load_base = ToRegister(instr->temp());
+    Register key = ToRegister(instr->key());
+    bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
+    mem_op = PrepareKeyedArrayOperand(load_base, elements, key, key_is_tagged,
+                                      instr->hydrogen()->elements_kind(),
+                                      instr->hydrogen()->representation(),
+                                      instr->base_offset());
+  }
+
+  __ Ldr(result, mem_op);
+
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    Register scratch = ToRegister(instr->temp());
+    // Detect the hole NaN by adding one to the integer representation of the
+    // result, and checking for overflow.
+    STATIC_ASSERT(kHoleNanInt64 == 0x7fffffffffffffff);
+    __ Ldr(scratch, mem_op);
+    __ Cmn(scratch, 1);
+    DeoptimizeIf(vs, instr);
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedFixed(LLoadKeyedFixed* instr) {
+  Register elements = ToRegister(instr->elements());
+  Register result = ToRegister(instr->result());
+  MemOperand mem_op;
+
+  Representation representation = instr->hydrogen()->representation();
+  if (instr->key()->IsConstantOperand()) {
+    DCHECK(instr->temp() == NULL);
+    LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
+    int offset = instr->base_offset() +
+        ToInteger32(const_operand) * kPointerSize;
+    if (representation.IsInteger32()) {
+      DCHECK(instr->hydrogen()->elements_kind() == FAST_SMI_ELEMENTS);
+      STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
+      STATIC_ASSERT(kSmiTag == 0);
+      mem_op = UntagSmiMemOperand(elements, offset);
+    } else {
+      mem_op = MemOperand(elements, offset);
+    }
+  } else {
+    Register load_base = ToRegister(instr->temp());
+    Register key = ToRegister(instr->key());
+    bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
+
+    mem_op = PrepareKeyedArrayOperand(load_base, elements, key, key_is_tagged,
+                                      instr->hydrogen()->elements_kind(),
+                                      representation, instr->base_offset());
+  }
+
+  __ Load(result, mem_op, representation);
+
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    if (IsFastSmiElementsKind(instr->hydrogen()->elements_kind())) {
+      DeoptimizeIfNotSmi(result, instr);
+    } else {
+      DeoptimizeIfRoot(result, Heap::kTheHoleValueRootIndex, instr);
+    }
+  }
+}
+
+
+void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->key()).is(LoadDescriptor::NameRegister()));
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadKeyedGeneric>(instr);
+  }
+
+  Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+
+  DCHECK(ToRegister(instr->result()).Is(x0));
+}
+
+
+void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
+  HObjectAccess access = instr->hydrogen()->access();
+  int offset = access.offset();
+  Register object = ToRegister(instr->object());
+
+  if (access.IsExternalMemory()) {
+    Register result = ToRegister(instr->result());
+    __ Load(result, MemOperand(object, offset), access.representation());
+    return;
+  }
+
+  if (instr->hydrogen()->representation().IsDouble()) {
+    FPRegister result = ToDoubleRegister(instr->result());
+    __ Ldr(result, FieldMemOperand(object, offset));
+    return;
+  }
+
+  Register result = ToRegister(instr->result());
+  Register source;
+  if (access.IsInobject()) {
+    source = object;
+  } else {
+    // Load the properties array, using result as a scratch register.
+    __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+    source = result;
+  }
+
+  if (access.representation().IsSmi() &&
+      instr->hydrogen()->representation().IsInteger32()) {
+    // Read int value directly from upper half of the smi.
+    STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
+    STATIC_ASSERT(kSmiTag == 0);
+    __ Load(result, UntagSmiFieldMemOperand(source, offset),
+            Representation::Integer32());
+  } else {
+    __ Load(result, FieldMemOperand(source, offset), access.representation());
+  }
+}
+
+
+void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  // LoadIC expects name and receiver in registers.
+  DCHECK(ToRegister(instr->object()).is(LoadDescriptor::ReceiverRegister()));
+  __ Mov(LoadDescriptor::NameRegister(), Operand(instr->name()));
+  if (FLAG_vector_ics) {
+    EmitVectorLoadICRegisters<LLoadNamedGeneric>(instr);
+  }
+
+  Handle<Code> ic = CodeFactory::LoadIC(isolate(), NOT_CONTEXTUAL).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+
+  DCHECK(ToRegister(instr->result()).is(x0));
+}
+
+
+void LCodeGen::DoLoadRoot(LLoadRoot* instr) {
+  Register result = ToRegister(instr->result());
+  __ LoadRoot(result, instr->index());
+}
+
+
+void LCodeGen::DoMapEnumLength(LMapEnumLength* instr) {
+  Register result = ToRegister(instr->result());
+  Register map = ToRegister(instr->value());
+  __ EnumLengthSmi(result, map);
+}
+
+
+void LCodeGen::DoMathAbs(LMathAbs* instr) {
+  Representation r = instr->hydrogen()->value()->representation();
+  if (r.IsDouble()) {
+    DoubleRegister input = ToDoubleRegister(instr->value());
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    __ Fabs(result, input);
+  } else if (r.IsSmi() || r.IsInteger32()) {
+    Register input = r.IsSmi() ? ToRegister(instr->value())
+                               : ToRegister32(instr->value());
+    Register result = r.IsSmi() ? ToRegister(instr->result())
+                                : ToRegister32(instr->result());
+    __ Abs(result, input);
+    DeoptimizeIf(vs, instr);
+  }
+}
+
+
+void LCodeGen::DoDeferredMathAbsTagged(LMathAbsTagged* instr,
+                                       Label* exit,
+                                       Label* allocation_entry) {
+  // Handle the tricky cases of MathAbsTagged:
+  //  - HeapNumber inputs.
+  //    - Negative inputs produce a positive result, so a new HeapNumber is
+  //      allocated to hold it.
+  //    - Positive inputs are returned as-is, since there is no need to allocate
+  //      a new HeapNumber for the result.
+  //  - The (smi) input -0x80000000, produces +0x80000000, which does not fit
+  //    a smi. In this case, the inline code sets the result and jumps directly
+  //    to the allocation_entry label.
+  DCHECK(instr->context() != NULL);
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Register input = ToRegister(instr->value());
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+  Register result_bits = ToRegister(instr->temp3());
+  Register result = ToRegister(instr->result());
+
+  Label runtime_allocation;
+
+  // Deoptimize if the input is not a HeapNumber.
+  DeoptimizeIfNotHeapNumber(input, instr);
+
+  // If the argument is positive, we can return it as-is, without any need to
+  // allocate a new HeapNumber for the result. We have to do this in integer
+  // registers (rather than with fabs) because we need to be able to distinguish
+  // the two zeroes.
+  __ Ldr(result_bits, FieldMemOperand(input, HeapNumber::kValueOffset));
+  __ Mov(result, input);
+  __ Tbz(result_bits, kXSignBit, exit);
+
+  // Calculate abs(input) by clearing the sign bit.
+  __ Bic(result_bits, result_bits, kXSignMask);
+
+  // Allocate a new HeapNumber to hold the result.
+  //  result_bits   The bit representation of the (double) result.
+  __ Bind(allocation_entry);
+  __ AllocateHeapNumber(result, &runtime_allocation, temp1, temp2);
+  // The inline (non-deferred) code will store result_bits into result.
+  __ B(exit);
+
+  __ Bind(&runtime_allocation);
+  if (FLAG_debug_code) {
+    // Because result is in the pointer map, we need to make sure it has a valid
+    // tagged value before we call the runtime. We speculatively set it to the
+    // input (for abs(+x)) or to a smi (for abs(-SMI_MIN)), so it should already
+    // be valid.
+    Label result_ok;
+    Register input = ToRegister(instr->value());
+    __ JumpIfSmi(result, &result_ok);
+    __ Cmp(input, result);
+    __ Assert(eq, kUnexpectedValue);
+    __ Bind(&result_ok);
+  }
+
+  { PushSafepointRegistersScope scope(this);
+    CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr,
+                            instr->context());
+    __ StoreToSafepointRegisterSlot(x0, result);
+  }
+  // The inline (non-deferred) code will store result_bits into result.
+}
+
+
+void LCodeGen::DoMathAbsTagged(LMathAbsTagged* instr) {
+  // Class for deferred case.
+  class DeferredMathAbsTagged: public LDeferredCode {
+   public:
+    DeferredMathAbsTagged(LCodeGen* codegen, LMathAbsTagged* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredMathAbsTagged(instr_, exit(),
+                                         allocation_entry());
+    }
+    virtual LInstruction* instr() { return instr_; }
+    Label* allocation_entry() { return &allocation; }
+   private:
+    LMathAbsTagged* instr_;
+    Label allocation;
+  };
+
+  // TODO(jbramley): The early-exit mechanism would skip the new frame handling
+  // in GenerateDeferredCode. Tidy this up.
+  DCHECK(!NeedsDeferredFrame());
+
+  DeferredMathAbsTagged* deferred =
+      new(zone()) DeferredMathAbsTagged(this, instr);
+
+  DCHECK(instr->hydrogen()->value()->representation().IsTagged() ||
+         instr->hydrogen()->value()->representation().IsSmi());
+  Register input = ToRegister(instr->value());
+  Register result_bits = ToRegister(instr->temp3());
+  Register result = ToRegister(instr->result());
+  Label done;
+
+  // Handle smis inline.
+  // We can treat smis as 64-bit integers, since the (low-order) tag bits will
+  // never get set by the negation. This is therefore the same as the Integer32
+  // case in DoMathAbs, except that it operates on 64-bit values.
+  STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0));
+
+  __ JumpIfNotSmi(input, deferred->entry());
+
+  __ Abs(result, input, NULL, &done);
+
+  // The result is the magnitude (abs) of the smallest value a smi can
+  // represent, encoded as a double.
+  __ Mov(result_bits, double_to_rawbits(0x80000000));
+  __ B(deferred->allocation_entry());
+
+  __ Bind(deferred->exit());
+  __ Str(result_bits, FieldMemOperand(result, HeapNumber::kValueOffset));
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoMathExp(LMathExp* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  DoubleRegister double_temp1 = ToDoubleRegister(instr->double_temp1());
+  DoubleRegister double_temp2 = double_scratch();
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+  Register temp3 = ToRegister(instr->temp3());
+
+  MathExpGenerator::EmitMathExp(masm(), input, result,
+                                double_temp1, double_temp2,
+                                temp1, temp2, temp3);
+}
+
+
+void LCodeGen::DoMathFloorD(LMathFloorD* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+
+  __ Frintm(result, input);
+}
+
+
+void LCodeGen::DoMathFloorI(LMathFloorI* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister(instr->result());
+
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    DeoptimizeIfMinusZero(input, instr);
+  }
+
+  __ Fcvtms(result, input);
+
+  // Check that the result fits into a 32-bit integer.
+  //  - The result did not overflow.
+  __ Cmp(result, Operand(result, SXTW));
+  //  - The input was not NaN.
+  __ Fccmp(input, input, NoFlag, eq);
+  DeoptimizeIf(ne, instr);
+}
+
+
+void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  Register result = ToRegister32(instr->result());
+  int32_t divisor = instr->divisor();
+
+  // If the divisor is 1, return the dividend.
+  if (divisor == 1) {
+    __ Mov(result, dividend, kDiscardForSameWReg);
+    return;
+  }
+
+  // If the divisor is positive, things are easy: There can be no deopts and we
+  // can simply do an arithmetic right shift.
+  int32_t shift = WhichPowerOf2Abs(divisor);
+  if (divisor > 1) {
+    __ Mov(result, Operand(dividend, ASR, shift));
+    return;
+  }
+
+  // If the divisor is negative, we have to negate and handle edge cases.
+  __ Negs(result, dividend);
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    DeoptimizeIf(eq, instr);
+  }
+
+  // Dividing by -1 is basically negation, unless we overflow.
+  if (divisor == -1) {
+    if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
+      DeoptimizeIf(vs, instr);
+    }
+    return;
+  }
+
+  // If the negation could not overflow, simply shifting is OK.
+  if (!instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
+    __ Mov(result, Operand(dividend, ASR, shift));
+    return;
+  }
+
+  __ Asr(result, result, shift);
+  __ Csel(result, result, kMinInt / divisor, vc);
+}
+
+
+void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister32(instr->result());
+  DCHECK(!AreAliased(dividend, result));
+
+  if (divisor == 0) {
+    Deoptimize(instr);
+    return;
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  HMathFloorOfDiv* hdiv = instr->hydrogen();
+  if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
+    DeoptimizeIfZero(dividend, instr);
+  }
+
+  // Easy case: We need no dynamic check for the dividend and the flooring
+  // division is the same as the truncating division.
+  if ((divisor > 0 && !hdiv->CheckFlag(HValue::kLeftCanBeNegative)) ||
+      (divisor < 0 && !hdiv->CheckFlag(HValue::kLeftCanBePositive))) {
+    __ TruncatingDiv(result, dividend, Abs(divisor));
+    if (divisor < 0) __ Neg(result, result);
+    return;
+  }
+
+  // In the general case we may need to adjust before and after the truncating
+  // division to get a flooring division.
+  Register temp = ToRegister32(instr->temp());
+  DCHECK(!AreAliased(temp, dividend, result));
+  Label needs_adjustment, done;
+  __ Cmp(dividend, 0);
+  __ B(divisor > 0 ? lt : gt, &needs_adjustment);
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  if (divisor < 0) __ Neg(result, result);
+  __ B(&done);
+  __ Bind(&needs_adjustment);
+  __ Add(temp, dividend, Operand(divisor > 0 ? 1 : -1));
+  __ TruncatingDiv(result, temp, Abs(divisor));
+  if (divisor < 0) __ Neg(result, result);
+  __ Sub(result, result, Operand(1));
+  __ Bind(&done);
+}
+
+
+// TODO(svenpanne) Refactor this to avoid code duplication with DoDivI.
+void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  Register divisor = ToRegister32(instr->divisor());
+  Register remainder = ToRegister32(instr->temp());
+  Register result = ToRegister32(instr->result());
+
+  // This can't cause an exception on ARM, so we can speculatively
+  // execute it already now.
+  __ Sdiv(result, dividend, divisor);
+
+  // Check for x / 0.
+  DeoptimizeIfZero(divisor, instr);
+
+  // Check for (kMinInt / -1).
+  if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
+    // The V flag will be set iff dividend == kMinInt.
+    __ Cmp(dividend, 1);
+    __ Ccmp(divisor, -1, NoFlag, vs);
+    DeoptimizeIf(eq, instr);
+  }
+
+  // Check for (0 / -x) that will produce negative zero.
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    __ Cmp(divisor, 0);
+    __ Ccmp(dividend, 0, ZFlag, mi);
+    // "divisor" can't be null because the code would have already been
+    // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
+    // In this case we need to deoptimize to produce a -0.
+    DeoptimizeIf(eq, instr);
+  }
+
+  Label done;
+  // If both operands have the same sign then we are done.
+  __ Eor(remainder, dividend, divisor);
+  __ Tbz(remainder, kWSignBit, &done);
+
+  // Check if the result needs to be corrected.
+  __ Msub(remainder, result, divisor, dividend);
+  __ Cbz(remainder, &done);
+  __ Sub(result, result, 1);
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoMathLog(LMathLog* instr) {
+  DCHECK(instr->IsMarkedAsCall());
+  DCHECK(ToDoubleRegister(instr->value()).is(d0));
+  __ CallCFunction(ExternalReference::math_log_double_function(isolate()),
+                   0, 1);
+  DCHECK(ToDoubleRegister(instr->result()).Is(d0));
+}
+
+
+void LCodeGen::DoMathClz32(LMathClz32* instr) {
+  Register input = ToRegister32(instr->value());
+  Register result = ToRegister32(instr->result());
+  __ Clz(result, input);
+}
+
+
+void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  Label done;
+
+  // Math.pow(x, 0.5) differs from fsqrt(x) in the following cases:
+  //  Math.pow(-Infinity, 0.5) == +Infinity
+  //  Math.pow(-0.0, 0.5) == +0.0
+
+  // Catch -infinity inputs first.
+  // TODO(jbramley): A constant infinity register would be helpful here.
+  __ Fmov(double_scratch(), kFP64NegativeInfinity);
+  __ Fcmp(double_scratch(), input);
+  __ Fabs(result, input);
+  __ B(&done, eq);
+
+  // Add +0.0 to convert -0.0 to +0.0.
+  __ Fadd(double_scratch(), input, fp_zero);
+  __ Fsqrt(result, double_scratch());
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoPower(LPower* instr) {
+  Representation exponent_type = instr->hydrogen()->right()->representation();
+  // Having marked this as a call, we can use any registers.
+  // Just make sure that the input/output registers are the expected ones.
+  Register tagged_exponent = MathPowTaggedDescriptor::exponent();
+  Register integer_exponent = MathPowIntegerDescriptor::exponent();
+  DCHECK(!instr->right()->IsDoubleRegister() ||
+         ToDoubleRegister(instr->right()).is(d1));
+  DCHECK(exponent_type.IsInteger32() || !instr->right()->IsRegister() ||
+         ToRegister(instr->right()).is(tagged_exponent));
+  DCHECK(!exponent_type.IsInteger32() ||
+         ToRegister(instr->right()).is(integer_exponent));
+  DCHECK(ToDoubleRegister(instr->left()).is(d0));
+  DCHECK(ToDoubleRegister(instr->result()).is(d0));
+
+  if (exponent_type.IsSmi()) {
+    MathPowStub stub(isolate(), MathPowStub::TAGGED);
+    __ CallStub(&stub);
+  } else if (exponent_type.IsTagged()) {
+    Label no_deopt;
+    __ JumpIfSmi(tagged_exponent, &no_deopt);
+    DeoptimizeIfNotHeapNumber(tagged_exponent, instr);
+    __ Bind(&no_deopt);
+    MathPowStub stub(isolate(), MathPowStub::TAGGED);
+    __ CallStub(&stub);
+  } else if (exponent_type.IsInteger32()) {
+    // Ensure integer exponent has no garbage in top 32-bits, as MathPowStub
+    // supports large integer exponents.
+    __ Sxtw(integer_exponent, integer_exponent);
+    MathPowStub stub(isolate(), MathPowStub::INTEGER);
+    __ CallStub(&stub);
+  } else {
+    DCHECK(exponent_type.IsDouble());
+    MathPowStub stub(isolate(), MathPowStub::DOUBLE);
+    __ CallStub(&stub);
+  }
+}
+
+
+void LCodeGen::DoMathRoundD(LMathRoundD* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  DoubleRegister scratch_d = double_scratch();
+
+  DCHECK(!AreAliased(input, result, scratch_d));
+
+  Label done;
+
+  __ Frinta(result, input);
+  __ Fcmp(input, 0.0);
+  __ Fccmp(result, input, ZFlag, lt);
+  // The result is correct if the input was in [-0, +infinity], or was a
+  // negative integral value.
+  __ B(eq, &done);
+
+  // Here the input is negative, non integral, with an exponent lower than 52.
+  // We do not have to worry about the 0.49999999999999994 (0x3fdfffffffffffff)
+  // case. So we can safely add 0.5.
+  __ Fmov(scratch_d, 0.5);
+  __ Fadd(result, input, scratch_d);
+  __ Frintm(result, result);
+  // The range [-0.5, -0.0[ yielded +0.0. Force the sign to negative.
+  __ Fabs(result, result);
+  __ Fneg(result, result);
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoMathRoundI(LMathRoundI* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister temp = ToDoubleRegister(instr->temp1());
+  DoubleRegister dot_five = double_scratch();
+  Register result = ToRegister(instr->result());
+  Label done;
+
+  // Math.round() rounds to the nearest integer, with ties going towards
+  // +infinity. This does not match any IEEE-754 rounding mode.
+  //  - Infinities and NaNs are propagated unchanged, but cause deopts because
+  //    they can't be represented as integers.
+  //  - The sign of the result is the same as the sign of the input. This means
+  //    that -0.0 rounds to itself, and values -0.5 <= input < 0 also produce a
+  //    result of -0.0.
+
+  // Add 0.5 and round towards -infinity.
+  __ Fmov(dot_five, 0.5);
+  __ Fadd(temp, input, dot_five);
+  __ Fcvtms(result, temp);
+
+  // The result is correct if:
+  //  result is not 0, as the input could be NaN or [-0.5, -0.0].
+  //  result is not 1, as 0.499...94 will wrongly map to 1.
+  //  result fits in 32 bits.
+  __ Cmp(result, Operand(result.W(), SXTW));
+  __ Ccmp(result, 1, ZFlag, eq);
+  __ B(hi, &done);
+
+  // At this point, we have to handle possible inputs of NaN or numbers in the
+  // range [-0.5, 1.5[, or numbers larger than 32 bits.
+
+  // Deoptimize if the result > 1, as it must be larger than 32 bits.
+  __ Cmp(result, 1);
+  DeoptimizeIf(hi, instr);
+
+  // Deoptimize for negative inputs, which at this point are only numbers in
+  // the range [-0.5, -0.0]
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    __ Fmov(result, input);
+    DeoptimizeIfNegative(result, instr);
+  }
+
+  // Deoptimize if the input was NaN.
+  __ Fcmp(input, dot_five);
+  DeoptimizeIf(vs, instr);
+
+  // Now, the only unhandled inputs are in the range [0.0, 1.5[ (or [-0.5, 1.5[
+  // if we didn't generate a -0.0 bailout). If input >= 0.5 then return 1,
+  // else 0; we avoid dealing with 0.499...94 directly.
+  __ Cset(result, ge);
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoMathFround(LMathFround* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  __ Fcvt(result.S(), input);
+  __ Fcvt(result, result.S());
+}
+
+
+void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  __ Fsqrt(result, input);
+}
+
+
+void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
+  HMathMinMax::Operation op = instr->hydrogen()->operation();
+  if (instr->hydrogen()->representation().IsInteger32()) {
+    Register result = ToRegister32(instr->result());
+    Register left = ToRegister32(instr->left());
+    Operand right = ToOperand32(instr->right());
+
+    __ Cmp(left, right);
+    __ Csel(result, left, right, (op == HMathMinMax::kMathMax) ? ge : le);
+  } else if (instr->hydrogen()->representation().IsSmi()) {
+    Register result = ToRegister(instr->result());
+    Register left = ToRegister(instr->left());
+    Operand right = ToOperand(instr->right());
+
+    __ Cmp(left, right);
+    __ Csel(result, left, right, (op == HMathMinMax::kMathMax) ? ge : le);
+  } else {
+    DCHECK(instr->hydrogen()->representation().IsDouble());
+    DoubleRegister result = ToDoubleRegister(instr->result());
+    DoubleRegister left = ToDoubleRegister(instr->left());
+    DoubleRegister right = ToDoubleRegister(instr->right());
+
+    if (op == HMathMinMax::kMathMax) {
+      __ Fmax(result, left, right);
+    } else {
+      DCHECK(op == HMathMinMax::kMathMin);
+      __ Fmin(result, left, right);
+    }
+  }
+}
+
+
+void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  int32_t divisor = instr->divisor();
+  DCHECK(dividend.is(ToRegister32(instr->result())));
+
+  // Theoretically, a variation of the branch-free code for integer division by
+  // a power of 2 (calculating the remainder via an additional multiplication
+  // (which gets simplified to an 'and') and subtraction) should be faster, and
+  // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
+  // indicate that positive dividends are heavily favored, so the branching
+  // version performs better.
+  HMod* hmod = instr->hydrogen();
+  int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
+  Label dividend_is_not_negative, done;
+  if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
+    __ Tbz(dividend, kWSignBit, &dividend_is_not_negative);
+    // Note that this is correct even for kMinInt operands.
+    __ Neg(dividend, dividend);
+    __ And(dividend, dividend, mask);
+    __ Negs(dividend, dividend);
+    if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      DeoptimizeIf(eq, instr);
+    }
+    __ B(&done);
+  }
+
+  __ bind(&dividend_is_not_negative);
+  __ And(dividend, dividend, mask);
+  __ bind(&done);
+}
+
+
+void LCodeGen::DoModByConstI(LModByConstI* instr) {
+  Register dividend = ToRegister32(instr->dividend());
+  int32_t divisor = instr->divisor();
+  Register result = ToRegister32(instr->result());
+  Register temp = ToRegister32(instr->temp());
+  DCHECK(!AreAliased(dividend, result, temp));
+
+  if (divisor == 0) {
+    Deoptimize(instr);
+    return;
+  }
+
+  __ TruncatingDiv(result, dividend, Abs(divisor));
+  __ Sxtw(dividend.X(), dividend);
+  __ Mov(temp, Abs(divisor));
+  __ Smsubl(result.X(), result, temp, dividend.X());
+
+  // Check for negative zero.
+  HMod* hmod = instr->hydrogen();
+  if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    Label remainder_not_zero;
+    __ Cbnz(result, &remainder_not_zero);
+    DeoptimizeIfNegative(dividend, instr);
+    __ bind(&remainder_not_zero);
+  }
+}
+
+
+void LCodeGen::DoModI(LModI* instr) {
+  Register dividend = ToRegister32(instr->left());
+  Register divisor = ToRegister32(instr->right());
+  Register result = ToRegister32(instr->result());
+
+  Label done;
+  // modulo = dividend - quotient * divisor
+  __ Sdiv(result, dividend, divisor);
+  if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
+    DeoptimizeIfZero(divisor, instr);
+  }
+  __ Msub(result, result, divisor, dividend);
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    __ Cbnz(result, &done);
+    DeoptimizeIfNegative(dividend, instr);
+  }
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoMulConstIS(LMulConstIS* instr) {
+  DCHECK(instr->hydrogen()->representation().IsSmiOrInteger32());
+  bool is_smi = instr->hydrogen()->representation().IsSmi();
+  Register result =
+      is_smi ? ToRegister(instr->result()) : ToRegister32(instr->result());
+  Register left =
+      is_smi ? ToRegister(instr->left()) : ToRegister32(instr->left()) ;
+  int32_t right = ToInteger32(instr->right());
+  DCHECK((right > -kMaxInt) || (right < kMaxInt));
+
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  bool bailout_on_minus_zero =
+    instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+
+  if (bailout_on_minus_zero) {
+    if (right < 0) {
+      // The result is -0 if right is negative and left is zero.
+      DeoptimizeIfZero(left, instr);
+    } else if (right == 0) {
+      // The result is -0 if the right is zero and the left is negative.
+      DeoptimizeIfNegative(left, instr);
+    }
+  }
+
+  switch (right) {
+    // Cases which can detect overflow.
+    case -1:
+      if (can_overflow) {
+        // Only 0x80000000 can overflow here.
+        __ Negs(result, left);
+        DeoptimizeIf(vs, instr);
+      } else {
+        __ Neg(result, left);
+      }
+      break;
+    case 0:
+      // This case can never overflow.
+      __ Mov(result, 0);
+      break;
+    case 1:
+      // This case can never overflow.
+      __ Mov(result, left, kDiscardForSameWReg);
+      break;
+    case 2:
+      if (can_overflow) {
+        __ Adds(result, left, left);
+        DeoptimizeIf(vs, instr);
+      } else {
+        __ Add(result, left, left);
+      }
+      break;
+
+    default:
+      // Multiplication by constant powers of two (and some related values)
+      // can be done efficiently with shifted operands.
+      int32_t right_abs = Abs(right);
+
+      if (base::bits::IsPowerOfTwo32(right_abs)) {
+        int right_log2 = WhichPowerOf2(right_abs);
+
+        if (can_overflow) {
+          Register scratch = result;
+          DCHECK(!AreAliased(scratch, left));
+          __ Cls(scratch, left);
+          __ Cmp(scratch, right_log2);
+          DeoptimizeIf(lt, instr);
+        }
+
+        if (right >= 0) {
+          // result = left << log2(right)
+          __ Lsl(result, left, right_log2);
+        } else {
+          // result = -left << log2(-right)
+          if (can_overflow) {
+            __ Negs(result, Operand(left, LSL, right_log2));
+            DeoptimizeIf(vs, instr);
+          } else {
+            __ Neg(result, Operand(left, LSL, right_log2));
+          }
+        }
+        return;
+      }
+
+
+      // For the following cases, we could perform a conservative overflow check
+      // with CLS as above. However the few cycles saved are likely not worth
+      // the risk of deoptimizing more often than required.
+      DCHECK(!can_overflow);
+
+      if (right >= 0) {
+        if (base::bits::IsPowerOfTwo32(right - 1)) {
+          // result = left + left << log2(right - 1)
+          __ Add(result, left, Operand(left, LSL, WhichPowerOf2(right - 1)));
+        } else if (base::bits::IsPowerOfTwo32(right + 1)) {
+          // result = -left + left << log2(right + 1)
+          __ Sub(result, left, Operand(left, LSL, WhichPowerOf2(right + 1)));
+          __ Neg(result, result);
+        } else {
+          UNREACHABLE();
+        }
+      } else {
+        if (base::bits::IsPowerOfTwo32(-right + 1)) {
+          // result = left - left << log2(-right + 1)
+          __ Sub(result, left, Operand(left, LSL, WhichPowerOf2(-right + 1)));
+        } else if (base::bits::IsPowerOfTwo32(-right - 1)) {
+          // result = -left - left << log2(-right - 1)
+          __ Add(result, left, Operand(left, LSL, WhichPowerOf2(-right - 1)));
+          __ Neg(result, result);
+        } else {
+          UNREACHABLE();
+        }
+      }
+  }
+}
+
+
+void LCodeGen::DoMulI(LMulI* instr) {
+  Register result = ToRegister32(instr->result());
+  Register left = ToRegister32(instr->left());
+  Register right = ToRegister32(instr->right());
+
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  bool bailout_on_minus_zero =
+    instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+
+  if (bailout_on_minus_zero && !left.Is(right)) {
+    // If one operand is zero and the other is negative, the result is -0.
+    //  - Set Z (eq) if either left or right, or both, are 0.
+    __ Cmp(left, 0);
+    __ Ccmp(right, 0, ZFlag, ne);
+    //  - If so (eq), set N (mi) if left + right is negative.
+    //  - Otherwise, clear N.
+    __ Ccmn(left, right, NoFlag, eq);
+    DeoptimizeIf(mi, instr);
+  }
+
+  if (can_overflow) {
+    __ Smull(result.X(), left, right);
+    __ Cmp(result.X(), Operand(result, SXTW));
+    DeoptimizeIf(ne, instr);
+  } else {
+    __ Mul(result, left, right);
+  }
+}
+
+
+void LCodeGen::DoMulS(LMulS* instr) {
+  Register result = ToRegister(instr->result());
+  Register left = ToRegister(instr->left());
+  Register right = ToRegister(instr->right());
+
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  bool bailout_on_minus_zero =
+    instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+
+  if (bailout_on_minus_zero && !left.Is(right)) {
+    // If one operand is zero and the other is negative, the result is -0.
+    //  - Set Z (eq) if either left or right, or both, are 0.
+    __ Cmp(left, 0);
+    __ Ccmp(right, 0, ZFlag, ne);
+    //  - If so (eq), set N (mi) if left + right is negative.
+    //  - Otherwise, clear N.
+    __ Ccmn(left, right, NoFlag, eq);
+    DeoptimizeIf(mi, instr);
+  }
+
+  STATIC_ASSERT((kSmiShift == 32) && (kSmiTag == 0));
+  if (can_overflow) {
+    __ Smulh(result, left, right);
+    __ Cmp(result, Operand(result.W(), SXTW));
+    __ SmiTag(result);
+    DeoptimizeIf(ne, instr);
+  } else {
+    if (AreAliased(result, left, right)) {
+      // All three registers are the same: half untag the input and then
+      // multiply, giving a tagged result.
+      STATIC_ASSERT((kSmiShift % 2) == 0);
+      __ Asr(result, left, kSmiShift / 2);
+      __ Mul(result, result, result);
+    } else if (result.Is(left) && !left.Is(right)) {
+      // Registers result and left alias, right is distinct: untag left into
+      // result, and then multiply by right, giving a tagged result.
+      __ SmiUntag(result, left);
+      __ Mul(result, result, right);
+    } else {
+      DCHECK(!left.Is(result));
+      // Registers result and right alias, left is distinct, or all registers
+      // are distinct: untag right into result, and then multiply by left,
+      // giving a tagged result.
+      __ SmiUntag(result, right);
+      __ Mul(result, left, result);
+    }
+  }
+}
+
+
+void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  Register result = ToRegister(instr->result());
+  __ Mov(result, 0);
+
+  PushSafepointRegistersScope scope(this);
+  // NumberTagU and NumberTagD use the context from the frame, rather than
+  // the environment's HContext or HInlinedContext value.
+  // They only call Runtime::kAllocateHeapNumber.
+  // The corresponding HChange instructions are added in a phase that does
+  // not have easy access to the local context.
+  __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
+  __ StoreToSafepointRegisterSlot(x0, result);
+}
+
+
+void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
+  class DeferredNumberTagD: public LDeferredCode {
+   public:
+    DeferredNumberTagD(LCodeGen* codegen, LNumberTagD* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredNumberTagD(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LNumberTagD* instr_;
+  };
+
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
+  if (FLAG_inline_new) {
+    __ AllocateHeapNumber(result, deferred->entry(), temp1, temp2);
+  } else {
+    __ B(deferred->entry());
+  }
+
+  __ Bind(deferred->exit());
+  __ Str(input, FieldMemOperand(result, HeapNumber::kValueOffset));
+}
+
+
+void LCodeGen::DoDeferredNumberTagU(LInstruction* instr,
+                                    LOperand* value,
+                                    LOperand* temp1,
+                                    LOperand* temp2) {
+  Label slow, convert_and_store;
+  Register src = ToRegister32(value);
+  Register dst = ToRegister(instr->result());
+  Register scratch1 = ToRegister(temp1);
+
+  if (FLAG_inline_new) {
+    Register scratch2 = ToRegister(temp2);
+    __ AllocateHeapNumber(dst, &slow, scratch1, scratch2);
+    __ B(&convert_and_store);
+  }
+
+  // Slow case: call the runtime system to do the number allocation.
+  __ Bind(&slow);
+  // TODO(3095996): Put a valid pointer value in the stack slot where the result
+  // register is stored, as this register is in the pointer map, but contains an
+  // integer value.
+  __ Mov(dst, 0);
+  {
+    // Preserve the value of all registers.
+    PushSafepointRegistersScope scope(this);
+
+    // NumberTagU and NumberTagD use the context from the frame, rather than
+    // the environment's HContext or HInlinedContext value.
+    // They only call Runtime::kAllocateHeapNumber.
+    // The corresponding HChange instructions are added in a phase that does
+    // not have easy access to the local context.
+    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+    RecordSafepointWithRegisters(
+      instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(x0, dst);
+  }
+
+  // Convert number to floating point and store in the newly allocated heap
+  // number.
+  __ Bind(&convert_and_store);
+  DoubleRegister dbl_scratch = double_scratch();
+  __ Ucvtf(dbl_scratch, src);
+  __ Str(dbl_scratch, FieldMemOperand(dst, HeapNumber::kValueOffset));
+}
+
+
+void LCodeGen::DoNumberTagU(LNumberTagU* instr) {
+  class DeferredNumberTagU: public LDeferredCode {
+   public:
+    DeferredNumberTagU(LCodeGen* codegen, LNumberTagU* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredNumberTagU(instr_,
+                                      instr_->value(),
+                                      instr_->temp1(),
+                                      instr_->temp2());
+    }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LNumberTagU* instr_;
+  };
+
+  Register value = ToRegister32(instr->value());
+  Register result = ToRegister(instr->result());
+
+  DeferredNumberTagU* deferred = new(zone()) DeferredNumberTagU(this, instr);
+  __ Cmp(value, Smi::kMaxValue);
+  __ B(hi, deferred->entry());
+  __ SmiTag(result, value.X());
+  __ Bind(deferred->exit());
+}
+
+
+void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
+  Register input = ToRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  bool can_convert_undefined_to_nan =
+      instr->hydrogen()->can_convert_undefined_to_nan();
+
+  Label done, load_smi;
+
+  // Work out what untag mode we're working with.
+  HValue* value = instr->hydrogen()->value();
+  NumberUntagDMode mode = value->representation().IsSmi()
+      ? NUMBER_CANDIDATE_IS_SMI : NUMBER_CANDIDATE_IS_ANY_TAGGED;
+
+  if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
+    __ JumpIfSmi(input, &load_smi);
+
+    Label convert_undefined;
+
+    // Heap number map check.
+    if (can_convert_undefined_to_nan) {
+      __ JumpIfNotHeapNumber(input, &convert_undefined);
+    } else {
+      DeoptimizeIfNotHeapNumber(input, instr);
+    }
+
+    // Load heap number.
+    __ Ldr(result, FieldMemOperand(input, HeapNumber::kValueOffset));
+    if (instr->hydrogen()->deoptimize_on_minus_zero()) {
+      DeoptimizeIfMinusZero(result, instr);
+    }
+    __ B(&done);
+
+    if (can_convert_undefined_to_nan) {
+      __ Bind(&convert_undefined);
+      DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+
+      __ LoadRoot(scratch, Heap::kNanValueRootIndex);
+      __ Ldr(result, FieldMemOperand(scratch, HeapNumber::kValueOffset));
+      __ B(&done);
+    }
+
+  } else {
+    DCHECK(mode == NUMBER_CANDIDATE_IS_SMI);
+    // Fall through to load_smi.
+  }
+
+  // Smi to double register conversion.
+  __ Bind(&load_smi);
+  __ SmiUntagToDouble(result, input);
+
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoOsrEntry(LOsrEntry* instr) {
+  // This is a pseudo-instruction that ensures that the environment here is
+  // properly registered for deoptimization and records the assembler's PC
+  // offset.
+  LEnvironment* environment = instr->environment();
+
+  // If the environment were already registered, we would have no way of
+  // backpatching it with the spill slot operands.
+  DCHECK(!environment->HasBeenRegistered());
+  RegisterEnvironmentForDeoptimization(environment, Safepoint::kNoLazyDeopt);
+
+  GenerateOsrPrologue();
+}
+
+
+void LCodeGen::DoParameter(LParameter* instr) {
+  // Nothing to do.
+}
+
+
+void LCodeGen::DoPreparePushArguments(LPreparePushArguments* instr) {
+  __ PushPreamble(instr->argc(), kPointerSize);
+}
+
+
+void LCodeGen::DoPushArguments(LPushArguments* instr) {
+  MacroAssembler::PushPopQueue args(masm());
+
+  for (int i = 0; i < instr->ArgumentCount(); ++i) {
+    LOperand* arg = instr->argument(i);
+    if (arg->IsDoubleRegister() || arg->IsDoubleStackSlot()) {
+      Abort(kDoPushArgumentNotImplementedForDoubleType);
+      return;
+    }
+    args.Queue(ToRegister(arg));
+  }
+
+  // The preamble was done by LPreparePushArguments.
+  args.PushQueued(MacroAssembler::PushPopQueue::SKIP_PREAMBLE);
+
+  after_push_argument_ = true;
+}
+
+
+void LCodeGen::DoReturn(LReturn* instr) {
+  if (FLAG_trace && info()->IsOptimizing()) {
+    // Push the return value on the stack as the parameter.
+    // Runtime::TraceExit returns its parameter in x0.  We're leaving the code
+    // managed by the register allocator and tearing down the frame, it's
+    // safe to write to the context register.
+    __ Push(x0);
+    __ Ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ CallRuntime(Runtime::kTraceExit, 1);
+  }
+
+  if (info()->saves_caller_doubles()) {
+    RestoreCallerDoubles();
+  }
+
+  int no_frame_start = -1;
+  if (NeedsEagerFrame()) {
+    Register stack_pointer = masm()->StackPointer();
+    __ Mov(stack_pointer, fp);
+    no_frame_start = masm_->pc_offset();
+    __ Pop(fp, lr);
+  }
+
+  if (instr->has_constant_parameter_count()) {
+    int parameter_count = ToInteger32(instr->constant_parameter_count());
+    __ Drop(parameter_count + 1);
+  } else {
+    Register parameter_count = ToRegister(instr->parameter_count());
+    __ DropBySMI(parameter_count);
+  }
+  __ Ret();
+
+  if (no_frame_start != -1) {
+    info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
+  }
+}
+
+
+MemOperand LCodeGen::BuildSeqStringOperand(Register string,
+                                           Register temp,
+                                           LOperand* index,
+                                           String::Encoding encoding) {
+  if (index->IsConstantOperand()) {
+    int offset = ToInteger32(LConstantOperand::cast(index));
+    if (encoding == String::TWO_BYTE_ENCODING) {
+      offset *= kUC16Size;
+    }
+    STATIC_ASSERT(kCharSize == 1);
+    return FieldMemOperand(string, SeqString::kHeaderSize + offset);
+  }
+
+  __ Add(temp, string, SeqString::kHeaderSize - kHeapObjectTag);
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    return MemOperand(temp, ToRegister32(index), SXTW);
+  } else {
+    STATIC_ASSERT(kUC16Size == 2);
+    return MemOperand(temp, ToRegister32(index), SXTW, 1);
+  }
+}
+
+
+void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
+  String::Encoding encoding = instr->hydrogen()->encoding();
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+  Register temp = ToRegister(instr->temp());
+
+  if (FLAG_debug_code) {
+    // Even though this lithium instruction comes with a temp register, we
+    // can't use it here because we want to use "AtStart" constraints on the
+    // inputs and the debug code here needs a scratch register.
+    UseScratchRegisterScope temps(masm());
+    Register dbg_temp = temps.AcquireX();
+
+    __ Ldr(dbg_temp, FieldMemOperand(string, HeapObject::kMapOffset));
+    __ Ldrb(dbg_temp, FieldMemOperand(dbg_temp, Map::kInstanceTypeOffset));
+
+    __ And(dbg_temp, dbg_temp,
+           Operand(kStringRepresentationMask | kStringEncodingMask));
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    __ Cmp(dbg_temp, Operand(encoding == String::ONE_BYTE_ENCODING
+                             ? one_byte_seq_type : two_byte_seq_type));
+    __ Check(eq, kUnexpectedStringType);
+  }
+
+  MemOperand operand =
+      BuildSeqStringOperand(string, temp, instr->index(), encoding);
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    __ Ldrb(result, operand);
+  } else {
+    __ Ldrh(result, operand);
+  }
+}
+
+
+void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
+  String::Encoding encoding = instr->hydrogen()->encoding();
+  Register string = ToRegister(instr->string());
+  Register value = ToRegister(instr->value());
+  Register temp = ToRegister(instr->temp());
+
+  if (FLAG_debug_code) {
+    DCHECK(ToRegister(instr->context()).is(cp));
+    Register index = ToRegister(instr->index());
+    static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
+    static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
+    int encoding_mask =
+        instr->hydrogen()->encoding() == String::ONE_BYTE_ENCODING
+        ? one_byte_seq_type : two_byte_seq_type;
+    __ EmitSeqStringSetCharCheck(string, index, kIndexIsInteger32, temp,
+                                 encoding_mask);
+  }
+  MemOperand operand =
+      BuildSeqStringOperand(string, temp, instr->index(), encoding);
+  if (encoding == String::ONE_BYTE_ENCODING) {
+    __ Strb(value, operand);
+  } else {
+    __ Strh(value, operand);
+  }
+}
+
+
+void LCodeGen::DoSmiTag(LSmiTag* instr) {
+  HChange* hchange = instr->hydrogen();
+  Register input = ToRegister(instr->value());
+  Register output = ToRegister(instr->result());
+  if (hchange->CheckFlag(HValue::kCanOverflow) &&
+      hchange->value()->CheckFlag(HValue::kUint32)) {
+    DeoptimizeIfNegative(input.W(), instr);
+  }
+  __ SmiTag(output, input);
+}
+
+
+void LCodeGen::DoSmiUntag(LSmiUntag* instr) {
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Label done, untag;
+
+  if (instr->needs_check()) {
+    DeoptimizeIfNotSmi(input, instr);
+  }
+
+  __ Bind(&untag);
+  __ SmiUntag(result, input);
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoShiftI(LShiftI* instr) {
+  LOperand* right_op = instr->right();
+  Register left = ToRegister32(instr->left());
+  Register result = ToRegister32(instr->result());
+
+  if (right_op->IsRegister()) {
+    Register right = ToRegister32(instr->right());
+    switch (instr->op()) {
+      case Token::ROR: __ Ror(result, left, right); break;
+      case Token::SAR: __ Asr(result, left, right); break;
+      case Token::SHL: __ Lsl(result, left, right); break;
+      case Token::SHR:
+        __ Lsr(result, left, right);
+        if (instr->can_deopt()) {
+          // If `left >>> right` >= 0x80000000, the result is not representable
+          // in a signed 32-bit smi.
+          DeoptimizeIfNegative(result, instr);
+        }
+        break;
+      default: UNREACHABLE();
+    }
+  } else {
+    DCHECK(right_op->IsConstantOperand());
+    int shift_count = JSShiftAmountFromLConstant(right_op);
+    if (shift_count == 0) {
+      if ((instr->op() == Token::SHR) && instr->can_deopt()) {
+        DeoptimizeIfNegative(left, instr);
+      }
+      __ Mov(result, left, kDiscardForSameWReg);
+    } else {
+      switch (instr->op()) {
+        case Token::ROR: __ Ror(result, left, shift_count); break;
+        case Token::SAR: __ Asr(result, left, shift_count); break;
+        case Token::SHL: __ Lsl(result, left, shift_count); break;
+        case Token::SHR: __ Lsr(result, left, shift_count); break;
+        default: UNREACHABLE();
+      }
+    }
+  }
+}
+
+
+void LCodeGen::DoShiftS(LShiftS* instr) {
+  LOperand* right_op = instr->right();
+  Register left = ToRegister(instr->left());
+  Register result = ToRegister(instr->result());
+
+  if (right_op->IsRegister()) {
+    Register right = ToRegister(instr->right());
+
+    // JavaScript shifts only look at the bottom 5 bits of the 'right' operand.
+    // Since we're handling smis in X registers, we have to extract these bits
+    // explicitly.
+    __ Ubfx(result, right, kSmiShift, 5);
+
+    switch (instr->op()) {
+      case Token::ROR: {
+        // This is the only case that needs a scratch register. To keep things
+        // simple for the other cases, borrow a MacroAssembler scratch register.
+        UseScratchRegisterScope temps(masm());
+        Register temp = temps.AcquireW();
+        __ SmiUntag(temp, left);
+        __ Ror(result.W(), temp.W(), result.W());
+        __ SmiTag(result);
+        break;
+      }
+      case Token::SAR:
+        __ Asr(result, left, result);
+        __ Bic(result, result, kSmiShiftMask);
+        break;
+      case Token::SHL:
+        __ Lsl(result, left, result);
+        break;
+      case Token::SHR:
+        __ Lsr(result, left, result);
+        __ Bic(result, result, kSmiShiftMask);
+        if (instr->can_deopt()) {
+          // If `left >>> right` >= 0x80000000, the result is not representable
+          // in a signed 32-bit smi.
+          DeoptimizeIfNegative(result, instr);
+        }
+        break;
+      default: UNREACHABLE();
+    }
+  } else {
+    DCHECK(right_op->IsConstantOperand());
+    int shift_count = JSShiftAmountFromLConstant(right_op);
+    if (shift_count == 0) {
+      if ((instr->op() == Token::SHR) && instr->can_deopt()) {
+        DeoptimizeIfNegative(left, instr);
+      }
+      __ Mov(result, left);
+    } else {
+      switch (instr->op()) {
+        case Token::ROR:
+          __ SmiUntag(result, left);
+          __ Ror(result.W(), result.W(), shift_count);
+          __ SmiTag(result);
+          break;
+        case Token::SAR:
+          __ Asr(result, left, shift_count);
+          __ Bic(result, result, kSmiShiftMask);
+          break;
+        case Token::SHL:
+          __ Lsl(result, left, shift_count);
+          break;
+        case Token::SHR:
+          __ Lsr(result, left, shift_count);
+          __ Bic(result, result, kSmiShiftMask);
+          break;
+        default: UNREACHABLE();
+      }
+    }
+  }
+}
+
+
+void LCodeGen::DoDebugBreak(LDebugBreak* instr) {
+  __ Debug("LDebugBreak", 0, BREAK);
+}
+
+
+void LCodeGen::DoDeclareGlobals(LDeclareGlobals* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Register scratch1 = x5;
+  Register scratch2 = x6;
+  DCHECK(instr->IsMarkedAsCall());
+
+  ASM_UNIMPLEMENTED_BREAK("DoDeclareGlobals");
+  // TODO(all): if Mov could handle object in new space then it could be used
+  // here.
+  __ LoadHeapObject(scratch1, instr->hydrogen()->pairs());
+  __ Mov(scratch2, Smi::FromInt(instr->hydrogen()->flags()));
+  __ Push(cp, scratch1, scratch2);  // The context is the first argument.
+  CallRuntime(Runtime::kDeclareGlobals, 3, instr);
+}
+
+
+void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
+  PushSafepointRegistersScope scope(this);
+  LoadContextFromDeferred(instr->context());
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
+  RecordSafepointWithLazyDeopt(
+      instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  safepoints_.RecordLazyDeoptimizationIndex(env->deoptimization_index());
+}
+
+
+void LCodeGen::DoStackCheck(LStackCheck* instr) {
+  class DeferredStackCheck: public LDeferredCode {
+   public:
+    DeferredStackCheck(LCodeGen* codegen, LStackCheck* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredStackCheck(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LStackCheck* instr_;
+  };
+
+  DCHECK(instr->HasEnvironment());
+  LEnvironment* env = instr->environment();
+  // There is no LLazyBailout instruction for stack-checks. We have to
+  // prepare for lazy deoptimization explicitly here.
+  if (instr->hydrogen()->is_function_entry()) {
+    // Perform stack overflow check.
+    Label done;
+    __ CompareRoot(masm()->StackPointer(), Heap::kStackLimitRootIndex);
+    __ B(hs, &done);
+
+    PredictableCodeSizeScope predictable(masm_,
+                                         Assembler::kCallSizeWithRelocation);
+    DCHECK(instr->context()->IsRegister());
+    DCHECK(ToRegister(instr->context()).is(cp));
+    CallCode(isolate()->builtins()->StackCheck(),
+             RelocInfo::CODE_TARGET,
+             instr);
+    __ Bind(&done);
+  } else {
+    DCHECK(instr->hydrogen()->is_backwards_branch());
+    // Perform stack overflow check if this goto needs it before jumping.
+    DeferredStackCheck* deferred_stack_check =
+        new(zone()) DeferredStackCheck(this, instr);
+    __ CompareRoot(masm()->StackPointer(), Heap::kStackLimitRootIndex);
+    __ B(lo, deferred_stack_check->entry());
+
+    EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
+    __ Bind(instr->done_label());
+    deferred_stack_check->SetExit(instr->done_label());
+    RegisterEnvironmentForDeoptimization(env, Safepoint::kLazyDeopt);
+    // Don't record a deoptimization index for the safepoint here.
+    // This will be done explicitly when emitting call and the safepoint in
+    // the deferred code.
+  }
+}
+
+
+void LCodeGen::DoStoreCodeEntry(LStoreCodeEntry* instr) {
+  Register function = ToRegister(instr->function());
+  Register code_object = ToRegister(instr->code_object());
+  Register temp = ToRegister(instr->temp());
+  __ Add(temp, code_object, Code::kHeaderSize - kHeapObjectTag);
+  __ Str(temp, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+}
+
+
+void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
+  Register context = ToRegister(instr->context());
+  Register value = ToRegister(instr->value());
+  Register scratch = ToRegister(instr->temp());
+  MemOperand target = ContextMemOperand(context, instr->slot_index());
+
+  Label skip_assignment;
+
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    __ Ldr(scratch, target);
+    if (instr->hydrogen()->DeoptimizesOnHole()) {
+      DeoptimizeIfRoot(scratch, Heap::kTheHoleValueRootIndex, instr);
+    } else {
+      __ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, &skip_assignment);
+    }
+  }
+
+  __ Str(value, target);
+  if (instr->hydrogen()->NeedsWriteBarrier()) {
+    SmiCheck check_needed =
+        instr->hydrogen()->value()->type().IsHeapObject()
+            ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
+    __ RecordWriteContextSlot(context,
+                              target.offset(),
+                              value,
+                              scratch,
+                              GetLinkRegisterState(),
+                              kSaveFPRegs,
+                              EMIT_REMEMBERED_SET,
+                              check_needed);
+  }
+  __ Bind(&skip_assignment);
+}
+
+
+void LCodeGen::DoStoreGlobalCell(LStoreGlobalCell* instr) {
+  Register value = ToRegister(instr->value());
+  Register cell = ToRegister(instr->temp1());
+
+  // Load the cell.
+  __ Mov(cell, Operand(instr->hydrogen()->cell().handle()));
+
+  // If the cell we are storing to contains the hole it could have
+  // been deleted from the property dictionary. In that case, we need
+  // to update the property details in the property dictionary to mark
+  // it as no longer deleted. We deoptimize in that case.
+  if (instr->hydrogen()->RequiresHoleCheck()) {
+    Register payload = ToRegister(instr->temp2());
+    __ Ldr(payload, FieldMemOperand(cell, Cell::kValueOffset));
+    DeoptimizeIfRoot(payload, Heap::kTheHoleValueRootIndex, instr);
+  }
+
+  // Store the value.
+  __ Str(value, FieldMemOperand(cell, Cell::kValueOffset));
+  // Cells are always rescanned, so no write barrier here.
+}
+
+
+void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
+  Register ext_ptr = ToRegister(instr->elements());
+  Register key = no_reg;
+  Register scratch;
+  ElementsKind elements_kind = instr->elements_kind();
+
+  bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi();
+  bool key_is_constant = instr->key()->IsConstantOperand();
+  int constant_key = 0;
+  if (key_is_constant) {
+    DCHECK(instr->temp() == NULL);
+    constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xf0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+  } else {
+    key = ToRegister(instr->key());
+    scratch = ToRegister(instr->temp());
+  }
+
+  MemOperand dst =
+    PrepareKeyedExternalArrayOperand(key, ext_ptr, scratch, key_is_smi,
+                                     key_is_constant, constant_key,
+                                     elements_kind,
+                                     instr->base_offset());
+
+  if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) ||
+      (elements_kind == FLOAT32_ELEMENTS)) {
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    DoubleRegister dbl_scratch = double_scratch();
+    __ Fcvt(dbl_scratch.S(), value);
+    __ Str(dbl_scratch.S(), dst);
+  } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) ||
+             (elements_kind == FLOAT64_ELEMENTS)) {
+    DoubleRegister value = ToDoubleRegister(instr->value());
+    __ Str(value, dst);
+  } else {
+    Register value = ToRegister(instr->value());
+
+    switch (elements_kind) {
+      case EXTERNAL_UINT8_CLAMPED_ELEMENTS:
+      case EXTERNAL_INT8_ELEMENTS:
+      case EXTERNAL_UINT8_ELEMENTS:
+      case UINT8_ELEMENTS:
+      case UINT8_CLAMPED_ELEMENTS:
+      case INT8_ELEMENTS:
+        __ Strb(value, dst);
+        break;
+      case EXTERNAL_INT16_ELEMENTS:
+      case EXTERNAL_UINT16_ELEMENTS:
+      case INT16_ELEMENTS:
+      case UINT16_ELEMENTS:
+        __ Strh(value, dst);
+        break;
+      case EXTERNAL_INT32_ELEMENTS:
+      case EXTERNAL_UINT32_ELEMENTS:
+      case INT32_ELEMENTS:
+      case UINT32_ELEMENTS:
+        __ Str(value.W(), dst);
+        break;
+      case FLOAT32_ELEMENTS:
+      case FLOAT64_ELEMENTS:
+      case EXTERNAL_FLOAT32_ELEMENTS:
+      case EXTERNAL_FLOAT64_ELEMENTS:
+      case FAST_DOUBLE_ELEMENTS:
+      case FAST_ELEMENTS:
+      case FAST_SMI_ELEMENTS:
+      case FAST_HOLEY_DOUBLE_ELEMENTS:
+      case FAST_HOLEY_ELEMENTS:
+      case FAST_HOLEY_SMI_ELEMENTS:
+      case DICTIONARY_ELEMENTS:
+      case SLOPPY_ARGUMENTS_ELEMENTS:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedFixedDouble(LStoreKeyedFixedDouble* instr) {
+  Register elements = ToRegister(instr->elements());
+  DoubleRegister value = ToDoubleRegister(instr->value());
+  MemOperand mem_op;
+
+  if (instr->key()->IsConstantOperand()) {
+    int constant_key = ToInteger32(LConstantOperand::cast(instr->key()));
+    if (constant_key & 0xf0000000) {
+      Abort(kArrayIndexConstantValueTooBig);
+    }
+    int offset = instr->base_offset() + constant_key * kDoubleSize;
+    mem_op = MemOperand(elements, offset);
+  } else {
+    Register store_base = ToRegister(instr->temp());
+    Register key = ToRegister(instr->key());
+    bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
+    mem_op = PrepareKeyedArrayOperand(store_base, elements, key, key_is_tagged,
+                                      instr->hydrogen()->elements_kind(),
+                                      instr->hydrogen()->representation(),
+                                      instr->base_offset());
+  }
+
+  if (instr->NeedsCanonicalization()) {
+    __ CanonicalizeNaN(double_scratch(), value);
+    __ Str(double_scratch(), mem_op);
+  } else {
+    __ Str(value, mem_op);
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedFixed(LStoreKeyedFixed* instr) {
+  Register value = ToRegister(instr->value());
+  Register elements = ToRegister(instr->elements());
+  Register scratch = no_reg;
+  Register store_base = no_reg;
+  Register key = no_reg;
+  MemOperand mem_op;
+
+  if (!instr->key()->IsConstantOperand() ||
+      instr->hydrogen()->NeedsWriteBarrier()) {
+    scratch = ToRegister(instr->temp());
+  }
+
+  Representation representation = instr->hydrogen()->value()->representation();
+  if (instr->key()->IsConstantOperand()) {
+    LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
+    int offset = instr->base_offset() +
+        ToInteger32(const_operand) * kPointerSize;
+    store_base = elements;
+    if (representation.IsInteger32()) {
+      DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY);
+      DCHECK(instr->hydrogen()->elements_kind() == FAST_SMI_ELEMENTS);
+      STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
+      STATIC_ASSERT(kSmiTag == 0);
+      mem_op = UntagSmiMemOperand(store_base, offset);
+    } else {
+      mem_op = MemOperand(store_base, offset);
+    }
+  } else {
+    store_base = scratch;
+    key = ToRegister(instr->key());
+    bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
+
+    mem_op = PrepareKeyedArrayOperand(store_base, elements, key, key_is_tagged,
+                                      instr->hydrogen()->elements_kind(),
+                                      representation, instr->base_offset());
+  }
+
+  __ Store(value, mem_op, representation);
+
+  if (instr->hydrogen()->NeedsWriteBarrier()) {
+    DCHECK(representation.IsTagged());
+    // This assignment may cause element_addr to alias store_base.
+    Register element_addr = scratch;
+    SmiCheck check_needed =
+        instr->hydrogen()->value()->type().IsHeapObject()
+            ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
+    // Compute address of modified element and store it into key register.
+    __ Add(element_addr, mem_op.base(), mem_op.OffsetAsOperand());
+    __ RecordWrite(elements, element_addr, value, GetLinkRegisterState(),
+                   kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed,
+                   instr->hydrogen()->PointersToHereCheckForValue());
+  }
+}
+
+
+void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->key()).is(StoreDescriptor::NameRegister()));
+  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
+
+  Handle<Code> ic =
+      CodeFactory::KeyedStoreIC(isolate(), instr->strict_mode()).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
+  Representation representation = instr->representation();
+
+  Register object = ToRegister(instr->object());
+  HObjectAccess access = instr->hydrogen()->access();
+  int offset = access.offset();
+
+  if (access.IsExternalMemory()) {
+    DCHECK(!instr->hydrogen()->has_transition());
+    DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
+    Register value = ToRegister(instr->value());
+    __ Store(value, MemOperand(object, offset), representation);
+    return;
+  }
+
+  __ AssertNotSmi(object);
+
+  if (representation.IsDouble()) {
+    DCHECK(access.IsInobject());
+    DCHECK(!instr->hydrogen()->has_transition());
+    DCHECK(!instr->hydrogen()->NeedsWriteBarrier());
+    FPRegister value = ToDoubleRegister(instr->value());
+    __ Str(value, FieldMemOperand(object, offset));
+    return;
+  }
+
+  Register value = ToRegister(instr->value());
+
+  DCHECK(!representation.IsSmi() ||
+         !instr->value()->IsConstantOperand() ||
+         IsInteger32Constant(LConstantOperand::cast(instr->value())));
+
+  if (instr->hydrogen()->has_transition()) {
+    Handle<Map> transition = instr->hydrogen()->transition_map();
+    AddDeprecationDependency(transition);
+    // Store the new map value.
+    Register new_map_value = ToRegister(instr->temp0());
+    __ Mov(new_map_value, Operand(transition));
+    __ Str(new_map_value, FieldMemOperand(object, HeapObject::kMapOffset));
+    if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
+      // Update the write barrier for the map field.
+      __ RecordWriteForMap(object,
+                           new_map_value,
+                           ToRegister(instr->temp1()),
+                           GetLinkRegisterState(),
+                           kSaveFPRegs);
+    }
+  }
+
+  // Do the store.
+  Register destination;
+  if (access.IsInobject()) {
+    destination = object;
+  } else {
+    Register temp0 = ToRegister(instr->temp0());
+    __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset));
+    destination = temp0;
+  }
+
+  if (representation.IsSmi() &&
+     instr->hydrogen()->value()->representation().IsInteger32()) {
+    DCHECK(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY);
+#ifdef DEBUG
+    Register temp0 = ToRegister(instr->temp0());
+    __ Ldr(temp0, FieldMemOperand(destination, offset));
+    __ AssertSmi(temp0);
+    // If destination aliased temp0, restore it to the address calculated
+    // earlier.
+    if (destination.Is(temp0)) {
+      DCHECK(!access.IsInobject());
+      __ Ldr(destination, FieldMemOperand(object, JSObject::kPropertiesOffset));
+    }
+#endif
+    STATIC_ASSERT(static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits);
+    STATIC_ASSERT(kSmiTag == 0);
+    __ Store(value, UntagSmiFieldMemOperand(destination, offset),
+             Representation::Integer32());
+  } else {
+    __ Store(value, FieldMemOperand(destination, offset), representation);
+  }
+  if (instr->hydrogen()->NeedsWriteBarrier()) {
+    __ RecordWriteField(destination,
+                        offset,
+                        value,                        // Clobbered.
+                        ToRegister(instr->temp1()),   // Clobbered.
+                        GetLinkRegisterState(),
+                        kSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        instr->hydrogen()->SmiCheckForWriteBarrier(),
+                        instr->hydrogen()->PointersToHereCheckForValue());
+  }
+}
+
+
+void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->object()).is(StoreDescriptor::ReceiverRegister()));
+  DCHECK(ToRegister(instr->value()).is(StoreDescriptor::ValueRegister()));
+
+  __ Mov(StoreDescriptor::NameRegister(), Operand(instr->name()));
+  Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoStringAdd(LStringAdd* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  DCHECK(ToRegister(instr->left()).Is(x1));
+  DCHECK(ToRegister(instr->right()).Is(x0));
+  StringAddStub stub(isolate(),
+                     instr->hydrogen()->flags(),
+                     instr->hydrogen()->pretenure_flag());
+  CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoStringCharCodeAt(LStringCharCodeAt* instr) {
+  class DeferredStringCharCodeAt: public LDeferredCode {
+   public:
+    DeferredStringCharCodeAt(LCodeGen* codegen, LStringCharCodeAt* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredStringCharCodeAt(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LStringCharCodeAt* instr_;
+  };
+
+  DeferredStringCharCodeAt* deferred =
+      new(zone()) DeferredStringCharCodeAt(this, instr);
+
+  StringCharLoadGenerator::Generate(masm(),
+                                    ToRegister(instr->string()),
+                                    ToRegister32(instr->index()),
+                                    ToRegister(instr->result()),
+                                    deferred->entry());
+  __ Bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharCodeAt(LStringCharCodeAt* instr) {
+  Register string = ToRegister(instr->string());
+  Register result = ToRegister(instr->result());
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ Mov(result, 0);
+
+  PushSafepointRegistersScope scope(this);
+  __ Push(string);
+  // Push the index as a smi. This is safe because of the checks in
+  // DoStringCharCodeAt above.
+  Register index = ToRegister(instr->index());
+  __ SmiTagAndPush(index);
+
+  CallRuntimeFromDeferred(Runtime::kStringCharCodeAtRT, 2, instr,
+                          instr->context());
+  __ AssertSmi(x0);
+  __ SmiUntag(x0);
+  __ StoreToSafepointRegisterSlot(x0, result);
+}
+
+
+void LCodeGen::DoStringCharFromCode(LStringCharFromCode* instr) {
+  class DeferredStringCharFromCode: public LDeferredCode {
+   public:
+    DeferredStringCharFromCode(LCodeGen* codegen, LStringCharFromCode* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() { codegen()->DoDeferredStringCharFromCode(instr_); }
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LStringCharFromCode* instr_;
+  };
+
+  DeferredStringCharFromCode* deferred =
+      new(zone()) DeferredStringCharFromCode(this, instr);
+
+  DCHECK(instr->hydrogen()->value()->representation().IsInteger32());
+  Register char_code = ToRegister32(instr->char_code());
+  Register result = ToRegister(instr->result());
+
+  __ Cmp(char_code, String::kMaxOneByteCharCode);
+  __ B(hi, deferred->entry());
+  __ LoadRoot(result, Heap::kSingleCharacterStringCacheRootIndex);
+  __ Add(result, result, FixedArray::kHeaderSize - kHeapObjectTag);
+  __ Ldr(result, MemOperand(result, char_code, SXTW, kPointerSizeLog2));
+  __ CompareRoot(result, Heap::kUndefinedValueRootIndex);
+  __ B(eq, deferred->entry());
+  __ Bind(deferred->exit());
+}
+
+
+void LCodeGen::DoDeferredStringCharFromCode(LStringCharFromCode* instr) {
+  Register char_code = ToRegister(instr->char_code());
+  Register result = ToRegister(instr->result());
+
+  // TODO(3095996): Get rid of this. For now, we need to make the
+  // result register contain a valid pointer because it is already
+  // contained in the register pointer map.
+  __ Mov(result, 0);
+
+  PushSafepointRegistersScope scope(this);
+  __ SmiTagAndPush(char_code);
+  CallRuntimeFromDeferred(Runtime::kCharFromCode, 1, instr, instr->context());
+  __ StoreToSafepointRegisterSlot(x0, result);
+}
+
+
+void LCodeGen::DoStringCompareAndBranch(LStringCompareAndBranch* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Token::Value op = instr->op();
+
+  Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
+  CallCode(ic, RelocInfo::CODE_TARGET, instr);
+  InlineSmiCheckInfo::EmitNotInlined(masm());
+
+  Condition condition = TokenToCondition(op, false);
+
+  EmitCompareAndBranch(instr, condition, x0, 0);
+}
+
+
+void LCodeGen::DoSubI(LSubI* instr) {
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  Register result = ToRegister32(instr->result());
+  Register left = ToRegister32(instr->left());
+  Operand right = ToShiftedRightOperand32(instr->right(), instr);
+
+  if (can_overflow) {
+    __ Subs(result, left, right);
+    DeoptimizeIf(vs, instr);
+  } else {
+    __ Sub(result, left, right);
+  }
+}
+
+
+void LCodeGen::DoSubS(LSubS* instr) {
+  bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+  Register result = ToRegister(instr->result());
+  Register left = ToRegister(instr->left());
+  Operand right = ToOperand(instr->right());
+  if (can_overflow) {
+    __ Subs(result, left, right);
+    DeoptimizeIf(vs, instr);
+  } else {
+    __ Sub(result, left, right);
+  }
+}
+
+
+void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr,
+                                   LOperand* value,
+                                   LOperand* temp1,
+                                   LOperand* temp2) {
+  Register input = ToRegister(value);
+  Register scratch1 = ToRegister(temp1);
+  DoubleRegister dbl_scratch1 = double_scratch();
+
+  Label done;
+
+  if (instr->truncating()) {
+    Register output = ToRegister(instr->result());
+    Label check_bools;
+
+    // If it's not a heap number, jump to undefined check.
+    __ JumpIfNotHeapNumber(input, &check_bools);
+
+    // A heap number: load value and convert to int32 using truncating function.
+    __ TruncateHeapNumberToI(output, input);
+    __ B(&done);
+
+    __ Bind(&check_bools);
+
+    Register true_root = output;
+    Register false_root = scratch1;
+    __ LoadTrueFalseRoots(true_root, false_root);
+    __ Cmp(input, true_root);
+    __ Cset(output, eq);
+    __ Ccmp(input, false_root, ZFlag, ne);
+    __ B(eq, &done);
+
+    // Output contains zero, undefined is converted to zero for truncating
+    // conversions.
+    DeoptimizeIfNotRoot(input, Heap::kUndefinedValueRootIndex, instr);
+  } else {
+    Register output = ToRegister32(instr->result());
+    DoubleRegister dbl_scratch2 = ToDoubleRegister(temp2);
+
+    DeoptimizeIfNotHeapNumber(input, instr);
+
+    // A heap number: load value and convert to int32 using non-truncating
+    // function. If the result is out of range, branch to deoptimize.
+    __ Ldr(dbl_scratch1, FieldMemOperand(input, HeapNumber::kValueOffset));
+    __ TryRepresentDoubleAsInt32(output, dbl_scratch1, dbl_scratch2);
+    DeoptimizeIf(ne, instr, "lost precision or NaN");
+
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      __ Cmp(output, 0);
+      __ B(ne, &done);
+      __ Fmov(scratch1, dbl_scratch1);
+      DeoptimizeIfNegative(scratch1, instr, "minus zero");
+    }
+  }
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
+  class DeferredTaggedToI: public LDeferredCode {
+   public:
+    DeferredTaggedToI(LCodeGen* codegen, LTaggedToI* instr)
+        : LDeferredCode(codegen), instr_(instr) { }
+    virtual void Generate() {
+      codegen()->DoDeferredTaggedToI(instr_, instr_->value(), instr_->temp1(),
+                                     instr_->temp2());
+    }
+
+    virtual LInstruction* instr() { return instr_; }
+   private:
+    LTaggedToI* instr_;
+  };
+
+  Register input = ToRegister(instr->value());
+  Register output = ToRegister(instr->result());
+
+  if (instr->hydrogen()->value()->representation().IsSmi()) {
+    __ SmiUntag(output, input);
+  } else {
+    DeferredTaggedToI* deferred = new(zone()) DeferredTaggedToI(this, instr);
+
+    __ JumpIfNotSmi(input, deferred->entry());
+    __ SmiUntag(output, input);
+    __ Bind(deferred->exit());
+  }
+}
+
+
+void LCodeGen::DoThisFunction(LThisFunction* instr) {
+  Register result = ToRegister(instr->result());
+  __ Ldr(result, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
+}
+
+
+void LCodeGen::DoToFastProperties(LToFastProperties* instr) {
+  DCHECK(ToRegister(instr->value()).Is(x0));
+  DCHECK(ToRegister(instr->result()).Is(x0));
+  __ Push(x0);
+  CallRuntime(Runtime::kToFastProperties, 1, instr);
+}
+
+
+void LCodeGen::DoRegExpLiteral(LRegExpLiteral* instr) {
+  DCHECK(ToRegister(instr->context()).is(cp));
+  Label materialized;
+  // Registers will be used as follows:
+  // x7 = literals array.
+  // x1 = regexp literal.
+  // x0 = regexp literal clone.
+  // x10-x12 are used as temporaries.
+  int literal_offset =
+      FixedArray::OffsetOfElementAt(instr->hydrogen()->literal_index());
+  __ LoadObject(x7, instr->hydrogen()->literals());
+  __ Ldr(x1, FieldMemOperand(x7, literal_offset));
+  __ JumpIfNotRoot(x1, Heap::kUndefinedValueRootIndex, &materialized);
+
+  // Create regexp literal using runtime function
+  // Result will be in x0.
+  __ Mov(x12, Operand(Smi::FromInt(instr->hydrogen()->literal_index())));
+  __ Mov(x11, Operand(instr->hydrogen()->pattern()));
+  __ Mov(x10, Operand(instr->hydrogen()->flags()));
+  __ Push(x7, x12, x11, x10);
+  CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
+  __ Mov(x1, x0);
+
+  __ Bind(&materialized);
+  int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
+  Label allocated, runtime_allocate;
+
+  __ Allocate(size, x0, x10, x11, &runtime_allocate, TAG_OBJECT);
+  __ B(&allocated);
+
+  __ Bind(&runtime_allocate);
+  __ Mov(x0, Smi::FromInt(size));
+  __ Push(x1, x0);
+  CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
+  __ Pop(x1);
+
+  __ Bind(&allocated);
+  // Copy the content into the newly allocated memory.
+  __ CopyFields(x0, x1, CPURegList(x10, x11, x12), size / kPointerSize);
+}
+
+
+void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
+  Register object = ToRegister(instr->object());
+
+  Handle<Map> from_map = instr->original_map();
+  Handle<Map> to_map = instr->transitioned_map();
+  ElementsKind from_kind = instr->from_kind();
+  ElementsKind to_kind = instr->to_kind();
+
+  Label not_applicable;
+
+  if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
+    Register temp1 = ToRegister(instr->temp1());
+    Register new_map = ToRegister(instr->temp2());
+    __ CheckMap(object, temp1, from_map, &not_applicable, DONT_DO_SMI_CHECK);
+    __ Mov(new_map, Operand(to_map));
+    __ Str(new_map, FieldMemOperand(object, HeapObject::kMapOffset));
+    // Write barrier.
+    __ RecordWriteForMap(object, new_map, temp1, GetLinkRegisterState(),
+                         kDontSaveFPRegs);
+  } else {
+    {
+      UseScratchRegisterScope temps(masm());
+      // Use the temp register only in a restricted scope - the codegen checks
+      // that we do not use any register across a call.
+      __ CheckMap(object, temps.AcquireX(), from_map, &not_applicable,
+                  DONT_DO_SMI_CHECK);
+    }
+    DCHECK(object.is(x0));
+    DCHECK(ToRegister(instr->context()).is(cp));
+    PushSafepointRegistersScope scope(this);
+    __ Mov(x1, Operand(to_map));
+    bool is_js_array = from_map->instance_type() == JS_ARRAY_TYPE;
+    TransitionElementsKindStub stub(isolate(), from_kind, to_kind, is_js_array);
+    __ CallStub(&stub);
+    RecordSafepointWithRegisters(
+        instr->pointer_map(), 0, Safepoint::kLazyDeopt);
+  }
+  __ Bind(&not_applicable);
+}
+
+
+void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) {
+  Register object = ToRegister(instr->object());
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  Label no_memento_found;
+  __ TestJSArrayForAllocationMemento(object, temp1, temp2, &no_memento_found);
+  DeoptimizeIf(eq, instr);
+  __ Bind(&no_memento_found);
+}
+
+
+void LCodeGen::DoTruncateDoubleToIntOrSmi(LTruncateDoubleToIntOrSmi* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  __ TruncateDoubleToI(result, input);
+  if (instr->tag_result()) {
+    __ SmiTag(result, result);
+  }
+}
+
+
+void LCodeGen::DoTypeof(LTypeof* instr) {
+  Register input = ToRegister(instr->value());
+  __ Push(input);
+  CallRuntime(Runtime::kTypeof, 1, instr);
+}
+
+
+void LCodeGen::DoTypeofIsAndBranch(LTypeofIsAndBranch* instr) {
+  Handle<String> type_name = instr->type_literal();
+  Label* true_label = instr->TrueLabel(chunk_);
+  Label* false_label = instr->FalseLabel(chunk_);
+  Register value = ToRegister(instr->value());
+
+  Factory* factory = isolate()->factory();
+  if (String::Equals(type_name, factory->number_string())) {
+    __ JumpIfSmi(value, true_label);
+
+    int true_block = instr->TrueDestination(chunk_);
+    int false_block = instr->FalseDestination(chunk_);
+    int next_block = GetNextEmittedBlock();
+
+    if (true_block == false_block) {
+      EmitGoto(true_block);
+    } else if (true_block == next_block) {
+      __ JumpIfNotHeapNumber(value, chunk_->GetAssemblyLabel(false_block));
+    } else {
+      __ JumpIfHeapNumber(value, chunk_->GetAssemblyLabel(true_block));
+      if (false_block != next_block) {
+        __ B(chunk_->GetAssemblyLabel(false_block));
+      }
+    }
+
+  } else if (String::Equals(type_name, factory->string_string())) {
+    DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL));
+    Register map = ToRegister(instr->temp1());
+    Register scratch = ToRegister(instr->temp2());
+
+    __ JumpIfSmi(value, false_label);
+    __ JumpIfObjectType(
+        value, map, scratch, FIRST_NONSTRING_TYPE, false_label, ge);
+    __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+    EmitTestAndBranch(instr, eq, scratch, 1 << Map::kIsUndetectable);
+
+  } else if (String::Equals(type_name, factory->symbol_string())) {
+    DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL));
+    Register map = ToRegister(instr->temp1());
+    Register scratch = ToRegister(instr->temp2());
+
+    __ JumpIfSmi(value, false_label);
+    __ CompareObjectType(value, map, scratch, SYMBOL_TYPE);
+    EmitBranch(instr, eq);
+
+  } else if (String::Equals(type_name, factory->boolean_string())) {
+    __ JumpIfRoot(value, Heap::kTrueValueRootIndex, true_label);
+    __ CompareRoot(value, Heap::kFalseValueRootIndex);
+    EmitBranch(instr, eq);
+
+  } else if (String::Equals(type_name, factory->undefined_string())) {
+    DCHECK(instr->temp1() != NULL);
+    Register scratch = ToRegister(instr->temp1());
+
+    __ JumpIfRoot(value, Heap::kUndefinedValueRootIndex, true_label);
+    __ JumpIfSmi(value, false_label);
+    // Check for undetectable objects and jump to the true branch in this case.
+    __ Ldr(scratch, FieldMemOperand(value, HeapObject::kMapOffset));
+    __ Ldrb(scratch, FieldMemOperand(scratch, Map::kBitFieldOffset));
+    EmitTestAndBranch(instr, ne, scratch, 1 << Map::kIsUndetectable);
+
+  } else if (String::Equals(type_name, factory->function_string())) {
+    STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
+    DCHECK(instr->temp1() != NULL);
+    Register type = ToRegister(instr->temp1());
+
+    __ JumpIfSmi(value, false_label);
+    __ JumpIfObjectType(value, type, type, JS_FUNCTION_TYPE, true_label);
+    // HeapObject's type has been loaded into type register by JumpIfObjectType.
+    EmitCompareAndBranch(instr, eq, type, JS_FUNCTION_PROXY_TYPE);
+
+  } else if (String::Equals(type_name, factory->object_string())) {
+    DCHECK((instr->temp1() != NULL) && (instr->temp2() != NULL));
+    Register map = ToRegister(instr->temp1());
+    Register scratch = ToRegister(instr->temp2());
+
+    __ JumpIfSmi(value, false_label);
+    __ JumpIfRoot(value, Heap::kNullValueRootIndex, true_label);
+    __ JumpIfObjectType(value, map, scratch,
+                        FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, false_label, lt);
+    __ CompareInstanceType(map, scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
+    __ B(gt, false_label);
+    // Check for undetectable objects => false.
+    __ Ldrb(scratch, FieldMemOperand(map, Map::kBitFieldOffset));
+    EmitTestAndBranch(instr, eq, scratch, 1 << Map::kIsUndetectable);
+
+  } else {
+    __ B(false_label);
+  }
+}
+
+
+void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
+  __ Ucvtf(ToDoubleRegister(instr->result()), ToRegister32(instr->value()));
+}
+
+
+void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
+  Register object = ToRegister(instr->value());
+  Register map = ToRegister(instr->map());
+  Register temp = ToRegister(instr->temp());
+  __ Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+  __ Cmp(map, temp);
+  DeoptimizeIf(ne, instr);
+}
+
+
+void LCodeGen::DoWrapReceiver(LWrapReceiver* instr) {
+  Register receiver = ToRegister(instr->receiver());
+  Register function = ToRegister(instr->function());
+  Register result = ToRegister(instr->result());
+
+  // If the receiver is null or undefined, we have to pass the global object as
+  // a receiver to normal functions. Values have to be passed unchanged to
+  // builtins and strict-mode functions.
+  Label global_object, done, copy_receiver;
+
+  if (!instr->hydrogen()->known_function()) {
+    __ Ldr(result, FieldMemOperand(function,
+                                   JSFunction::kSharedFunctionInfoOffset));
+
+    // CompilerHints is an int32 field. See objects.h.
+    __ Ldr(result.W(),
+           FieldMemOperand(result, SharedFunctionInfo::kCompilerHintsOffset));
+
+    // Do not transform the receiver to object for strict mode functions.
+    __ Tbnz(result, SharedFunctionInfo::kStrictModeFunction, &copy_receiver);
+
+    // Do not transform the receiver to object for builtins.
+    __ Tbnz(result, SharedFunctionInfo::kNative, &copy_receiver);
+  }
+
+  // Normal function. Replace undefined or null with global receiver.
+  __ JumpIfRoot(receiver, Heap::kNullValueRootIndex, &global_object);
+  __ JumpIfRoot(receiver, Heap::kUndefinedValueRootIndex, &global_object);
+
+  // Deoptimize if the receiver is not a JS object.
+  DeoptimizeIfSmi(receiver, instr);
+  __ CompareObjectType(receiver, result, result, FIRST_SPEC_OBJECT_TYPE);
+  __ B(ge, &copy_receiver);
+  Deoptimize(instr);
+
+  __ Bind(&global_object);
+  __ Ldr(result, FieldMemOperand(function, JSFunction::kContextOffset));
+  __ Ldr(result, ContextMemOperand(result, Context::GLOBAL_OBJECT_INDEX));
+  __ Ldr(result, FieldMemOperand(result, GlobalObject::kGlobalProxyOffset));
+  __ B(&done);
+
+  __ Bind(&copy_receiver);
+  __ Mov(result, receiver);
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
+                                           Register result,
+                                           Register object,
+                                           Register index) {
+  PushSafepointRegistersScope scope(this);
+  __ Push(object);
+  __ Push(index);
+  __ Mov(cp, 0);
+  __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
+  RecordSafepointWithRegisters(
+      instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
+  __ StoreToSafepointRegisterSlot(x0, result);
+}
+
+
+void LCodeGen::DoLoadFieldByIndex(LLoadFieldByIndex* instr) {
+  class DeferredLoadMutableDouble FINAL : public LDeferredCode {
+   public:
+    DeferredLoadMutableDouble(LCodeGen* codegen,
+                              LLoadFieldByIndex* instr,
+                              Register result,
+                              Register object,
+                              Register index)
+        : LDeferredCode(codegen),
+          instr_(instr),
+          result_(result),
+          object_(object),
+          index_(index) {
+    }
+    virtual void Generate() OVERRIDE {
+      codegen()->DoDeferredLoadMutableDouble(instr_, result_, object_, index_);
+    }
+    virtual LInstruction* instr() OVERRIDE { return instr_; }
+   private:
+    LLoadFieldByIndex* instr_;
+    Register result_;
+    Register object_;
+    Register index_;
+  };
+  Register object = ToRegister(instr->object());
+  Register index = ToRegister(instr->index());
+  Register result = ToRegister(instr->result());
+
+  __ AssertSmi(index);
+
+  DeferredLoadMutableDouble* deferred;
+  deferred = new(zone()) DeferredLoadMutableDouble(
+      this, instr, result, object, index);
+
+  Label out_of_object, done;
+
+  __ TestAndBranchIfAnySet(
+      index, reinterpret_cast<uint64_t>(Smi::FromInt(1)), deferred->entry());
+  __ Mov(index, Operand(index, ASR, 1));
+
+  __ Cmp(index, Smi::FromInt(0));
+  __ B(lt, &out_of_object);
+
+  STATIC_ASSERT(kPointerSizeLog2 > kSmiTagSize);
+  __ Add(result, object, Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Ldr(result, FieldMemOperand(result, JSObject::kHeaderSize));
+
+  __ B(&done);
+
+  __ Bind(&out_of_object);
+  __ Ldr(result, FieldMemOperand(object, JSObject::kPropertiesOffset));
+  // Index is equal to negated out of object property index plus 1.
+  __ Sub(result, result, Operand::UntagSmiAndScale(index, kPointerSizeLog2));
+  __ Ldr(result, FieldMemOperand(result,
+                                 FixedArray::kHeaderSize - kPointerSize));
+  __ Bind(deferred->exit());
+  __ Bind(&done);
+}
+
+
+void LCodeGen::DoStoreFrameContext(LStoreFrameContext* instr) {
+  Register context = ToRegister(instr->context());
+  __ Str(context, MemOperand(fp, StandardFrameConstants::kContextOffset));
+}
+
+
+void LCodeGen::DoAllocateBlockContext(LAllocateBlockContext* instr) {
+  Handle<ScopeInfo> scope_info = instr->scope_info();
+  __ Push(scope_info);
+  __ Push(ToRegister(instr->function()));
+  CallRuntime(Runtime::kPushBlockContext, 2, instr);
+  RecordSafepoint(Safepoint::kNoLazyDeopt);
+}
+
+
+
+} }  // namespace v8::internal
diff --git a/src/arm64/lithium-codegen-arm64.h b/src/arm64/lithium-codegen-arm64.h
new file mode 100644
index 0000000..a141dfa
--- /dev/null
+++ b/src/arm64/lithium-codegen-arm64.h
@@ -0,0 +1,473 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_LITHIUM_CODEGEN_ARM64_H_
+#define V8_ARM64_LITHIUM_CODEGEN_ARM64_H_
+
+#include "src/arm64/lithium-arm64.h"
+
+#include "src/arm64/lithium-gap-resolver-arm64.h"
+#include "src/deoptimizer.h"
+#include "src/lithium-codegen.h"
+#include "src/safepoint-table.h"
+#include "src/scopes.h"
+#include "src/utils.h"
+
+namespace v8 {
+namespace internal {
+
+// Forward declarations.
+class LDeferredCode;
+class SafepointGenerator;
+class BranchGenerator;
+
+class LCodeGen: public LCodeGenBase {
+ public:
+  LCodeGen(LChunk* chunk, MacroAssembler* assembler, CompilationInfo* info)
+      : LCodeGenBase(chunk, assembler, info),
+        deoptimizations_(4, info->zone()),
+        jump_table_(4, info->zone()),
+        deoptimization_literals_(8, info->zone()),
+        inlined_function_count_(0),
+        scope_(info->scope()),
+        translations_(info->zone()),
+        deferred_(8, info->zone()),
+        osr_pc_offset_(-1),
+        frame_is_built_(false),
+        safepoints_(info->zone()),
+        resolver_(this),
+        expected_safepoint_kind_(Safepoint::kSimple),
+        after_push_argument_(false),
+        inlined_arguments_(false) {
+    PopulateDeoptimizationLiteralsWithInlinedFunctions();
+  }
+
+  ~LCodeGen() {
+    DCHECK(!after_push_argument_ || inlined_arguments_);
+  }
+
+  // Simple accessors.
+  Scope* scope() const { return scope_; }
+
+  int LookupDestination(int block_id) const {
+    return chunk()->LookupDestination(block_id);
+  }
+
+  bool IsNextEmittedBlock(int block_id) const {
+    return LookupDestination(block_id) == GetNextEmittedBlock();
+  }
+
+  bool NeedsEagerFrame() const {
+    return GetStackSlotCount() > 0 ||
+        info()->is_non_deferred_calling() ||
+        !info()->IsStub() ||
+        info()->requires_frame();
+  }
+  bool NeedsDeferredFrame() const {
+    return !NeedsEagerFrame() && info()->is_deferred_calling();
+  }
+
+  LinkRegisterStatus GetLinkRegisterState() const {
+    return frame_is_built_ ? kLRHasBeenSaved : kLRHasNotBeenSaved;
+  }
+
+  // Try to generate code for the entire chunk, but it may fail if the
+  // chunk contains constructs we cannot handle. Returns true if the
+  // code generation attempt succeeded.
+  bool GenerateCode();
+
+  // Finish the code by setting stack height, safepoint, and bailout
+  // information on it.
+  void FinishCode(Handle<Code> code);
+
+  enum IntegerSignedness { SIGNED_INT32, UNSIGNED_INT32 };
+  // Support for converting LOperands to assembler types.
+  Register ToRegister(LOperand* op) const;
+  Register ToRegister32(LOperand* op) const;
+  Operand ToOperand(LOperand* op);
+  Operand ToOperand32(LOperand* op);
+  enum StackMode { kMustUseFramePointer, kCanUseStackPointer };
+  MemOperand ToMemOperand(LOperand* op,
+                          StackMode stack_mode = kCanUseStackPointer) const;
+  Handle<Object> ToHandle(LConstantOperand* op) const;
+
+  template <class LI>
+  Operand ToShiftedRightOperand32(LOperand* right, LI* shift_info);
+
+  int JSShiftAmountFromLConstant(LOperand* constant) {
+    return ToInteger32(LConstantOperand::cast(constant)) & 0x1f;
+  }
+
+  // TODO(jbramley): Examine these helpers and check that they make sense.
+  // IsInteger32Constant returns true for smi constants, for example.
+  bool IsInteger32Constant(LConstantOperand* op) const;
+  bool IsSmi(LConstantOperand* op) const;
+
+  int32_t ToInteger32(LConstantOperand* op) const;
+  Smi* ToSmi(LConstantOperand* op) const;
+  double ToDouble(LConstantOperand* op) const;
+  DoubleRegister ToDoubleRegister(LOperand* op) const;
+
+  // Declare methods that deal with the individual node types.
+#define DECLARE_DO(type) void Do##type(L##type* node);
+  LITHIUM_CONCRETE_INSTRUCTION_LIST(DECLARE_DO)
+#undef DECLARE_DO
+
+ private:
+  // Return a double scratch register which can be used locally
+  // when generating code for a lithium instruction.
+  DoubleRegister double_scratch() { return crankshaft_fp_scratch; }
+
+  // Deferred code support.
+  void DoDeferredNumberTagD(LNumberTagD* instr);
+  void DoDeferredStackCheck(LStackCheck* instr);
+  void DoDeferredStringCharCodeAt(LStringCharCodeAt* instr);
+  void DoDeferredStringCharFromCode(LStringCharFromCode* instr);
+  void DoDeferredMathAbsTagged(LMathAbsTagged* instr,
+                               Label* exit,
+                               Label* allocation_entry);
+
+  void DoDeferredNumberTagU(LInstruction* instr,
+                            LOperand* value,
+                            LOperand* temp1,
+                            LOperand* temp2);
+  void DoDeferredTaggedToI(LTaggedToI* instr,
+                           LOperand* value,
+                           LOperand* temp1,
+                           LOperand* temp2);
+  void DoDeferredAllocate(LAllocate* instr);
+  void DoDeferredInstanceOfKnownGlobal(LInstanceOfKnownGlobal* instr);
+  void DoDeferredInstanceMigration(LCheckMaps* instr, Register object);
+  void DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
+                                   Register result,
+                                   Register object,
+                                   Register index);
+
+  static Condition TokenToCondition(Token::Value op, bool is_unsigned);
+  void EmitGoto(int block);
+  void DoGap(LGap* instr);
+
+  // Generic version of EmitBranch. It contains some code to avoid emitting a
+  // branch on the next emitted basic block where we could just fall-through.
+  // You shouldn't use that directly but rather consider one of the helper like
+  // LCodeGen::EmitBranch, LCodeGen::EmitCompareAndBranch...
+  template<class InstrType>
+  void EmitBranchGeneric(InstrType instr,
+                         const BranchGenerator& branch);
+
+  template<class InstrType>
+  void EmitBranch(InstrType instr, Condition condition);
+
+  template<class InstrType>
+  void EmitCompareAndBranch(InstrType instr,
+                            Condition condition,
+                            const Register& lhs,
+                            const Operand& rhs);
+
+  template<class InstrType>
+  void EmitTestAndBranch(InstrType instr,
+                         Condition condition,
+                         const Register& value,
+                         uint64_t mask);
+
+  template<class InstrType>
+  void EmitBranchIfNonZeroNumber(InstrType instr,
+                                 const FPRegister& value,
+                                 const FPRegister& scratch);
+
+  template<class InstrType>
+  void EmitBranchIfHeapNumber(InstrType instr,
+                              const Register& value);
+
+  template<class InstrType>
+  void EmitBranchIfRoot(InstrType instr,
+                        const Register& value,
+                        Heap::RootListIndex index);
+
+  // Emits optimized code to deep-copy the contents of statically known object
+  // graphs (e.g. object literal boilerplate). Expects a pointer to the
+  // allocated destination object in the result register, and a pointer to the
+  // source object in the source register.
+  void EmitDeepCopy(Handle<JSObject> object,
+                    Register result,
+                    Register source,
+                    Register scratch,
+                    int* offset,
+                    AllocationSiteMode mode);
+
+  template <class T>
+  void EmitVectorLoadICRegisters(T* instr);
+
+  // Emits optimized code for %_IsString(x).  Preserves input register.
+  // Returns the condition on which a final split to
+  // true and false label should be made, to optimize fallthrough.
+  Condition EmitIsString(Register input, Register temp1, Label* is_not_string,
+                         SmiCheck check_needed);
+
+  int DefineDeoptimizationLiteral(Handle<Object> literal);
+  void PopulateDeoptimizationData(Handle<Code> code);
+  void PopulateDeoptimizationLiteralsWithInlinedFunctions();
+
+  MemOperand BuildSeqStringOperand(Register string,
+                                   Register temp,
+                                   LOperand* index,
+                                   String::Encoding encoding);
+  void DeoptimizeBranch(LInstruction* instr, const char* detail,
+                        BranchType branch_type, Register reg = NoReg,
+                        int bit = -1,
+                        Deoptimizer::BailoutType* override_bailout_type = NULL);
+  void Deoptimize(LInstruction* instr,
+                  Deoptimizer::BailoutType* override_bailout_type = NULL,
+                  const char* detail = NULL);
+  void DeoptimizeIf(Condition cond, LInstruction* instr,
+                    const char* detail = NULL);
+  void DeoptimizeIfZero(Register rt, LInstruction* instr,
+                        const char* detail = NULL);
+  void DeoptimizeIfNotZero(Register rt, LInstruction* instr,
+                           const char* detail = NULL);
+  void DeoptimizeIfNegative(Register rt, LInstruction* instr,
+                            const char* detail = NULL);
+  void DeoptimizeIfSmi(Register rt, LInstruction* instr,
+                       const char* detail = NULL);
+  void DeoptimizeIfNotSmi(Register rt, LInstruction* instr,
+                          const char* detail = NULL);
+  void DeoptimizeIfRoot(Register rt, Heap::RootListIndex index,
+                        LInstruction* instr, const char* detail = NULL);
+  void DeoptimizeIfNotRoot(Register rt, Heap::RootListIndex index,
+                           LInstruction* instr, const char* detail = NULL);
+  void DeoptimizeIfNotHeapNumber(Register object, LInstruction* instr);
+  void DeoptimizeIfMinusZero(DoubleRegister input, LInstruction* instr,
+                             const char* detail = NULL);
+  void DeoptimizeIfBitSet(Register rt, int bit, LInstruction* instr,
+                          const char* detail = NULL);
+  void DeoptimizeIfBitClear(Register rt, int bit, LInstruction* instr,
+                            const char* detail = NULL);
+
+  MemOperand PrepareKeyedExternalArrayOperand(Register key,
+                                              Register base,
+                                              Register scratch,
+                                              bool key_is_smi,
+                                              bool key_is_constant,
+                                              int constant_key,
+                                              ElementsKind elements_kind,
+                                              int base_offset);
+  MemOperand PrepareKeyedArrayOperand(Register base,
+                                      Register elements,
+                                      Register key,
+                                      bool key_is_tagged,
+                                      ElementsKind elements_kind,
+                                      Representation representation,
+                                      int base_offset);
+
+  void RegisterEnvironmentForDeoptimization(LEnvironment* environment,
+                                            Safepoint::DeoptMode mode);
+
+  int GetStackSlotCount() const { return chunk()->spill_slot_count(); }
+
+  void AddDeferredCode(LDeferredCode* code) { deferred_.Add(code, zone()); }
+
+  // Emit frame translation commands for an environment.
+  void WriteTranslation(LEnvironment* environment, Translation* translation);
+
+  void AddToTranslation(LEnvironment* environment,
+                        Translation* translation,
+                        LOperand* op,
+                        bool is_tagged,
+                        bool is_uint32,
+                        int* object_index_pointer,
+                        int* dematerialized_index_pointer);
+
+  void SaveCallerDoubles();
+  void RestoreCallerDoubles();
+
+  // Code generation steps.  Returns true if code generation should continue.
+  void GenerateBodyInstructionPre(LInstruction* instr) OVERRIDE;
+  bool GeneratePrologue();
+  bool GenerateDeferredCode();
+  bool GenerateJumpTable();
+  bool GenerateSafepointTable();
+
+  // Generates the custom OSR entrypoint and sets the osr_pc_offset.
+  void GenerateOsrPrologue();
+
+  enum SafepointMode {
+    RECORD_SIMPLE_SAFEPOINT,
+    RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS
+  };
+
+  void CallCode(Handle<Code> code,
+                RelocInfo::Mode mode,
+                LInstruction* instr);
+
+  void CallCodeGeneric(Handle<Code> code,
+                       RelocInfo::Mode mode,
+                       LInstruction* instr,
+                       SafepointMode safepoint_mode);
+
+  void CallRuntime(const Runtime::Function* function,
+                   int num_arguments,
+                   LInstruction* instr,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
+
+  void CallRuntime(Runtime::FunctionId id,
+                   int num_arguments,
+                   LInstruction* instr) {
+    const Runtime::Function* function = Runtime::FunctionForId(id);
+    CallRuntime(function, num_arguments, instr);
+  }
+
+  void LoadContextFromDeferred(LOperand* context);
+  void CallRuntimeFromDeferred(Runtime::FunctionId id,
+                               int argc,
+                               LInstruction* instr,
+                               LOperand* context);
+
+  // Generate a direct call to a known function.
+  // If the function is already loaded into x1 by the caller, function_reg may
+  // be set to x1. Otherwise, it must be NoReg, and CallKnownFunction will
+  // automatically load it.
+  void CallKnownFunction(Handle<JSFunction> function,
+                         int formal_parameter_count,
+                         int arity,
+                         LInstruction* instr,
+                         Register function_reg = NoReg);
+
+  // Support for recording safepoint and position information.
+  void RecordAndWritePosition(int position) OVERRIDE;
+  void RecordSafepoint(LPointerMap* pointers,
+                       Safepoint::Kind kind,
+                       int arguments,
+                       Safepoint::DeoptMode mode);
+  void RecordSafepoint(LPointerMap* pointers, Safepoint::DeoptMode mode);
+  void RecordSafepoint(Safepoint::DeoptMode mode);
+  void RecordSafepointWithRegisters(LPointerMap* pointers,
+                                    int arguments,
+                                    Safepoint::DeoptMode mode);
+  void RecordSafepointWithLazyDeopt(LInstruction* instr,
+                                    SafepointMode safepoint_mode);
+
+  void EnsureSpaceForLazyDeopt(int space_needed) OVERRIDE;
+
+  ZoneList<LEnvironment*> deoptimizations_;
+  ZoneList<Deoptimizer::JumpTableEntry*> jump_table_;
+  ZoneList<Handle<Object> > deoptimization_literals_;
+  int inlined_function_count_;
+  Scope* const scope_;
+  TranslationBuffer translations_;
+  ZoneList<LDeferredCode*> deferred_;
+  int osr_pc_offset_;
+  bool frame_is_built_;
+
+  // Builder that keeps track of safepoints in the code. The table itself is
+  // emitted at the end of the generated code.
+  SafepointTableBuilder safepoints_;
+
+  // Compiler from a set of parallel moves to a sequential list of moves.
+  LGapResolver resolver_;
+
+  Safepoint::Kind expected_safepoint_kind_;
+
+  // This flag is true when we are after a push (but before a call).
+  // In this situation, jssp no longer references the end of the stack slots so,
+  // we can only reference a stack slot via fp.
+  bool after_push_argument_;
+  // If we have inlined arguments, we are no longer able to use jssp because
+  // jssp is modified and we never know if we are in a block after or before
+  // the pop of the arguments (which restores jssp).
+  bool inlined_arguments_;
+
+  int old_position_;
+
+  class PushSafepointRegistersScope BASE_EMBEDDED {
+   public:
+    explicit PushSafepointRegistersScope(LCodeGen* codegen)
+        : codegen_(codegen) {
+      DCHECK(codegen_->info()->is_calling());
+      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kSimple);
+      codegen_->expected_safepoint_kind_ = Safepoint::kWithRegisters;
+
+      UseScratchRegisterScope temps(codegen_->masm_);
+      // Preserve the value of lr which must be saved on the stack (the call to
+      // the stub will clobber it).
+      Register to_be_pushed_lr =
+          temps.UnsafeAcquire(StoreRegistersStateStub::to_be_pushed_lr());
+      codegen_->masm_->Mov(to_be_pushed_lr, lr);
+      StoreRegistersStateStub stub(codegen_->isolate());
+      codegen_->masm_->CallStub(&stub);
+    }
+
+    ~PushSafepointRegistersScope() {
+      DCHECK(codegen_->expected_safepoint_kind_ == Safepoint::kWithRegisters);
+      RestoreRegistersStateStub stub(codegen_->isolate());
+      codegen_->masm_->CallStub(&stub);
+      codegen_->expected_safepoint_kind_ = Safepoint::kSimple;
+    }
+
+   private:
+    LCodeGen* codegen_;
+  };
+
+  friend class LDeferredCode;
+  friend class SafepointGenerator;
+  DISALLOW_COPY_AND_ASSIGN(LCodeGen);
+};
+
+
+class LDeferredCode: public ZoneObject {
+ public:
+  explicit LDeferredCode(LCodeGen* codegen)
+      : codegen_(codegen),
+        external_exit_(NULL),
+        instruction_index_(codegen->current_instruction_) {
+    codegen->AddDeferredCode(this);
+  }
+
+  virtual ~LDeferredCode() { }
+  virtual void Generate() = 0;
+  virtual LInstruction* instr() = 0;
+
+  void SetExit(Label* exit) { external_exit_ = exit; }
+  Label* entry() { return &entry_; }
+  Label* exit() { return (external_exit_ != NULL) ? external_exit_ : &exit_; }
+  int instruction_index() const { return instruction_index_; }
+
+ protected:
+  LCodeGen* codegen() const { return codegen_; }
+  MacroAssembler* masm() const { return codegen_->masm(); }
+
+ private:
+  LCodeGen* codegen_;
+  Label entry_;
+  Label exit_;
+  Label* external_exit_;
+  int instruction_index_;
+};
+
+
+// This is the abstract class used by EmitBranchGeneric.
+// It is used to emit code for conditional branching. The Emit() function
+// emits code to branch when the condition holds and EmitInverted() emits
+// the branch when the inverted condition is verified.
+//
+// For actual examples of condition see the concrete implementation in
+// lithium-codegen-arm64.cc (e.g. BranchOnCondition, CompareAndBranch).
+class BranchGenerator BASE_EMBEDDED {
+ public:
+  explicit BranchGenerator(LCodeGen* codegen)
+    : codegen_(codegen) { }
+
+  virtual ~BranchGenerator() { }
+
+  virtual void Emit(Label* label) const = 0;
+  virtual void EmitInverted(Label* label) const = 0;
+
+ protected:
+  MacroAssembler* masm() const { return codegen_->masm(); }
+
+  LCodeGen* codegen_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_LITHIUM_CODEGEN_ARM64_H_
diff --git a/src/arm64/lithium-gap-resolver-arm64.cc b/src/arm64/lithium-gap-resolver-arm64.cc
new file mode 100644
index 0000000..d06a37b
--- /dev/null
+++ b/src/arm64/lithium-gap-resolver-arm64.cc
@@ -0,0 +1,295 @@
+// Copyright 2013 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/v8.h"
+
+#include "src/arm64/delayed-masm-arm64-inl.h"
+#include "src/arm64/lithium-codegen-arm64.h"
+#include "src/arm64/lithium-gap-resolver-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+#define __ ACCESS_MASM((&masm_))
+
+
+void DelayedGapMasm::EndDelayedUse() {
+  DelayedMasm::EndDelayedUse();
+  if (scratch_register_used()) {
+    DCHECK(ScratchRegister().Is(root));
+    DCHECK(!pending());
+    InitializeRootRegister();
+    reset_scratch_register_used();
+  }
+}
+
+
+LGapResolver::LGapResolver(LCodeGen* owner)
+    : cgen_(owner), masm_(owner, owner->masm()), moves_(32, owner->zone()),
+      root_index_(0), in_cycle_(false), saved_destination_(NULL) {
+}
+
+
+void LGapResolver::Resolve(LParallelMove* parallel_move) {
+  DCHECK(moves_.is_empty());
+  DCHECK(!masm_.pending());
+
+  // Build up a worklist of moves.
+  BuildInitialMoveList(parallel_move);
+
+  for (int i = 0; i < moves_.length(); ++i) {
+    LMoveOperands move = moves_[i];
+
+    // Skip constants to perform them last. They don't block other moves
+    // and skipping such moves with register destinations keeps those
+    // registers free for the whole algorithm.
+    if (!move.IsEliminated() && !move.source()->IsConstantOperand()) {
+      root_index_ = i;  // Any cycle is found when we reach this move again.
+      PerformMove(i);
+      if (in_cycle_) RestoreValue();
+    }
+  }
+
+  // Perform the moves with constant sources.
+  for (int i = 0; i < moves_.length(); ++i) {
+    LMoveOperands move = moves_[i];
+
+    if (!move.IsEliminated()) {
+      DCHECK(move.source()->IsConstantOperand());
+      EmitMove(i);
+    }
+  }
+
+  __ EndDelayedUse();
+
+  moves_.Rewind(0);
+}
+
+
+void LGapResolver::BuildInitialMoveList(LParallelMove* parallel_move) {
+  // Perform a linear sweep of the moves to add them to the initial list of
+  // moves to perform, ignoring any move that is redundant (the source is
+  // the same as the destination, the destination is ignored and
+  // unallocated, or the move was already eliminated).
+  const ZoneList<LMoveOperands>* moves = parallel_move->move_operands();
+  for (int i = 0; i < moves->length(); ++i) {
+    LMoveOperands move = moves->at(i);
+    if (!move.IsRedundant()) moves_.Add(move, cgen_->zone());
+  }
+  Verify();
+}
+
+
+void LGapResolver::PerformMove(int index) {
+  // Each call to this function performs a move and deletes it from the move
+  // graph. We first recursively perform any move blocking this one. We
+  // mark a move as "pending" on entry to PerformMove in order to detect
+  // cycles in the move graph.
+  LMoveOperands& current_move = moves_[index];
+
+  DCHECK(!current_move.IsPending());
+  DCHECK(!current_move.IsRedundant());
+
+  // Clear this move's destination to indicate a pending move.  The actual
+  // destination is saved in a stack allocated local. Multiple moves can
+  // be pending because this function is recursive.
+  DCHECK(current_move.source() != NULL);  // Otherwise it will look eliminated.
+  LOperand* destination = current_move.destination();
+  current_move.set_destination(NULL);
+
+  // Perform a depth-first traversal of the move graph to resolve
+  // dependencies. Any unperformed, unpending move with a source the same
+  // as this one's destination blocks this one so recursively perform all
+  // such moves.
+  for (int i = 0; i < moves_.length(); ++i) {
+    LMoveOperands other_move = moves_[i];
+    if (other_move.Blocks(destination) && !other_move.IsPending()) {
+      PerformMove(i);
+      // If there is a blocking, pending move it must be moves_[root_index_]
+      // and all other moves with the same source as moves_[root_index_] are
+      // sucessfully executed (because they are cycle-free) by this loop.
+    }
+  }
+
+  // We are about to resolve this move and don't need it marked as
+  // pending, so restore its destination.
+  current_move.set_destination(destination);
+
+  // The move may be blocked on a pending move, which must be the starting move.
+  // In this case, we have a cycle, and we save the source of this move to
+  // a scratch register to break it.
+  LMoveOperands other_move = moves_[root_index_];
+  if (other_move.Blocks(destination)) {
+    DCHECK(other_move.IsPending());
+    BreakCycle(index);
+    return;
+  }
+
+  // This move is no longer blocked.
+  EmitMove(index);
+}
+
+
+void LGapResolver::Verify() {
+#ifdef ENABLE_SLOW_DCHECKS
+  // No operand should be the destination for more than one move.
+  for (int i = 0; i < moves_.length(); ++i) {
+    LOperand* destination = moves_[i].destination();
+    for (int j = i + 1; j < moves_.length(); ++j) {
+      SLOW_DCHECK(!destination->Equals(moves_[j].destination()));
+    }
+  }
+#endif
+}
+
+
+void LGapResolver::BreakCycle(int index) {
+  DCHECK(moves_[index].destination()->Equals(moves_[root_index_].source()));
+  DCHECK(!in_cycle_);
+
+  // We save in a register the source of that move and we remember its
+  // destination. Then we mark this move as resolved so the cycle is
+  // broken and we can perform the other moves.
+  in_cycle_ = true;
+  LOperand* source = moves_[index].source();
+  saved_destination_ = moves_[index].destination();
+
+  if (source->IsRegister()) {
+    AcquireSavedValueRegister();
+    __ Mov(SavedValueRegister(), cgen_->ToRegister(source));
+  } else if (source->IsStackSlot()) {
+    AcquireSavedValueRegister();
+    __ Load(SavedValueRegister(), cgen_->ToMemOperand(source));
+  } else if (source->IsDoubleRegister()) {
+    __ Fmov(SavedFPValueRegister(), cgen_->ToDoubleRegister(source));
+  } else if (source->IsDoubleStackSlot()) {
+    __ Load(SavedFPValueRegister(), cgen_->ToMemOperand(source));
+  } else {
+    UNREACHABLE();
+  }
+
+  // Mark this move as resolved.
+  // This move will be actually performed by moving the saved value to this
+  // move's destination in LGapResolver::RestoreValue().
+  moves_[index].Eliminate();
+}
+
+
+void LGapResolver::RestoreValue() {
+  DCHECK(in_cycle_);
+  DCHECK(saved_destination_ != NULL);
+
+  if (saved_destination_->IsRegister()) {
+    __ Mov(cgen_->ToRegister(saved_destination_), SavedValueRegister());
+    ReleaseSavedValueRegister();
+  } else if (saved_destination_->IsStackSlot()) {
+    __ Store(SavedValueRegister(), cgen_->ToMemOperand(saved_destination_));
+    ReleaseSavedValueRegister();
+  } else if (saved_destination_->IsDoubleRegister()) {
+    __ Fmov(cgen_->ToDoubleRegister(saved_destination_),
+            SavedFPValueRegister());
+  } else if (saved_destination_->IsDoubleStackSlot()) {
+    __ Store(SavedFPValueRegister(), cgen_->ToMemOperand(saved_destination_));
+  } else {
+    UNREACHABLE();
+  }
+
+  in_cycle_ = false;
+  saved_destination_ = NULL;
+}
+
+
+void LGapResolver::EmitMove(int index) {
+  LOperand* source = moves_[index].source();
+  LOperand* destination = moves_[index].destination();
+
+  // Dispatch on the source and destination operand kinds.  Not all
+  // combinations are possible.
+
+  if (source->IsRegister()) {
+    Register source_register = cgen_->ToRegister(source);
+    if (destination->IsRegister()) {
+      __ Mov(cgen_->ToRegister(destination), source_register);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      __ Store(source_register, cgen_->ToMemOperand(destination));
+    }
+
+  } else if (source->IsStackSlot()) {
+    MemOperand source_operand = cgen_->ToMemOperand(source);
+    if (destination->IsRegister()) {
+      __ Load(cgen_->ToRegister(destination), source_operand);
+    } else {
+      DCHECK(destination->IsStackSlot());
+      EmitStackSlotMove(index);
+    }
+
+  } else if (source->IsConstantOperand()) {
+    LConstantOperand* constant_source = LConstantOperand::cast(source);
+    if (destination->IsRegister()) {
+      Register dst = cgen_->ToRegister(destination);
+      if (cgen_->IsSmi(constant_source)) {
+        __ Mov(dst, cgen_->ToSmi(constant_source));
+      } else if (cgen_->IsInteger32Constant(constant_source)) {
+        __ Mov(dst, cgen_->ToInteger32(constant_source));
+      } else {
+        __ LoadObject(dst, cgen_->ToHandle(constant_source));
+      }
+    } else if (destination->IsDoubleRegister()) {
+      DoubleRegister result = cgen_->ToDoubleRegister(destination);
+      __ Fmov(result, cgen_->ToDouble(constant_source));
+    } else {
+      DCHECK(destination->IsStackSlot());
+      DCHECK(!in_cycle_);  // Constant moves happen after all cycles are gone.
+      if (cgen_->IsSmi(constant_source)) {
+        Smi* smi = cgen_->ToSmi(constant_source);
+        __ StoreConstant(reinterpret_cast<intptr_t>(smi),
+                         cgen_->ToMemOperand(destination));
+      } else if (cgen_->IsInteger32Constant(constant_source)) {
+        __ StoreConstant(cgen_->ToInteger32(constant_source),
+                         cgen_->ToMemOperand(destination));
+      } else {
+        Handle<Object> handle = cgen_->ToHandle(constant_source);
+        AllowDeferredHandleDereference smi_object_check;
+        if (handle->IsSmi()) {
+          Object* obj = *handle;
+          DCHECK(!obj->IsHeapObject());
+          __ StoreConstant(reinterpret_cast<intptr_t>(obj),
+                           cgen_->ToMemOperand(destination));
+        } else {
+          AcquireSavedValueRegister();
+          __ LoadObject(SavedValueRegister(), handle);
+          __ Store(SavedValueRegister(), cgen_->ToMemOperand(destination));
+          ReleaseSavedValueRegister();
+        }
+      }
+    }
+
+  } else if (source->IsDoubleRegister()) {
+    DoubleRegister src = cgen_->ToDoubleRegister(source);
+    if (destination->IsDoubleRegister()) {
+      __ Fmov(cgen_->ToDoubleRegister(destination), src);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      __ Store(src, cgen_->ToMemOperand(destination));
+    }
+
+  } else if (source->IsDoubleStackSlot()) {
+    MemOperand src = cgen_->ToMemOperand(source);
+    if (destination->IsDoubleRegister()) {
+      __ Load(cgen_->ToDoubleRegister(destination), src);
+    } else {
+      DCHECK(destination->IsDoubleStackSlot());
+      EmitStackSlotMove(index);
+    }
+
+  } else {
+    UNREACHABLE();
+  }
+
+  // The move has been emitted, we can eliminate it.
+  moves_[index].Eliminate();
+}
+
+} }  // namespace v8::internal
diff --git a/src/arm64/lithium-gap-resolver-arm64.h b/src/arm64/lithium-gap-resolver-arm64.h
new file mode 100644
index 0000000..2eb651b
--- /dev/null
+++ b/src/arm64/lithium-gap-resolver-arm64.h
@@ -0,0 +1,99 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_LITHIUM_GAP_RESOLVER_ARM64_H_
+#define V8_ARM64_LITHIUM_GAP_RESOLVER_ARM64_H_
+
+#include "src/v8.h"
+
+#include "src/arm64/delayed-masm-arm64.h"
+#include "src/lithium.h"
+
+namespace v8 {
+namespace internal {
+
+class LCodeGen;
+class LGapResolver;
+
+class DelayedGapMasm : public DelayedMasm {
+ public:
+  DelayedGapMasm(LCodeGen* owner, MacroAssembler* masm)
+    : DelayedMasm(owner, masm, root) {
+    // We use the root register as an extra scratch register.
+    // The root register has two advantages:
+    //  - It is not in crankshaft allocatable registers list, so it can't
+    //    interfere with the allocatable registers.
+    //  - We don't need to push it on the stack, as we can reload it with its
+    //    value once we have finish.
+  }
+  void EndDelayedUse();
+};
+
+
+class LGapResolver BASE_EMBEDDED {
+ public:
+  explicit LGapResolver(LCodeGen* owner);
+
+  // Resolve a set of parallel moves, emitting assembler instructions.
+  void Resolve(LParallelMove* parallel_move);
+
+ private:
+  // Build the initial list of moves.
+  void BuildInitialMoveList(LParallelMove* parallel_move);
+
+  // Perform the move at the moves_ index in question (possibly requiring
+  // other moves to satisfy dependencies).
+  void PerformMove(int index);
+
+  // If a cycle is found in the series of moves, save the blocking value to
+  // a scratch register.  The cycle must be found by hitting the root of the
+  // depth-first search.
+  void BreakCycle(int index);
+
+  // After a cycle has been resolved, restore the value from the scratch
+  // register to its proper destination.
+  void RestoreValue();
+
+  // Emit a move and remove it from the move graph.
+  void EmitMove(int index);
+
+  // Emit a move from one stack slot to another.
+  void EmitStackSlotMove(int index) {
+    masm_.StackSlotMove(moves_[index].source(), moves_[index].destination());
+  }
+
+  // Verify the move list before performing moves.
+  void Verify();
+
+  // Registers used to solve cycles.
+  const Register& SavedValueRegister() {
+    DCHECK(!masm_.ScratchRegister().IsAllocatable());
+    return masm_.ScratchRegister();
+  }
+  // The scratch register is used to break cycles and to store constant.
+  // These two methods switch from one mode to the other.
+  void AcquireSavedValueRegister() { masm_.AcquireScratchRegister(); }
+  void ReleaseSavedValueRegister() { masm_.ReleaseScratchRegister(); }
+  const FPRegister& SavedFPValueRegister() {
+    // We use the Crankshaft floating-point scratch register to break a cycle
+    // involving double values as the MacroAssembler will not need it for the
+    // operations performed by the gap resolver.
+    DCHECK(!crankshaft_fp_scratch.IsAllocatable());
+    return crankshaft_fp_scratch;
+  }
+
+  LCodeGen* cgen_;
+  DelayedGapMasm masm_;
+
+  // List of moves not yet resolved.
+  ZoneList<LMoveOperands> moves_;
+
+  int root_index_;
+  bool in_cycle_;
+  LOperand* saved_destination_;
+};
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_LITHIUM_GAP_RESOLVER_ARM64_H_
diff --git a/src/arm64/macro-assembler-arm64-inl.h b/src/arm64/macro-assembler-arm64-inl.h
new file mode 100644
index 0000000..23767e4
--- /dev/null
+++ b/src/arm64/macro-assembler-arm64-inl.h
@@ -0,0 +1,1702 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
+#define V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
+
+#include <ctype.h>
+
+#include "src/globals.h"
+
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/arm64/assembler-arm64.h"
+#include "src/arm64/instrument-arm64.h"
+#include "src/arm64/macro-assembler-arm64.h"
+#include "src/base/bits.h"
+
+
+namespace v8 {
+namespace internal {
+
+
+MemOperand FieldMemOperand(Register object, int offset) {
+  return MemOperand(object, offset - kHeapObjectTag);
+}
+
+
+MemOperand UntagSmiFieldMemOperand(Register object, int offset) {
+  return UntagSmiMemOperand(object, offset - kHeapObjectTag);
+}
+
+
+MemOperand UntagSmiMemOperand(Register object, int offset) {
+  // Assumes that Smis are shifted by 32 bits and little endianness.
+  STATIC_ASSERT(kSmiShift == 32);
+  return MemOperand(object, offset + (kSmiShift / kBitsPerByte));
+}
+
+
+Handle<Object> MacroAssembler::CodeObject() {
+  DCHECK(!code_object_.is_null());
+  return code_object_;
+}
+
+
+void MacroAssembler::And(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, AND);
+}
+
+
+void MacroAssembler::Ands(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, ANDS);
+}
+
+
+void MacroAssembler::Tst(const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  LogicalMacro(AppropriateZeroRegFor(rn), rn, operand, ANDS);
+}
+
+
+void MacroAssembler::Bic(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, BIC);
+}
+
+
+void MacroAssembler::Bics(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, BICS);
+}
+
+
+void MacroAssembler::Orr(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, ORR);
+}
+
+
+void MacroAssembler::Orn(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, ORN);
+}
+
+
+void MacroAssembler::Eor(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, EOR);
+}
+
+
+void MacroAssembler::Eon(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  LogicalMacro(rd, rn, operand, EON);
+}
+
+
+void MacroAssembler::Ccmp(const Register& rn,
+                          const Operand& operand,
+                          StatusFlags nzcv,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
+    ConditionalCompareMacro(rn, -operand.ImmediateValue(), nzcv, cond, CCMN);
+  } else {
+    ConditionalCompareMacro(rn, operand, nzcv, cond, CCMP);
+  }
+}
+
+
+void MacroAssembler::Ccmn(const Register& rn,
+                          const Operand& operand,
+                          StatusFlags nzcv,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0)) {
+    ConditionalCompareMacro(rn, -operand.ImmediateValue(), nzcv, cond, CCMP);
+  } else {
+    ConditionalCompareMacro(rn, operand, nzcv, cond, CCMN);
+  }
+}
+
+
+void MacroAssembler::Add(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
+      IsImmAddSub(-operand.ImmediateValue())) {
+    AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, SUB);
+  } else {
+    AddSubMacro(rd, rn, operand, LeaveFlags, ADD);
+  }
+}
+
+void MacroAssembler::Adds(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
+      IsImmAddSub(-operand.ImmediateValue())) {
+    AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, SUB);
+  } else {
+    AddSubMacro(rd, rn, operand, SetFlags, ADD);
+  }
+}
+
+
+void MacroAssembler::Sub(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
+      IsImmAddSub(-operand.ImmediateValue())) {
+    AddSubMacro(rd, rn, -operand.ImmediateValue(), LeaveFlags, ADD);
+  } else {
+    AddSubMacro(rd, rn, operand, LeaveFlags, SUB);
+  }
+}
+
+
+void MacroAssembler::Subs(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  if (operand.IsImmediate() && (operand.ImmediateValue() < 0) &&
+      IsImmAddSub(-operand.ImmediateValue())) {
+    AddSubMacro(rd, rn, -operand.ImmediateValue(), SetFlags, ADD);
+  } else {
+    AddSubMacro(rd, rn, operand, SetFlags, SUB);
+  }
+}
+
+
+void MacroAssembler::Cmn(const Register& rn, const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  Adds(AppropriateZeroRegFor(rn), rn, operand);
+}
+
+
+void MacroAssembler::Cmp(const Register& rn, const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  Subs(AppropriateZeroRegFor(rn), rn, operand);
+}
+
+
+void MacroAssembler::Neg(const Register& rd,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  if (operand.IsImmediate()) {
+    Mov(rd, -operand.ImmediateValue());
+  } else {
+    Sub(rd, AppropriateZeroRegFor(rd), operand);
+  }
+}
+
+
+void MacroAssembler::Negs(const Register& rd,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  Subs(rd, AppropriateZeroRegFor(rd), operand);
+}
+
+
+void MacroAssembler::Adc(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, ADC);
+}
+
+
+void MacroAssembler::Adcs(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  AddSubWithCarryMacro(rd, rn, operand, SetFlags, ADC);
+}
+
+
+void MacroAssembler::Sbc(const Register& rd,
+                         const Register& rn,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  AddSubWithCarryMacro(rd, rn, operand, LeaveFlags, SBC);
+}
+
+
+void MacroAssembler::Sbcs(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  AddSubWithCarryMacro(rd, rn, operand, SetFlags, SBC);
+}
+
+
+void MacroAssembler::Ngc(const Register& rd,
+                         const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  Register zr = AppropriateZeroRegFor(rd);
+  Sbc(rd, zr, operand);
+}
+
+
+void MacroAssembler::Ngcs(const Register& rd,
+                          const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  Register zr = AppropriateZeroRegFor(rd);
+  Sbcs(rd, zr, operand);
+}
+
+
+void MacroAssembler::Mvn(const Register& rd, uint64_t imm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  Mov(rd, ~imm);
+}
+
+
+#define DEFINE_FUNCTION(FN, REGTYPE, REG, OP)                         \
+void MacroAssembler::FN(const REGTYPE REG, const MemOperand& addr) {  \
+  DCHECK(allow_macro_instructions_);                                  \
+  LoadStoreMacro(REG, addr, OP);                                      \
+}
+LS_MACRO_LIST(DEFINE_FUNCTION)
+#undef DEFINE_FUNCTION
+
+
+#define DEFINE_FUNCTION(FN, REGTYPE, REG, REG2, OP)              \
+  void MacroAssembler::FN(const REGTYPE REG, const REGTYPE REG2, \
+                          const MemOperand& addr) {              \
+    DCHECK(allow_macro_instructions_);                           \
+    LoadStorePairMacro(REG, REG2, addr, OP);                     \
+  }
+LSPAIR_MACRO_LIST(DEFINE_FUNCTION)
+#undef DEFINE_FUNCTION
+
+
+void MacroAssembler::Asr(const Register& rd,
+                         const Register& rn,
+                         unsigned shift) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  asr(rd, rn, shift);
+}
+
+
+void MacroAssembler::Asr(const Register& rd,
+                         const Register& rn,
+                         const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  asrv(rd, rn, rm);
+}
+
+
+void MacroAssembler::B(Label* label) {
+  b(label);
+  CheckVeneerPool(false, false);
+}
+
+
+void MacroAssembler::B(Condition cond, Label* label) {
+  DCHECK(allow_macro_instructions_);
+  B(label, cond);
+}
+
+
+void MacroAssembler::Bfi(const Register& rd,
+                         const Register& rn,
+                         unsigned lsb,
+                         unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  bfi(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Bfxil(const Register& rd,
+                           const Register& rn,
+                           unsigned lsb,
+                           unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  bfxil(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Bind(Label* label) {
+  DCHECK(allow_macro_instructions_);
+  bind(label);
+}
+
+
+void MacroAssembler::Bl(Label* label) {
+  DCHECK(allow_macro_instructions_);
+  bl(label);
+}
+
+
+void MacroAssembler::Blr(const Register& xn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!xn.IsZero());
+  blr(xn);
+}
+
+
+void MacroAssembler::Br(const Register& xn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!xn.IsZero());
+  br(xn);
+}
+
+
+void MacroAssembler::Brk(int code) {
+  DCHECK(allow_macro_instructions_);
+  brk(code);
+}
+
+
+void MacroAssembler::Cinc(const Register& rd,
+                          const Register& rn,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  cinc(rd, rn, cond);
+}
+
+
+void MacroAssembler::Cinv(const Register& rd,
+                          const Register& rn,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  cinv(rd, rn, cond);
+}
+
+
+void MacroAssembler::Cls(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  cls(rd, rn);
+}
+
+
+void MacroAssembler::Clz(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  clz(rd, rn);
+}
+
+
+void MacroAssembler::Cneg(const Register& rd,
+                          const Register& rn,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  cneg(rd, rn, cond);
+}
+
+
+// Conditionally zero the destination register. Only X registers are supported
+// due to the truncation side-effect when used on W registers.
+void MacroAssembler::CzeroX(const Register& rd,
+                            Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsSP() && rd.Is64Bits());
+  DCHECK((cond != al) && (cond != nv));
+  csel(rd, xzr, rd, cond);
+}
+
+
+// Conditionally move a value into the destination register. Only X registers
+// are supported due to the truncation side-effect when used on W registers.
+void MacroAssembler::CmovX(const Register& rd,
+                           const Register& rn,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsSP());
+  DCHECK(rd.Is64Bits() && rn.Is64Bits());
+  DCHECK((cond != al) && (cond != nv));
+  if (!rd.is(rn)) {
+    csel(rd, rn, rd, cond);
+  }
+}
+
+
+void MacroAssembler::Cset(const Register& rd, Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  cset(rd, cond);
+}
+
+
+void MacroAssembler::Csetm(const Register& rd, Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  csetm(rd, cond);
+}
+
+
+void MacroAssembler::Csinc(const Register& rd,
+                           const Register& rn,
+                           const Register& rm,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  csinc(rd, rn, rm, cond);
+}
+
+
+void MacroAssembler::Csinv(const Register& rd,
+                           const Register& rn,
+                           const Register& rm,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  csinv(rd, rn, rm, cond);
+}
+
+
+void MacroAssembler::Csneg(const Register& rd,
+                           const Register& rn,
+                           const Register& rm,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  csneg(rd, rn, rm, cond);
+}
+
+
+void MacroAssembler::Dmb(BarrierDomain domain, BarrierType type) {
+  DCHECK(allow_macro_instructions_);
+  dmb(domain, type);
+}
+
+
+void MacroAssembler::Dsb(BarrierDomain domain, BarrierType type) {
+  DCHECK(allow_macro_instructions_);
+  dsb(domain, type);
+}
+
+
+void MacroAssembler::Debug(const char* message, uint32_t code, Instr params) {
+  DCHECK(allow_macro_instructions_);
+  debug(message, code, params);
+}
+
+
+void MacroAssembler::Extr(const Register& rd,
+                          const Register& rn,
+                          const Register& rm,
+                          unsigned lsb) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  extr(rd, rn, rm, lsb);
+}
+
+
+void MacroAssembler::Fabs(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  fabs(fd, fn);
+}
+
+
+void MacroAssembler::Fadd(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fadd(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fccmp(const FPRegister& fn,
+                           const FPRegister& fm,
+                           StatusFlags nzcv,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK((cond != al) && (cond != nv));
+  fccmp(fn, fm, nzcv, cond);
+}
+
+
+void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fcmp(fn, fm);
+}
+
+
+void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
+  DCHECK(allow_macro_instructions_);
+  if (value != 0.0) {
+    UseScratchRegisterScope temps(this);
+    FPRegister tmp = temps.AcquireSameSizeAs(fn);
+    Fmov(tmp, value);
+    fcmp(fn, tmp);
+  } else {
+    fcmp(fn, value);
+  }
+}
+
+
+void MacroAssembler::Fcsel(const FPRegister& fd,
+                           const FPRegister& fn,
+                           const FPRegister& fm,
+                           Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK((cond != al) && (cond != nv));
+  fcsel(fd, fn, fm, cond);
+}
+
+
+void MacroAssembler::Fcvt(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  fcvt(fd, fn);
+}
+
+
+void MacroAssembler::Fcvtas(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtas(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtau(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtau(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtms(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtms(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtmu(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtmu(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtns(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtns(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtnu(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtnu(rd, fn);
+}
+
+
+void MacroAssembler::Fcvtzs(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtzs(rd, fn);
+}
+void MacroAssembler::Fcvtzu(const Register& rd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fcvtzu(rd, fn);
+}
+
+
+void MacroAssembler::Fdiv(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fdiv(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fmadd(const FPRegister& fd,
+                           const FPRegister& fn,
+                           const FPRegister& fm,
+                           const FPRegister& fa) {
+  DCHECK(allow_macro_instructions_);
+  fmadd(fd, fn, fm, fa);
+}
+
+
+void MacroAssembler::Fmax(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fmax(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fmaxnm(const FPRegister& fd,
+                            const FPRegister& fn,
+                            const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fmaxnm(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fmin(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fmin(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fminnm(const FPRegister& fd,
+                            const FPRegister& fn,
+                            const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fminnm(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fmov(FPRegister fd, FPRegister fn) {
+  DCHECK(allow_macro_instructions_);
+  // Only emit an instruction if fd and fn are different, and they are both D
+  // registers. fmov(s0, s0) is not a no-op because it clears the top word of
+  // d0. Technically, fmov(d0, d0) is not a no-op either because it clears the
+  // top of q0, but FPRegister does not currently support Q registers.
+  if (!fd.Is(fn) || !fd.Is64Bits()) {
+    fmov(fd, fn);
+  }
+}
+
+
+void MacroAssembler::Fmov(FPRegister fd, Register rn) {
+  DCHECK(allow_macro_instructions_);
+  fmov(fd, rn);
+}
+
+
+void MacroAssembler::Fmov(FPRegister fd, double imm) {
+  DCHECK(allow_macro_instructions_);
+  if (fd.Is32Bits()) {
+    Fmov(fd, static_cast<float>(imm));
+    return;
+  }
+
+  DCHECK(fd.Is64Bits());
+  if (IsImmFP64(imm)) {
+    fmov(fd, imm);
+  } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
+    fmov(fd, xzr);
+  } else {
+    Ldr(fd, imm);
+  }
+}
+
+
+void MacroAssembler::Fmov(FPRegister fd, float imm) {
+  DCHECK(allow_macro_instructions_);
+  if (fd.Is64Bits()) {
+    Fmov(fd, static_cast<double>(imm));
+    return;
+  }
+
+  DCHECK(fd.Is32Bits());
+  if (IsImmFP32(imm)) {
+    fmov(fd, imm);
+  } else if ((imm == 0.0) && (copysign(1.0, imm) == 1.0)) {
+    fmov(fd, wzr);
+  } else {
+    UseScratchRegisterScope temps(this);
+    Register tmp = temps.AcquireW();
+    // TODO(all): Use Assembler::ldr(const FPRegister& ft, float imm).
+    Mov(tmp, float_to_rawbits(imm));
+    Fmov(fd, tmp);
+  }
+}
+
+
+void MacroAssembler::Fmov(Register rd, FPRegister fn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  fmov(rd, fn);
+}
+
+
+void MacroAssembler::Fmsub(const FPRegister& fd,
+                           const FPRegister& fn,
+                           const FPRegister& fm,
+                           const FPRegister& fa) {
+  DCHECK(allow_macro_instructions_);
+  fmsub(fd, fn, fm, fa);
+}
+
+
+void MacroAssembler::Fmul(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fmul(fd, fn, fm);
+}
+
+
+void MacroAssembler::Fneg(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  fneg(fd, fn);
+}
+
+
+void MacroAssembler::Fnmadd(const FPRegister& fd,
+                            const FPRegister& fn,
+                            const FPRegister& fm,
+                            const FPRegister& fa) {
+  DCHECK(allow_macro_instructions_);
+  fnmadd(fd, fn, fm, fa);
+}
+
+
+void MacroAssembler::Fnmsub(const FPRegister& fd,
+                            const FPRegister& fn,
+                            const FPRegister& fm,
+                            const FPRegister& fa) {
+  DCHECK(allow_macro_instructions_);
+  fnmsub(fd, fn, fm, fa);
+}
+
+
+void MacroAssembler::Frinta(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frinta(fd, fn);
+}
+
+
+void MacroAssembler::Frintm(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frintm(fd, fn);
+}
+
+
+void MacroAssembler::Frintn(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frintn(fd, fn);
+}
+
+
+void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frintz(fd, fn);
+}
+
+
+void MacroAssembler::Fsqrt(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  fsqrt(fd, fn);
+}
+
+
+void MacroAssembler::Fsub(const FPRegister& fd,
+                          const FPRegister& fn,
+                          const FPRegister& fm) {
+  DCHECK(allow_macro_instructions_);
+  fsub(fd, fn, fm);
+}
+
+
+void MacroAssembler::Hint(SystemHint code) {
+  DCHECK(allow_macro_instructions_);
+  hint(code);
+}
+
+
+void MacroAssembler::Hlt(int code) {
+  DCHECK(allow_macro_instructions_);
+  hlt(code);
+}
+
+
+void MacroAssembler::Isb() {
+  DCHECK(allow_macro_instructions_);
+  isb();
+}
+
+
+void MacroAssembler::Ldnp(const CPURegister& rt,
+                          const CPURegister& rt2,
+                          const MemOperand& src) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!AreAliased(rt, rt2));
+  ldnp(rt, rt2, src);
+}
+
+
+void MacroAssembler::Ldr(const CPURegister& rt, const Immediate& imm) {
+  DCHECK(allow_macro_instructions_);
+  ldr(rt, imm);
+}
+
+
+void MacroAssembler::Ldr(const CPURegister& rt, double imm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(rt.Is64Bits());
+  ldr(rt, Immediate(double_to_rawbits(imm)));
+}
+
+
+void MacroAssembler::Lsl(const Register& rd,
+                         const Register& rn,
+                         unsigned shift) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  lsl(rd, rn, shift);
+}
+
+
+void MacroAssembler::Lsl(const Register& rd,
+                         const Register& rn,
+                         const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  lslv(rd, rn, rm);
+}
+
+
+void MacroAssembler::Lsr(const Register& rd,
+                         const Register& rn,
+                         unsigned shift) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  lsr(rd, rn, shift);
+}
+
+
+void MacroAssembler::Lsr(const Register& rd,
+                         const Register& rn,
+                         const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  lsrv(rd, rn, rm);
+}
+
+
+void MacroAssembler::Madd(const Register& rd,
+                          const Register& rn,
+                          const Register& rm,
+                          const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  madd(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Mneg(const Register& rd,
+                          const Register& rn,
+                          const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  mneg(rd, rn, rm);
+}
+
+
+void MacroAssembler::Mov(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  // Emit a register move only if the registers are distinct, or if they are
+  // not X registers. Note that mov(w0, w0) is not a no-op because it clears
+  // the top word of x0.
+  if (!rd.Is(rn) || !rd.Is64Bits()) {
+    Assembler::mov(rd, rn);
+  }
+}
+
+
+void MacroAssembler::Movk(const Register& rd, uint64_t imm, int shift) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  movk(rd, imm, shift);
+}
+
+
+void MacroAssembler::Mrs(const Register& rt, SystemRegister sysreg) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rt.IsZero());
+  mrs(rt, sysreg);
+}
+
+
+void MacroAssembler::Msr(SystemRegister sysreg, const Register& rt) {
+  DCHECK(allow_macro_instructions_);
+  msr(sysreg, rt);
+}
+
+
+void MacroAssembler::Msub(const Register& rd,
+                          const Register& rn,
+                          const Register& rm,
+                          const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  msub(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Mul(const Register& rd,
+                         const Register& rn,
+                         const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  mul(rd, rn, rm);
+}
+
+
+void MacroAssembler::Rbit(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  rbit(rd, rn);
+}
+
+
+void MacroAssembler::Ret(const Register& xn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!xn.IsZero());
+  ret(xn);
+  CheckVeneerPool(false, false);
+}
+
+
+void MacroAssembler::Rev(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  rev(rd, rn);
+}
+
+
+void MacroAssembler::Rev16(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  rev16(rd, rn);
+}
+
+
+void MacroAssembler::Rev32(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  rev32(rd, rn);
+}
+
+
+void MacroAssembler::Ror(const Register& rd,
+                         const Register& rs,
+                         unsigned shift) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  ror(rd, rs, shift);
+}
+
+
+void MacroAssembler::Ror(const Register& rd,
+                         const Register& rn,
+                         const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  rorv(rd, rn, rm);
+}
+
+
+void MacroAssembler::Sbfiz(const Register& rd,
+                           const Register& rn,
+                           unsigned lsb,
+                           unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sbfiz(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Sbfx(const Register& rd,
+                          const Register& rn,
+                          unsigned lsb,
+                          unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sbfx(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Scvtf(const FPRegister& fd,
+                           const Register& rn,
+                           unsigned fbits) {
+  DCHECK(allow_macro_instructions_);
+  scvtf(fd, rn, fbits);
+}
+
+
+void MacroAssembler::Sdiv(const Register& rd,
+                          const Register& rn,
+                          const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sdiv(rd, rn, rm);
+}
+
+
+void MacroAssembler::Smaddl(const Register& rd,
+                            const Register& rn,
+                            const Register& rm,
+                            const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  smaddl(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Smsubl(const Register& rd,
+                            const Register& rn,
+                            const Register& rm,
+                            const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  smsubl(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Smull(const Register& rd,
+                           const Register& rn,
+                           const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  smull(rd, rn, rm);
+}
+
+
+void MacroAssembler::Smulh(const Register& rd,
+                           const Register& rn,
+                           const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  smulh(rd, rn, rm);
+}
+
+
+void MacroAssembler::Stnp(const CPURegister& rt,
+                          const CPURegister& rt2,
+                          const MemOperand& dst) {
+  DCHECK(allow_macro_instructions_);
+  stnp(rt, rt2, dst);
+}
+
+
+void MacroAssembler::Sxtb(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sxtb(rd, rn);
+}
+
+
+void MacroAssembler::Sxth(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sxth(rd, rn);
+}
+
+
+void MacroAssembler::Sxtw(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  sxtw(rd, rn);
+}
+
+
+void MacroAssembler::Ubfiz(const Register& rd,
+                           const Register& rn,
+                           unsigned lsb,
+                           unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  ubfiz(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Ubfx(const Register& rd,
+                          const Register& rn,
+                          unsigned lsb,
+                          unsigned width) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  ubfx(rd, rn, lsb, width);
+}
+
+
+void MacroAssembler::Ucvtf(const FPRegister& fd,
+                           const Register& rn,
+                           unsigned fbits) {
+  DCHECK(allow_macro_instructions_);
+  ucvtf(fd, rn, fbits);
+}
+
+
+void MacroAssembler::Udiv(const Register& rd,
+                          const Register& rn,
+                          const Register& rm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  udiv(rd, rn, rm);
+}
+
+
+void MacroAssembler::Umaddl(const Register& rd,
+                            const Register& rn,
+                            const Register& rm,
+                            const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  umaddl(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Umsubl(const Register& rd,
+                            const Register& rn,
+                            const Register& rm,
+                            const Register& ra) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  umsubl(rd, rn, rm, ra);
+}
+
+
+void MacroAssembler::Uxtb(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  uxtb(rd, rn);
+}
+
+
+void MacroAssembler::Uxth(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  uxth(rd, rn);
+}
+
+
+void MacroAssembler::Uxtw(const Register& rd, const Register& rn) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  uxtw(rd, rn);
+}
+
+
+void MacroAssembler::BumpSystemStackPointer(const Operand& space) {
+  DCHECK(!csp.Is(sp_));
+  if (!TmpList()->IsEmpty()) {
+    if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+      UseScratchRegisterScope temps(this);
+      Register temp = temps.AcquireX();
+      Sub(temp, StackPointer(), space);
+      Bic(csp, temp, 0xf);
+    } else {
+      Sub(csp, StackPointer(), space);
+    }
+  } else {
+    // TODO(jbramley): Several callers rely on this not using scratch
+    // registers, so we use the assembler directly here. However, this means
+    // that large immediate values of 'space' cannot be handled cleanly. (Only
+    // 24-bits immediates or values of 'space' that can be encoded in one
+    // instruction are accepted.) Once we implement our flexible scratch
+    // register idea, we could greatly simplify this function.
+    InstructionAccurateScope scope(this);
+    DCHECK(space.IsImmediate());
+    // Align to 16 bytes.
+    uint64_t imm = RoundUp(space.ImmediateValue(), 0x10);
+    DCHECK(is_uint24(imm));
+
+    Register source = StackPointer();
+    if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+      bic(csp, source, 0xf);
+      source = csp;
+    }
+    if (!is_uint12(imm)) {
+      int64_t imm_top_12_bits = imm >> 12;
+      sub(csp, source, imm_top_12_bits << 12);
+      source = csp;
+      imm -= imm_top_12_bits << 12;
+    }
+    if (imm > 0) {
+      sub(csp, source, imm);
+    }
+  }
+  AssertStackConsistency();
+}
+
+
+void MacroAssembler::SyncSystemStackPointer() {
+  DCHECK(emit_debug_code());
+  DCHECK(!csp.Is(sp_));
+  { InstructionAccurateScope scope(this);
+    if (CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+      bic(csp, StackPointer(), 0xf);
+    } else {
+      mov(csp, StackPointer());
+    }
+  }
+  AssertStackConsistency();
+}
+
+
+void MacroAssembler::InitializeRootRegister() {
+  ExternalReference roots_array_start =
+      ExternalReference::roots_array_start(isolate());
+  Mov(root, Operand(roots_array_start));
+}
+
+
+void MacroAssembler::SmiTag(Register dst, Register src) {
+  STATIC_ASSERT(kXRegSizeInBits ==
+                static_cast<unsigned>(kSmiShift + kSmiValueSize));
+  DCHECK(dst.Is64Bits() && src.Is64Bits());
+  Lsl(dst, src, kSmiShift);
+}
+
+
+void MacroAssembler::SmiTag(Register smi) { SmiTag(smi, smi); }
+
+
+void MacroAssembler::SmiUntag(Register dst, Register src) {
+  STATIC_ASSERT(kXRegSizeInBits ==
+                static_cast<unsigned>(kSmiShift + kSmiValueSize));
+  DCHECK(dst.Is64Bits() && src.Is64Bits());
+  if (FLAG_enable_slow_asserts) {
+    AssertSmi(src);
+  }
+  Asr(dst, src, kSmiShift);
+}
+
+
+void MacroAssembler::SmiUntag(Register smi) { SmiUntag(smi, smi); }
+
+
+void MacroAssembler::SmiUntagToDouble(FPRegister dst,
+                                      Register src,
+                                      UntagMode mode) {
+  DCHECK(dst.Is64Bits() && src.Is64Bits());
+  if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
+    AssertSmi(src);
+  }
+  Scvtf(dst, src, kSmiShift);
+}
+
+
+void MacroAssembler::SmiUntagToFloat(FPRegister dst,
+                                     Register src,
+                                     UntagMode mode) {
+  DCHECK(dst.Is32Bits() && src.Is64Bits());
+  if (FLAG_enable_slow_asserts && (mode == kNotSpeculativeUntag)) {
+    AssertSmi(src);
+  }
+  Scvtf(dst, src, kSmiShift);
+}
+
+
+void MacroAssembler::SmiTagAndPush(Register src) {
+  STATIC_ASSERT((static_cast<unsigned>(kSmiShift) == kWRegSizeInBits) &&
+                (static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits) &&
+                (kSmiTag == 0));
+  Push(src.W(), wzr);
+}
+
+
+void MacroAssembler::SmiTagAndPush(Register src1, Register src2) {
+  STATIC_ASSERT((static_cast<unsigned>(kSmiShift) == kWRegSizeInBits) &&
+                (static_cast<unsigned>(kSmiValueSize) == kWRegSizeInBits) &&
+                (kSmiTag == 0));
+  Push(src1.W(), wzr, src2.W(), wzr);
+}
+
+
+void MacroAssembler::JumpIfSmi(Register value,
+                               Label* smi_label,
+                               Label* not_smi_label) {
+  STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
+  // Check if the tag bit is set.
+  if (smi_label) {
+    Tbz(value, 0, smi_label);
+    if (not_smi_label) {
+      B(not_smi_label);
+    }
+  } else {
+    DCHECK(not_smi_label);
+    Tbnz(value, 0, not_smi_label);
+  }
+}
+
+
+void MacroAssembler::JumpIfNotSmi(Register value, Label* not_smi_label) {
+  JumpIfSmi(value, NULL, not_smi_label);
+}
+
+
+void MacroAssembler::JumpIfBothSmi(Register value1,
+                                   Register value2,
+                                   Label* both_smi_label,
+                                   Label* not_smi_label) {
+  STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
+  UseScratchRegisterScope temps(this);
+  Register tmp = temps.AcquireX();
+  // Check if both tag bits are clear.
+  Orr(tmp, value1, value2);
+  JumpIfSmi(tmp, both_smi_label, not_smi_label);
+}
+
+
+void MacroAssembler::JumpIfEitherSmi(Register value1,
+                                     Register value2,
+                                     Label* either_smi_label,
+                                     Label* not_smi_label) {
+  STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
+  UseScratchRegisterScope temps(this);
+  Register tmp = temps.AcquireX();
+  // Check if either tag bit is clear.
+  And(tmp, value1, value2);
+  JumpIfSmi(tmp, either_smi_label, not_smi_label);
+}
+
+
+void MacroAssembler::JumpIfEitherNotSmi(Register value1,
+                                        Register value2,
+                                        Label* not_smi_label) {
+  JumpIfBothSmi(value1, value2, NULL, not_smi_label);
+}
+
+
+void MacroAssembler::JumpIfBothNotSmi(Register value1,
+                                      Register value2,
+                                      Label* not_smi_label) {
+  JumpIfEitherSmi(value1, value2, NULL, not_smi_label);
+}
+
+
+void MacroAssembler::ObjectTag(Register tagged_obj, Register obj) {
+  STATIC_ASSERT(kHeapObjectTag == 1);
+  if (emit_debug_code()) {
+    Label ok;
+    Tbz(obj, 0, &ok);
+    Abort(kObjectTagged);
+    Bind(&ok);
+  }
+  Orr(tagged_obj, obj, kHeapObjectTag);
+}
+
+
+void MacroAssembler::ObjectUntag(Register untagged_obj, Register obj) {
+  STATIC_ASSERT(kHeapObjectTag == 1);
+  if (emit_debug_code()) {
+    Label ok;
+    Tbnz(obj, 0, &ok);
+    Abort(kObjectNotTagged);
+    Bind(&ok);
+  }
+  Bic(untagged_obj, obj, kHeapObjectTag);
+}
+
+
+void MacroAssembler::IsObjectNameType(Register object,
+                                      Register type,
+                                      Label* fail) {
+  CompareObjectType(object, type, type, LAST_NAME_TYPE);
+  B(hi, fail);
+}
+
+
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+                                          Register map,
+                                          Register scratch,
+                                          Label* fail) {
+  Ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+  IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+                                            Register scratch,
+                                            Label* fail) {
+  Ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  // If cmp result is lt, the following ccmp will clear all flags.
+  // Z == 0, N == V implies gt condition.
+  Cmp(scratch, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
+  Ccmp(scratch, LAST_NONCALLABLE_SPEC_OBJECT_TYPE, NoFlag, ge);
+
+  // If we didn't get a valid label object just fall through and leave the
+  // flags updated.
+  if (fail != NULL) {
+    B(gt, fail);
+  }
+}
+
+
+void MacroAssembler::IsObjectJSStringType(Register object,
+                                          Register type,
+                                          Label* not_string,
+                                          Label* string) {
+  Ldr(type, FieldMemOperand(object, HeapObject::kMapOffset));
+  Ldrb(type.W(), FieldMemOperand(type, Map::kInstanceTypeOffset));
+
+  STATIC_ASSERT(kStringTag == 0);
+  DCHECK((string != NULL) || (not_string != NULL));
+  if (string == NULL) {
+    TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
+  } else if (not_string == NULL) {
+    TestAndBranchIfAllClear(type.W(), kIsNotStringMask, string);
+  } else {
+    TestAndBranchIfAnySet(type.W(), kIsNotStringMask, not_string);
+    B(string);
+  }
+}
+
+
+void MacroAssembler::Push(Handle<Object> handle) {
+  UseScratchRegisterScope temps(this);
+  Register tmp = temps.AcquireX();
+  Mov(tmp, Operand(handle));
+  Push(tmp);
+}
+
+
+void MacroAssembler::Claim(uint64_t count, uint64_t unit_size) {
+  uint64_t size = count * unit_size;
+
+  if (size == 0) {
+    return;
+  }
+
+  if (csp.Is(StackPointer())) {
+    DCHECK(size % 16 == 0);
+  } else {
+    BumpSystemStackPointer(size);
+  }
+
+  Sub(StackPointer(), StackPointer(), size);
+}
+
+
+void MacroAssembler::Claim(const Register& count, uint64_t unit_size) {
+  if (unit_size == 0) return;
+  DCHECK(base::bits::IsPowerOfTwo64(unit_size));
+
+  const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
+  const Operand size(count, LSL, shift);
+
+  if (size.IsZero()) {
+    return;
+  }
+
+  if (!csp.Is(StackPointer())) {
+    BumpSystemStackPointer(size);
+  }
+
+  Sub(StackPointer(), StackPointer(), size);
+}
+
+
+void MacroAssembler::ClaimBySMI(const Register& count_smi, uint64_t unit_size) {
+  DCHECK(unit_size == 0 || base::bits::IsPowerOfTwo64(unit_size));
+  const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
+  const Operand size(count_smi,
+                     (shift >= 0) ? (LSL) : (LSR),
+                     (shift >= 0) ? (shift) : (-shift));
+
+  if (size.IsZero()) {
+    return;
+  }
+
+  if (!csp.Is(StackPointer())) {
+    BumpSystemStackPointer(size);
+  }
+
+  Sub(StackPointer(), StackPointer(), size);
+}
+
+
+void MacroAssembler::Drop(uint64_t count, uint64_t unit_size) {
+  uint64_t size = count * unit_size;
+
+  if (size == 0) {
+    return;
+  }
+
+  Add(StackPointer(), StackPointer(), size);
+
+  if (csp.Is(StackPointer())) {
+    DCHECK(size % 16 == 0);
+  } else if (emit_debug_code()) {
+    // It is safe to leave csp where it is when unwinding the JavaScript stack,
+    // but if we keep it matching StackPointer, the simulator can detect memory
+    // accesses in the now-free part of the stack.
+    SyncSystemStackPointer();
+  }
+}
+
+
+void MacroAssembler::Drop(const Register& count, uint64_t unit_size) {
+  if (unit_size == 0) return;
+  DCHECK(base::bits::IsPowerOfTwo64(unit_size));
+
+  const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits);
+  const Operand size(count, LSL, shift);
+
+  if (size.IsZero()) {
+    return;
+  }
+
+  Add(StackPointer(), StackPointer(), size);
+
+  if (!csp.Is(StackPointer()) && emit_debug_code()) {
+    // It is safe to leave csp where it is when unwinding the JavaScript stack,
+    // but if we keep it matching StackPointer, the simulator can detect memory
+    // accesses in the now-free part of the stack.
+    SyncSystemStackPointer();
+  }
+}
+
+
+void MacroAssembler::DropBySMI(const Register& count_smi, uint64_t unit_size) {
+  DCHECK(unit_size == 0 || base::bits::IsPowerOfTwo64(unit_size));
+  const int shift = CountTrailingZeros(unit_size, kXRegSizeInBits) - kSmiShift;
+  const Operand size(count_smi,
+                     (shift >= 0) ? (LSL) : (LSR),
+                     (shift >= 0) ? (shift) : (-shift));
+
+  if (size.IsZero()) {
+    return;
+  }
+
+  Add(StackPointer(), StackPointer(), size);
+
+  if (!csp.Is(StackPointer()) && emit_debug_code()) {
+    // It is safe to leave csp where it is when unwinding the JavaScript stack,
+    // but if we keep it matching StackPointer, the simulator can detect memory
+    // accesses in the now-free part of the stack.
+    SyncSystemStackPointer();
+  }
+}
+
+
+void MacroAssembler::CompareAndBranch(const Register& lhs,
+                                      const Operand& rhs,
+                                      Condition cond,
+                                      Label* label) {
+  if (rhs.IsImmediate() && (rhs.ImmediateValue() == 0) &&
+      ((cond == eq) || (cond == ne))) {
+    if (cond == eq) {
+      Cbz(lhs, label);
+    } else {
+      Cbnz(lhs, label);
+    }
+  } else {
+    Cmp(lhs, rhs);
+    B(cond, label);
+  }
+}
+
+
+void MacroAssembler::TestAndBranchIfAnySet(const Register& reg,
+                                           const uint64_t bit_pattern,
+                                           Label* label) {
+  int bits = reg.SizeInBits();
+  DCHECK(CountSetBits(bit_pattern, bits) > 0);
+  if (CountSetBits(bit_pattern, bits) == 1) {
+    Tbnz(reg, MaskToBit(bit_pattern), label);
+  } else {
+    Tst(reg, bit_pattern);
+    B(ne, label);
+  }
+}
+
+
+void MacroAssembler::TestAndBranchIfAllClear(const Register& reg,
+                                             const uint64_t bit_pattern,
+                                             Label* label) {
+  int bits = reg.SizeInBits();
+  DCHECK(CountSetBits(bit_pattern, bits) > 0);
+  if (CountSetBits(bit_pattern, bits) == 1) {
+    Tbz(reg, MaskToBit(bit_pattern), label);
+  } else {
+    Tst(reg, bit_pattern);
+    B(eq, label);
+  }
+}
+
+
+void MacroAssembler::InlineData(uint64_t data) {
+  DCHECK(is_uint16(data));
+  InstructionAccurateScope scope(this, 1);
+  movz(xzr, data);
+}
+
+
+void MacroAssembler::EnableInstrumentation() {
+  InstructionAccurateScope scope(this, 1);
+  movn(xzr, InstrumentStateEnable);
+}
+
+
+void MacroAssembler::DisableInstrumentation() {
+  InstructionAccurateScope scope(this, 1);
+  movn(xzr, InstrumentStateDisable);
+}
+
+
+void MacroAssembler::AnnotateInstrumentation(const char* marker_name) {
+  DCHECK(strlen(marker_name) == 2);
+
+  // We allow only printable characters in the marker names. Unprintable
+  // characters are reserved for controlling features of the instrumentation.
+  DCHECK(isprint(marker_name[0]) && isprint(marker_name[1]));
+
+  InstructionAccurateScope scope(this, 1);
+  movn(xzr, (marker_name[1] << 8) | marker_name[0]);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_MACRO_ASSEMBLER_ARM64_INL_H_
diff --git a/src/arm64/macro-assembler-arm64.cc b/src/arm64/macro-assembler-arm64.cc
new file mode 100644
index 0000000..f670403
--- /dev/null
+++ b/src/arm64/macro-assembler-arm64.cc
@@ -0,0 +1,5390 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
+#include "src/bootstrapper.h"
+#include "src/codegen.h"
+#include "src/cpu-profiler.h"
+#include "src/debug.h"
+#include "src/isolate-inl.h"
+#include "src/runtime.h"
+
+namespace v8 {
+namespace internal {
+
+// Define a fake double underscore to use with the ASM_UNIMPLEMENTED macros.
+#define __
+
+
+MacroAssembler::MacroAssembler(Isolate* arg_isolate,
+                               byte * buffer,
+                               unsigned buffer_size)
+    : Assembler(arg_isolate, buffer, buffer_size),
+      generating_stub_(false),
+#if DEBUG
+      allow_macro_instructions_(true),
+#endif
+      has_frame_(false),
+      use_real_aborts_(true),
+      sp_(jssp),
+      tmp_list_(DefaultTmpList()),
+      fptmp_list_(DefaultFPTmpList()) {
+  if (isolate() != NULL) {
+    code_object_ = Handle<Object>(isolate()->heap()->undefined_value(),
+                                  isolate());
+  }
+}
+
+
+CPURegList MacroAssembler::DefaultTmpList() {
+  return CPURegList(ip0, ip1);
+}
+
+
+CPURegList MacroAssembler::DefaultFPTmpList() {
+  return CPURegList(fp_scratch1, fp_scratch2);
+}
+
+
+void MacroAssembler::LogicalMacro(const Register& rd,
+                                  const Register& rn,
+                                  const Operand& operand,
+                                  LogicalOp op) {
+  UseScratchRegisterScope temps(this);
+
+  if (operand.NeedsRelocation(this)) {
+    Register temp = temps.AcquireX();
+    Ldr(temp, operand.immediate());
+    Logical(rd, rn, temp, op);
+
+  } else if (operand.IsImmediate()) {
+    int64_t immediate = operand.ImmediateValue();
+    unsigned reg_size = rd.SizeInBits();
+
+    // If the operation is NOT, invert the operation and immediate.
+    if ((op & NOT) == NOT) {
+      op = static_cast<LogicalOp>(op & ~NOT);
+      immediate = ~immediate;
+    }
+
+    // Ignore the top 32 bits of an immediate if we're moving to a W register.
+    if (rd.Is32Bits()) {
+      // Check that the top 32 bits are consistent.
+      DCHECK(((immediate >> kWRegSizeInBits) == 0) ||
+             ((immediate >> kWRegSizeInBits) == -1));
+      immediate &= kWRegMask;
+    }
+
+    DCHECK(rd.Is64Bits() || is_uint32(immediate));
+
+    // Special cases for all set or all clear immediates.
+    if (immediate == 0) {
+      switch (op) {
+        case AND:
+          Mov(rd, 0);
+          return;
+        case ORR:  // Fall through.
+        case EOR:
+          Mov(rd, rn);
+          return;
+        case ANDS:  // Fall through.
+        case BICS:
+          break;
+        default:
+          UNREACHABLE();
+      }
+    } else if ((rd.Is64Bits() && (immediate == -1L)) ||
+               (rd.Is32Bits() && (immediate == 0xffffffffL))) {
+      switch (op) {
+        case AND:
+          Mov(rd, rn);
+          return;
+        case ORR:
+          Mov(rd, immediate);
+          return;
+        case EOR:
+          Mvn(rd, rn);
+          return;
+        case ANDS:  // Fall through.
+        case BICS:
+          break;
+        default:
+          UNREACHABLE();
+      }
+    }
+
+    unsigned n, imm_s, imm_r;
+    if (IsImmLogical(immediate, reg_size, &n, &imm_s, &imm_r)) {
+      // Immediate can be encoded in the instruction.
+      LogicalImmediate(rd, rn, n, imm_s, imm_r, op);
+    } else {
+      // Immediate can't be encoded: synthesize using move immediate.
+      Register temp = temps.AcquireSameSizeAs(rn);
+      Operand imm_operand = MoveImmediateForShiftedOp(temp, immediate);
+      if (rd.Is(csp)) {
+        // If rd is the stack pointer we cannot use it as the destination
+        // register so we use the temp register as an intermediate again.
+        Logical(temp, rn, imm_operand, op);
+        Mov(csp, temp);
+        AssertStackConsistency();
+      } else {
+        Logical(rd, rn, imm_operand, op);
+      }
+    }
+
+  } else if (operand.IsExtendedRegister()) {
+    DCHECK(operand.reg().SizeInBits() <= rd.SizeInBits());
+    // Add/sub extended supports shift <= 4. We want to support exactly the
+    // same modes here.
+    DCHECK(operand.shift_amount() <= 4);
+    DCHECK(operand.reg().Is64Bits() ||
+           ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
+    Register temp = temps.AcquireSameSizeAs(rn);
+    EmitExtendShift(temp, operand.reg(), operand.extend(),
+                    operand.shift_amount());
+    Logical(rd, rn, temp, op);
+
+  } else {
+    // The operand can be encoded in the instruction.
+    DCHECK(operand.IsShiftedRegister());
+    Logical(rd, rn, operand, op);
+  }
+}
+
+
+void MacroAssembler::Mov(const Register& rd, uint64_t imm) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(is_uint32(imm) || is_int32(imm) || rd.Is64Bits());
+  DCHECK(!rd.IsZero());
+
+  // TODO(all) extend to support more immediates.
+  //
+  // Immediates on Aarch64 can be produced using an initial value, and zero to
+  // three move keep operations.
+  //
+  // Initial values can be generated with:
+  //  1. 64-bit move zero (movz).
+  //  2. 32-bit move inverted (movn).
+  //  3. 64-bit move inverted.
+  //  4. 32-bit orr immediate.
+  //  5. 64-bit orr immediate.
+  // Move-keep may then be used to modify each of the 16-bit half-words.
+  //
+  // The code below supports all five initial value generators, and
+  // applying move-keep operations to move-zero and move-inverted initial
+  // values.
+
+  // Try to move the immediate in one instruction, and if that fails, switch to
+  // using multiple instructions.
+  if (!TryOneInstrMoveImmediate(rd, imm)) {
+    unsigned reg_size = rd.SizeInBits();
+
+    // Generic immediate case. Imm will be represented by
+    //   [imm3, imm2, imm1, imm0], where each imm is 16 bits.
+    // A move-zero or move-inverted is generated for the first non-zero or
+    // non-0xffff immX, and a move-keep for subsequent non-zero immX.
+
+    uint64_t ignored_halfword = 0;
+    bool invert_move = false;
+    // If the number of 0xffff halfwords is greater than the number of 0x0000
+    // halfwords, it's more efficient to use move-inverted.
+    if (CountClearHalfWords(~imm, reg_size) >
+        CountClearHalfWords(imm, reg_size)) {
+      ignored_halfword = 0xffffL;
+      invert_move = true;
+    }
+
+    // Mov instructions can't move immediate values into the stack pointer, so
+    // set up a temporary register, if needed.
+    UseScratchRegisterScope temps(this);
+    Register temp = rd.IsSP() ? temps.AcquireSameSizeAs(rd) : rd;
+
+    // Iterate through the halfwords. Use movn/movz for the first non-ignored
+    // halfword, and movk for subsequent halfwords.
+    DCHECK((reg_size % 16) == 0);
+    bool first_mov_done = false;
+    for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) {
+      uint64_t imm16 = (imm >> (16 * i)) & 0xffffL;
+      if (imm16 != ignored_halfword) {
+        if (!first_mov_done) {
+          if (invert_move) {
+            movn(temp, (~imm16) & 0xffffL, 16 * i);
+          } else {
+            movz(temp, imm16, 16 * i);
+          }
+          first_mov_done = true;
+        } else {
+          // Construct a wider constant.
+          movk(temp, imm16, 16 * i);
+        }
+      }
+    }
+    DCHECK(first_mov_done);
+
+    // Move the temporary if the original destination register was the stack
+    // pointer.
+    if (rd.IsSP()) {
+      mov(rd, temp);
+      AssertStackConsistency();
+    }
+  }
+}
+
+
+void MacroAssembler::Mov(const Register& rd,
+                         const Operand& operand,
+                         DiscardMoveMode discard_mode) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+
+  // Provide a swap register for instructions that need to write into the
+  // system stack pointer (and can't do this inherently).
+  UseScratchRegisterScope temps(this);
+  Register dst = (rd.IsSP()) ? temps.AcquireSameSizeAs(rd) : rd;
+
+  if (operand.NeedsRelocation(this)) {
+    Ldr(dst, operand.immediate());
+
+  } else if (operand.IsImmediate()) {
+    // Call the macro assembler for generic immediates.
+    Mov(dst, operand.ImmediateValue());
+
+  } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
+    // Emit a shift instruction if moving a shifted register. This operation
+    // could also be achieved using an orr instruction (like orn used by Mvn),
+    // but using a shift instruction makes the disassembly clearer.
+    EmitShift(dst, operand.reg(), operand.shift(), operand.shift_amount());
+
+  } else if (operand.IsExtendedRegister()) {
+    // Emit an extend instruction if moving an extended register. This handles
+    // extend with post-shift operations, too.
+    EmitExtendShift(dst, operand.reg(), operand.extend(),
+                    operand.shift_amount());
+
+  } else {
+    // Otherwise, emit a register move only if the registers are distinct, or
+    // if they are not X registers.
+    //
+    // Note that mov(w0, w0) is not a no-op because it clears the top word of
+    // x0. A flag is provided (kDiscardForSameWReg) if a move between the same W
+    // registers is not required to clear the top word of the X register. In
+    // this case, the instruction is discarded.
+    //
+    // If csp is an operand, add #0 is emitted, otherwise, orr #0.
+    if (!rd.Is(operand.reg()) || (rd.Is32Bits() &&
+                                  (discard_mode == kDontDiscardForSameWReg))) {
+      Assembler::mov(rd, operand.reg());
+    }
+    // This case can handle writes into the system stack pointer directly.
+    dst = rd;
+  }
+
+  // Copy the result to the system stack pointer.
+  if (!dst.Is(rd)) {
+    DCHECK(rd.IsSP());
+    Assembler::mov(rd, dst);
+  }
+}
+
+
+void MacroAssembler::Mvn(const Register& rd, const Operand& operand) {
+  DCHECK(allow_macro_instructions_);
+
+  if (operand.NeedsRelocation(this)) {
+    Ldr(rd, operand.immediate());
+    mvn(rd, rd);
+
+  } else if (operand.IsImmediate()) {
+    // Call the macro assembler for generic immediates.
+    Mov(rd, ~operand.ImmediateValue());
+
+  } else if (operand.IsExtendedRegister()) {
+    // Emit two instructions for the extend case. This differs from Mov, as
+    // the extend and invert can't be achieved in one instruction.
+    EmitExtendShift(rd, operand.reg(), operand.extend(),
+                    operand.shift_amount());
+    mvn(rd, rd);
+
+  } else {
+    mvn(rd, operand);
+  }
+}
+
+
+unsigned MacroAssembler::CountClearHalfWords(uint64_t imm, unsigned reg_size) {
+  DCHECK((reg_size % 8) == 0);
+  int count = 0;
+  for (unsigned i = 0; i < (reg_size / 16); i++) {
+    if ((imm & 0xffff) == 0) {
+      count++;
+    }
+    imm >>= 16;
+  }
+  return count;
+}
+
+
+// The movz instruction can generate immediates containing an arbitrary 16-bit
+// half-word, with remaining bits clear, eg. 0x00001234, 0x0000123400000000.
+bool MacroAssembler::IsImmMovz(uint64_t imm, unsigned reg_size) {
+  DCHECK((reg_size == kXRegSizeInBits) || (reg_size == kWRegSizeInBits));
+  return CountClearHalfWords(imm, reg_size) >= ((reg_size / 16) - 1);
+}
+
+
+// The movn instruction can generate immediates containing an arbitrary 16-bit
+// half-word, with remaining bits set, eg. 0xffff1234, 0xffff1234ffffffff.
+bool MacroAssembler::IsImmMovn(uint64_t imm, unsigned reg_size) {
+  return IsImmMovz(~imm, reg_size);
+}
+
+
+void MacroAssembler::ConditionalCompareMacro(const Register& rn,
+                                             const Operand& operand,
+                                             StatusFlags nzcv,
+                                             Condition cond,
+                                             ConditionalCompareOp op) {
+  DCHECK((cond != al) && (cond != nv));
+  if (operand.NeedsRelocation(this)) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+    Ldr(temp, operand.immediate());
+    ConditionalCompareMacro(rn, temp, nzcv, cond, op);
+
+  } else if ((operand.IsShiftedRegister() && (operand.shift_amount() == 0)) ||
+             (operand.IsImmediate() &&
+              IsImmConditionalCompare(operand.ImmediateValue()))) {
+    // The immediate can be encoded in the instruction, or the operand is an
+    // unshifted register: call the assembler.
+    ConditionalCompare(rn, operand, nzcv, cond, op);
+
+  } else {
+    // The operand isn't directly supported by the instruction: perform the
+    // operation on a temporary register.
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireSameSizeAs(rn);
+    Mov(temp, operand);
+    ConditionalCompare(rn, temp, nzcv, cond, op);
+  }
+}
+
+
+void MacroAssembler::Csel(const Register& rd,
+                          const Register& rn,
+                          const Operand& operand,
+                          Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+  DCHECK((cond != al) && (cond != nv));
+  if (operand.IsImmediate()) {
+    // Immediate argument. Handle special cases of 0, 1 and -1 using zero
+    // register.
+    int64_t imm = operand.ImmediateValue();
+    Register zr = AppropriateZeroRegFor(rn);
+    if (imm == 0) {
+      csel(rd, rn, zr, cond);
+    } else if (imm == 1) {
+      csinc(rd, rn, zr, cond);
+    } else if (imm == -1) {
+      csinv(rd, rn, zr, cond);
+    } else {
+      UseScratchRegisterScope temps(this);
+      Register temp = temps.AcquireSameSizeAs(rn);
+      Mov(temp, imm);
+      csel(rd, rn, temp, cond);
+    }
+  } else if (operand.IsShiftedRegister() && (operand.shift_amount() == 0)) {
+    // Unshifted register argument.
+    csel(rd, rn, operand.reg(), cond);
+  } else {
+    // All other arguments.
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireSameSizeAs(rn);
+    Mov(temp, operand);
+    csel(rd, rn, temp, cond);
+  }
+}
+
+
+bool MacroAssembler::TryOneInstrMoveImmediate(const Register& dst,
+                                              int64_t imm) {
+  unsigned n, imm_s, imm_r;
+  int reg_size = dst.SizeInBits();
+  if (IsImmMovz(imm, reg_size) && !dst.IsSP()) {
+    // Immediate can be represented in a move zero instruction. Movz can't write
+    // to the stack pointer.
+    movz(dst, imm);
+    return true;
+  } else if (IsImmMovn(imm, reg_size) && !dst.IsSP()) {
+    // Immediate can be represented in a move not instruction. Movn can't write
+    // to the stack pointer.
+    movn(dst, dst.Is64Bits() ? ~imm : (~imm & kWRegMask));
+    return true;
+  } else if (IsImmLogical(imm, reg_size, &n, &imm_s, &imm_r)) {
+    // Immediate can be represented in a logical orr instruction.
+    LogicalImmediate(dst, AppropriateZeroRegFor(dst), n, imm_s, imm_r, ORR);
+    return true;
+  }
+  return false;
+}
+
+
+Operand MacroAssembler::MoveImmediateForShiftedOp(const Register& dst,
+                                                  int64_t imm) {
+  int reg_size = dst.SizeInBits();
+
+  // Encode the immediate in a single move instruction, if possible.
+  if (TryOneInstrMoveImmediate(dst, imm)) {
+    // The move was successful; nothing to do here.
+  } else {
+    // Pre-shift the immediate to the least-significant bits of the register.
+    int shift_low = CountTrailingZeros(imm, reg_size);
+    int64_t imm_low = imm >> shift_low;
+
+    // Pre-shift the immediate to the most-significant bits of the register. We
+    // insert set bits in the least-significant bits, as this creates a
+    // different immediate that may be encodable using movn or orr-immediate.
+    // If this new immediate is encodable, the set bits will be eliminated by
+    // the post shift on the following instruction.
+    int shift_high = CountLeadingZeros(imm, reg_size);
+    int64_t imm_high = (imm << shift_high) | ((1 << shift_high) - 1);
+
+    if (TryOneInstrMoveImmediate(dst, imm_low)) {
+      // The new immediate has been moved into the destination's low bits:
+      // return a new leftward-shifting operand.
+      return Operand(dst, LSL, shift_low);
+    } else if (TryOneInstrMoveImmediate(dst, imm_high)) {
+      // The new immediate has been moved into the destination's high bits:
+      // return a new rightward-shifting operand.
+      return Operand(dst, LSR, shift_high);
+    } else {
+      // Use the generic move operation to set up the immediate.
+      Mov(dst, imm);
+    }
+  }
+  return Operand(dst);
+}
+
+
+void MacroAssembler::AddSubMacro(const Register& rd,
+                                 const Register& rn,
+                                 const Operand& operand,
+                                 FlagsUpdate S,
+                                 AddSubOp op) {
+  if (operand.IsZero() && rd.Is(rn) && rd.Is64Bits() && rn.Is64Bits() &&
+      !operand.NeedsRelocation(this) && (S == LeaveFlags)) {
+    // The instruction would be a nop. Avoid generating useless code.
+    return;
+  }
+
+  if (operand.NeedsRelocation(this)) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+    Ldr(temp, operand.immediate());
+    AddSubMacro(rd, rn, temp, S, op);
+  } else if ((operand.IsImmediate() &&
+              !IsImmAddSub(operand.ImmediateValue()))      ||
+             (rn.IsZero() && !operand.IsShiftedRegister()) ||
+             (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireSameSizeAs(rn);
+    if (operand.IsImmediate()) {
+      Operand imm_operand =
+          MoveImmediateForShiftedOp(temp, operand.ImmediateValue());
+      AddSub(rd, rn, imm_operand, S, op);
+    } else {
+      Mov(temp, operand);
+      AddSub(rd, rn, temp, S, op);
+    }
+  } else {
+    AddSub(rd, rn, operand, S, op);
+  }
+}
+
+
+void MacroAssembler::AddSubWithCarryMacro(const Register& rd,
+                                          const Register& rn,
+                                          const Operand& operand,
+                                          FlagsUpdate S,
+                                          AddSubWithCarryOp op) {
+  DCHECK(rd.SizeInBits() == rn.SizeInBits());
+  UseScratchRegisterScope temps(this);
+
+  if (operand.NeedsRelocation(this)) {
+    Register temp = temps.AcquireX();
+    Ldr(temp, operand.immediate());
+    AddSubWithCarryMacro(rd, rn, temp, S, op);
+
+  } else if (operand.IsImmediate() ||
+             (operand.IsShiftedRegister() && (operand.shift() == ROR))) {
+    // Add/sub with carry (immediate or ROR shifted register.)
+    Register temp = temps.AcquireSameSizeAs(rn);
+    Mov(temp, operand);
+    AddSubWithCarry(rd, rn, temp, S, op);
+
+  } else if (operand.IsShiftedRegister() && (operand.shift_amount() != 0)) {
+    // Add/sub with carry (shifted register).
+    DCHECK(operand.reg().SizeInBits() == rd.SizeInBits());
+    DCHECK(operand.shift() != ROR);
+    DCHECK(is_uintn(operand.shift_amount(),
+          rd.SizeInBits() == kXRegSizeInBits ? kXRegSizeInBitsLog2
+                                             : kWRegSizeInBitsLog2));
+    Register temp = temps.AcquireSameSizeAs(rn);
+    EmitShift(temp, operand.reg(), operand.shift(), operand.shift_amount());
+    AddSubWithCarry(rd, rn, temp, S, op);
+
+  } else if (operand.IsExtendedRegister()) {
+    // Add/sub with carry (extended register).
+    DCHECK(operand.reg().SizeInBits() <= rd.SizeInBits());
+    // Add/sub extended supports a shift <= 4. We want to support exactly the
+    // same modes.
+    DCHECK(operand.shift_amount() <= 4);
+    DCHECK(operand.reg().Is64Bits() ||
+           ((operand.extend() != UXTX) && (operand.extend() != SXTX)));
+    Register temp = temps.AcquireSameSizeAs(rn);
+    EmitExtendShift(temp, operand.reg(), operand.extend(),
+                    operand.shift_amount());
+    AddSubWithCarry(rd, rn, temp, S, op);
+
+  } else {
+    // The addressing mode is directly supported by the instruction.
+    AddSubWithCarry(rd, rn, operand, S, op);
+  }
+}
+
+
+void MacroAssembler::LoadStoreMacro(const CPURegister& rt,
+                                    const MemOperand& addr,
+                                    LoadStoreOp op) {
+  int64_t offset = addr.offset();
+  LSDataSize size = CalcLSDataSize(op);
+
+  // Check if an immediate offset fits in the immediate field of the
+  // appropriate instruction. If not, emit two instructions to perform
+  // the operation.
+  if (addr.IsImmediateOffset() && !IsImmLSScaled(offset, size) &&
+      !IsImmLSUnscaled(offset)) {
+    // Immediate offset that can't be encoded using unsigned or unscaled
+    // addressing modes.
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireSameSizeAs(addr.base());
+    Mov(temp, addr.offset());
+    LoadStore(rt, MemOperand(addr.base(), temp), op);
+  } else if (addr.IsPostIndex() && !IsImmLSUnscaled(offset)) {
+    // Post-index beyond unscaled addressing range.
+    LoadStore(rt, MemOperand(addr.base()), op);
+    add(addr.base(), addr.base(), offset);
+  } else if (addr.IsPreIndex() && !IsImmLSUnscaled(offset)) {
+    // Pre-index beyond unscaled addressing range.
+    add(addr.base(), addr.base(), offset);
+    LoadStore(rt, MemOperand(addr.base()), op);
+  } else {
+    // Encodable in one load/store instruction.
+    LoadStore(rt, addr, op);
+  }
+}
+
+void MacroAssembler::LoadStorePairMacro(const CPURegister& rt,
+                                        const CPURegister& rt2,
+                                        const MemOperand& addr,
+                                        LoadStorePairOp op) {
+  // TODO(all): Should we support register offset for load-store-pair?
+  DCHECK(!addr.IsRegisterOffset());
+
+  int64_t offset = addr.offset();
+  LSDataSize size = CalcLSPairDataSize(op);
+
+  // Check if the offset fits in the immediate field of the appropriate
+  // instruction. If not, emit two instructions to perform the operation.
+  if (IsImmLSPair(offset, size)) {
+    // Encodable in one load/store pair instruction.
+    LoadStorePair(rt, rt2, addr, op);
+  } else {
+    Register base = addr.base();
+    if (addr.IsImmediateOffset()) {
+      UseScratchRegisterScope temps(this);
+      Register temp = temps.AcquireSameSizeAs(base);
+      Add(temp, base, offset);
+      LoadStorePair(rt, rt2, MemOperand(temp), op);
+    } else if (addr.IsPostIndex()) {
+      LoadStorePair(rt, rt2, MemOperand(base), op);
+      Add(base, base, offset);
+    } else {
+      DCHECK(addr.IsPreIndex());
+      Add(base, base, offset);
+      LoadStorePair(rt, rt2, MemOperand(base), op);
+    }
+  }
+}
+
+
+void MacroAssembler::Load(const Register& rt,
+                          const MemOperand& addr,
+                          Representation r) {
+  DCHECK(!r.IsDouble());
+
+  if (r.IsInteger8()) {
+    Ldrsb(rt, addr);
+  } else if (r.IsUInteger8()) {
+    Ldrb(rt, addr);
+  } else if (r.IsInteger16()) {
+    Ldrsh(rt, addr);
+  } else if (r.IsUInteger16()) {
+    Ldrh(rt, addr);
+  } else if (r.IsInteger32()) {
+    Ldr(rt.W(), addr);
+  } else {
+    DCHECK(rt.Is64Bits());
+    Ldr(rt, addr);
+  }
+}
+
+
+void MacroAssembler::Store(const Register& rt,
+                           const MemOperand& addr,
+                           Representation r) {
+  DCHECK(!r.IsDouble());
+
+  if (r.IsInteger8() || r.IsUInteger8()) {
+    Strb(rt, addr);
+  } else if (r.IsInteger16() || r.IsUInteger16()) {
+    Strh(rt, addr);
+  } else if (r.IsInteger32()) {
+    Str(rt.W(), addr);
+  } else {
+    DCHECK(rt.Is64Bits());
+    if (r.IsHeapObject()) {
+      AssertNotSmi(rt);
+    } else if (r.IsSmi()) {
+      AssertSmi(rt);
+    }
+    Str(rt, addr);
+  }
+}
+
+
+bool MacroAssembler::NeedExtraInstructionsOrRegisterBranch(
+    Label *label, ImmBranchType b_type) {
+  bool need_longer_range = false;
+  // There are two situations in which we care about the offset being out of
+  // range:
+  //  - The label is bound but too far away.
+  //  - The label is not bound but linked, and the previous branch
+  //    instruction in the chain is too far away.
+  if (label->is_bound() || label->is_linked()) {
+    need_longer_range =
+      !Instruction::IsValidImmPCOffset(b_type, label->pos() - pc_offset());
+  }
+  if (!need_longer_range && !label->is_bound()) {
+    int max_reachable_pc = pc_offset() + Instruction::ImmBranchRange(b_type);
+    unresolved_branches_.insert(
+        std::pair<int, FarBranchInfo>(max_reachable_pc,
+                                      FarBranchInfo(pc_offset(), label)));
+    // Also maintain the next pool check.
+    next_veneer_pool_check_ =
+      Min(next_veneer_pool_check_,
+          max_reachable_pc - kVeneerDistanceCheckMargin);
+  }
+  return need_longer_range;
+}
+
+
+void MacroAssembler::Adr(const Register& rd, Label* label, AdrHint hint) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(!rd.IsZero());
+
+  if (hint == kAdrNear) {
+    adr(rd, label);
+    return;
+  }
+
+  DCHECK(hint == kAdrFar);
+  if (label->is_bound()) {
+    int label_offset = label->pos() - pc_offset();
+    if (Instruction::IsValidPCRelOffset(label_offset)) {
+      adr(rd, label);
+    } else {
+      DCHECK(label_offset <= 0);
+      int min_adr_offset = -(1 << (Instruction::ImmPCRelRangeBitwidth - 1));
+      adr(rd, min_adr_offset);
+      Add(rd, rd, label_offset - min_adr_offset);
+    }
+  } else {
+    UseScratchRegisterScope temps(this);
+    Register scratch = temps.AcquireX();
+
+    InstructionAccurateScope scope(
+        this, PatchingAssembler::kAdrFarPatchableNInstrs);
+    adr(rd, label);
+    for (int i = 0; i < PatchingAssembler::kAdrFarPatchableNNops; ++i) {
+      nop(ADR_FAR_NOP);
+    }
+    movz(scratch, 0);
+  }
+}
+
+
+void MacroAssembler::B(Label* label, BranchType type, Register reg, int bit) {
+  DCHECK((reg.Is(NoReg) || type >= kBranchTypeFirstUsingReg) &&
+         (bit == -1 || type >= kBranchTypeFirstUsingBit));
+  if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
+    B(static_cast<Condition>(type), label);
+  } else {
+    switch (type) {
+      case always:        B(label);              break;
+      case never:         break;
+      case reg_zero:      Cbz(reg, label);       break;
+      case reg_not_zero:  Cbnz(reg, label);      break;
+      case reg_bit_clear: Tbz(reg, bit, label);  break;
+      case reg_bit_set:   Tbnz(reg, bit, label); break;
+      default:
+        UNREACHABLE();
+    }
+  }
+}
+
+
+void MacroAssembler::B(Label* label, Condition cond) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK((cond != al) && (cond != nv));
+
+  Label done;
+  bool need_extra_instructions =
+    NeedExtraInstructionsOrRegisterBranch(label, CondBranchType);
+
+  if (need_extra_instructions) {
+    b(&done, NegateCondition(cond));
+    B(label);
+  } else {
+    b(label, cond);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::Tbnz(const Register& rt, unsigned bit_pos, Label* label) {
+  DCHECK(allow_macro_instructions_);
+
+  Label done;
+  bool need_extra_instructions =
+    NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
+
+  if (need_extra_instructions) {
+    tbz(rt, bit_pos, &done);
+    B(label);
+  } else {
+    tbnz(rt, bit_pos, label);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::Tbz(const Register& rt, unsigned bit_pos, Label* label) {
+  DCHECK(allow_macro_instructions_);
+
+  Label done;
+  bool need_extra_instructions =
+    NeedExtraInstructionsOrRegisterBranch(label, TestBranchType);
+
+  if (need_extra_instructions) {
+    tbnz(rt, bit_pos, &done);
+    B(label);
+  } else {
+    tbz(rt, bit_pos, label);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::Cbnz(const Register& rt, Label* label) {
+  DCHECK(allow_macro_instructions_);
+
+  Label done;
+  bool need_extra_instructions =
+    NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
+
+  if (need_extra_instructions) {
+    cbz(rt, &done);
+    B(label);
+  } else {
+    cbnz(rt, label);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::Cbz(const Register& rt, Label* label) {
+  DCHECK(allow_macro_instructions_);
+
+  Label done;
+  bool need_extra_instructions =
+    NeedExtraInstructionsOrRegisterBranch(label, CompareBranchType);
+
+  if (need_extra_instructions) {
+    cbnz(rt, &done);
+    B(label);
+  } else {
+    cbz(rt, label);
+  }
+  bind(&done);
+}
+
+
+// Pseudo-instructions.
+
+
+void MacroAssembler::Abs(const Register& rd, const Register& rm,
+                         Label* is_not_representable,
+                         Label* is_representable) {
+  DCHECK(allow_macro_instructions_);
+  DCHECK(AreSameSizeAndType(rd, rm));
+
+  Cmp(rm, 1);
+  Cneg(rd, rm, lt);
+
+  // If the comparison sets the v flag, the input was the smallest value
+  // representable by rm, and the mathematical result of abs(rm) is not
+  // representable using two's complement.
+  if ((is_not_representable != NULL) && (is_representable != NULL)) {
+    B(is_not_representable, vs);
+    B(is_representable);
+  } else if (is_not_representable != NULL) {
+    B(is_not_representable, vs);
+  } else if (is_representable != NULL) {
+    B(is_representable, vc);
+  }
+}
+
+
+// Abstracted stack operations.
+
+
+void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
+                          const CPURegister& src2, const CPURegister& src3) {
+  DCHECK(AreSameSizeAndType(src0, src1, src2, src3));
+
+  int count = 1 + src1.IsValid() + src2.IsValid() + src3.IsValid();
+  int size = src0.SizeInBytes();
+
+  PushPreamble(count, size);
+  PushHelper(count, size, src0, src1, src2, src3);
+}
+
+
+void MacroAssembler::Push(const CPURegister& src0, const CPURegister& src1,
+                          const CPURegister& src2, const CPURegister& src3,
+                          const CPURegister& src4, const CPURegister& src5,
+                          const CPURegister& src6, const CPURegister& src7) {
+  DCHECK(AreSameSizeAndType(src0, src1, src2, src3, src4, src5, src6, src7));
+
+  int count = 5 + src5.IsValid() + src6.IsValid() + src6.IsValid();
+  int size = src0.SizeInBytes();
+
+  PushPreamble(count, size);
+  PushHelper(4, size, src0, src1, src2, src3);
+  PushHelper(count - 4, size, src4, src5, src6, src7);
+}
+
+
+void MacroAssembler::Pop(const CPURegister& dst0, const CPURegister& dst1,
+                         const CPURegister& dst2, const CPURegister& dst3) {
+  // It is not valid to pop into the same register more than once in one
+  // instruction, not even into the zero register.
+  DCHECK(!AreAliased(dst0, dst1, dst2, dst3));
+  DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3));
+  DCHECK(dst0.IsValid());
+
+  int count = 1 + dst1.IsValid() + dst2.IsValid() + dst3.IsValid();
+  int size = dst0.SizeInBytes();
+
+  PopHelper(count, size, dst0, dst1, dst2, dst3);
+  PopPostamble(count, size);
+}
+
+
+void MacroAssembler::Push(const Register& src0, const FPRegister& src1) {
+  int size = src0.SizeInBytes() + src1.SizeInBytes();
+
+  PushPreamble(size);
+  // Reserve room for src0 and push src1.
+  str(src1, MemOperand(StackPointer(), -size, PreIndex));
+  // Fill the gap with src0.
+  str(src0, MemOperand(StackPointer(), src1.SizeInBytes()));
+}
+
+
+void MacroAssembler::PushPopQueue::PushQueued(
+    PreambleDirective preamble_directive) {
+  if (queued_.empty()) return;
+
+  if (preamble_directive == WITH_PREAMBLE) {
+    masm_->PushPreamble(size_);
+  }
+
+  int count = queued_.size();
+  int index = 0;
+  while (index < count) {
+    // PushHelper can only handle registers with the same size and type, and it
+    // can handle only four at a time. Batch them up accordingly.
+    CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg};
+    int batch_index = 0;
+    do {
+      batch[batch_index++] = queued_[index++];
+    } while ((batch_index < 4) && (index < count) &&
+             batch[0].IsSameSizeAndType(queued_[index]));
+
+    masm_->PushHelper(batch_index, batch[0].SizeInBytes(),
+                      batch[0], batch[1], batch[2], batch[3]);
+  }
+
+  queued_.clear();
+}
+
+
+void MacroAssembler::PushPopQueue::PopQueued() {
+  if (queued_.empty()) return;
+
+  int count = queued_.size();
+  int index = 0;
+  while (index < count) {
+    // PopHelper can only handle registers with the same size and type, and it
+    // can handle only four at a time. Batch them up accordingly.
+    CPURegister batch[4] = {NoReg, NoReg, NoReg, NoReg};
+    int batch_index = 0;
+    do {
+      batch[batch_index++] = queued_[index++];
+    } while ((batch_index < 4) && (index < count) &&
+             batch[0].IsSameSizeAndType(queued_[index]));
+
+    masm_->PopHelper(batch_index, batch[0].SizeInBytes(),
+                     batch[0], batch[1], batch[2], batch[3]);
+  }
+
+  masm_->PopPostamble(size_);
+  queued_.clear();
+}
+
+
+void MacroAssembler::PushCPURegList(CPURegList registers) {
+  int size = registers.RegisterSizeInBytes();
+
+  PushPreamble(registers.Count(), size);
+  // Push up to four registers at a time because if the current stack pointer is
+  // csp and reg_size is 32, registers must be pushed in blocks of four in order
+  // to maintain the 16-byte alignment for csp.
+  while (!registers.IsEmpty()) {
+    int count_before = registers.Count();
+    const CPURegister& src0 = registers.PopHighestIndex();
+    const CPURegister& src1 = registers.PopHighestIndex();
+    const CPURegister& src2 = registers.PopHighestIndex();
+    const CPURegister& src3 = registers.PopHighestIndex();
+    int count = count_before - registers.Count();
+    PushHelper(count, size, src0, src1, src2, src3);
+  }
+}
+
+
+void MacroAssembler::PopCPURegList(CPURegList registers) {
+  int size = registers.RegisterSizeInBytes();
+
+  // Pop up to four registers at a time because if the current stack pointer is
+  // csp and reg_size is 32, registers must be pushed in blocks of four in
+  // order to maintain the 16-byte alignment for csp.
+  while (!registers.IsEmpty()) {
+    int count_before = registers.Count();
+    const CPURegister& dst0 = registers.PopLowestIndex();
+    const CPURegister& dst1 = registers.PopLowestIndex();
+    const CPURegister& dst2 = registers.PopLowestIndex();
+    const CPURegister& dst3 = registers.PopLowestIndex();
+    int count = count_before - registers.Count();
+    PopHelper(count, size, dst0, dst1, dst2, dst3);
+  }
+  PopPostamble(registers.Count(), size);
+}
+
+
+void MacroAssembler::PushMultipleTimes(CPURegister src, int count) {
+  int size = src.SizeInBytes();
+
+  PushPreamble(count, size);
+
+  if (FLAG_optimize_for_size && count > 8) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    Label loop;
+    __ Mov(temp, count / 2);
+    __ Bind(&loop);
+    PushHelper(2, size, src, src, NoReg, NoReg);
+    __ Subs(temp, temp, 1);
+    __ B(ne, &loop);
+
+    count %= 2;
+  }
+
+  // Push up to four registers at a time if possible because if the current
+  // stack pointer is csp and the register size is 32, registers must be pushed
+  // in blocks of four in order to maintain the 16-byte alignment for csp.
+  while (count >= 4) {
+    PushHelper(4, size, src, src, src, src);
+    count -= 4;
+  }
+  if (count >= 2) {
+    PushHelper(2, size, src, src, NoReg, NoReg);
+    count -= 2;
+  }
+  if (count == 1) {
+    PushHelper(1, size, src, NoReg, NoReg, NoReg);
+    count -= 1;
+  }
+  DCHECK(count == 0);
+}
+
+
+void MacroAssembler::PushMultipleTimes(CPURegister src, Register count) {
+  PushPreamble(Operand(count, UXTW, WhichPowerOf2(src.SizeInBytes())));
+
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireSameSizeAs(count);
+
+  if (FLAG_optimize_for_size) {
+    Label loop, done;
+
+    Subs(temp, count, 1);
+    B(mi, &done);
+
+    // Push all registers individually, to save code size.
+    Bind(&loop);
+    Subs(temp, temp, 1);
+    PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
+    B(pl, &loop);
+
+    Bind(&done);
+  } else {
+    Label loop, leftover2, leftover1, done;
+
+    Subs(temp, count, 4);
+    B(mi, &leftover2);
+
+    // Push groups of four first.
+    Bind(&loop);
+    Subs(temp, temp, 4);
+    PushHelper(4, src.SizeInBytes(), src, src, src, src);
+    B(pl, &loop);
+
+    // Push groups of two.
+    Bind(&leftover2);
+    Tbz(count, 1, &leftover1);
+    PushHelper(2, src.SizeInBytes(), src, src, NoReg, NoReg);
+
+    // Push the last one (if required).
+    Bind(&leftover1);
+    Tbz(count, 0, &done);
+    PushHelper(1, src.SizeInBytes(), src, NoReg, NoReg, NoReg);
+
+    Bind(&done);
+  }
+}
+
+
+void MacroAssembler::PushHelper(int count, int size,
+                                const CPURegister& src0,
+                                const CPURegister& src1,
+                                const CPURegister& src2,
+                                const CPURegister& src3) {
+  // Ensure that we don't unintentially modify scratch or debug registers.
+  InstructionAccurateScope scope(this);
+
+  DCHECK(AreSameSizeAndType(src0, src1, src2, src3));
+  DCHECK(size == src0.SizeInBytes());
+
+  // When pushing multiple registers, the store order is chosen such that
+  // Push(a, b) is equivalent to Push(a) followed by Push(b).
+  switch (count) {
+    case 1:
+      DCHECK(src1.IsNone() && src2.IsNone() && src3.IsNone());
+      str(src0, MemOperand(StackPointer(), -1 * size, PreIndex));
+      break;
+    case 2:
+      DCHECK(src2.IsNone() && src3.IsNone());
+      stp(src1, src0, MemOperand(StackPointer(), -2 * size, PreIndex));
+      break;
+    case 3:
+      DCHECK(src3.IsNone());
+      stp(src2, src1, MemOperand(StackPointer(), -3 * size, PreIndex));
+      str(src0, MemOperand(StackPointer(), 2 * size));
+      break;
+    case 4:
+      // Skip over 4 * size, then fill in the gap. This allows four W registers
+      // to be pushed using csp, whilst maintaining 16-byte alignment for csp
+      // at all times.
+      stp(src3, src2, MemOperand(StackPointer(), -4 * size, PreIndex));
+      stp(src1, src0, MemOperand(StackPointer(), 2 * size));
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void MacroAssembler::PopHelper(int count, int size,
+                               const CPURegister& dst0,
+                               const CPURegister& dst1,
+                               const CPURegister& dst2,
+                               const CPURegister& dst3) {
+  // Ensure that we don't unintentially modify scratch or debug registers.
+  InstructionAccurateScope scope(this);
+
+  DCHECK(AreSameSizeAndType(dst0, dst1, dst2, dst3));
+  DCHECK(size == dst0.SizeInBytes());
+
+  // When popping multiple registers, the load order is chosen such that
+  // Pop(a, b) is equivalent to Pop(a) followed by Pop(b).
+  switch (count) {
+    case 1:
+      DCHECK(dst1.IsNone() && dst2.IsNone() && dst3.IsNone());
+      ldr(dst0, MemOperand(StackPointer(), 1 * size, PostIndex));
+      break;
+    case 2:
+      DCHECK(dst2.IsNone() && dst3.IsNone());
+      ldp(dst0, dst1, MemOperand(StackPointer(), 2 * size, PostIndex));
+      break;
+    case 3:
+      DCHECK(dst3.IsNone());
+      ldr(dst2, MemOperand(StackPointer(), 2 * size));
+      ldp(dst0, dst1, MemOperand(StackPointer(), 3 * size, PostIndex));
+      break;
+    case 4:
+      // Load the higher addresses first, then load the lower addresses and
+      // skip the whole block in the second instruction. This allows four W
+      // registers to be popped using csp, whilst maintaining 16-byte alignment
+      // for csp at all times.
+      ldp(dst2, dst3, MemOperand(StackPointer(), 2 * size));
+      ldp(dst0, dst1, MemOperand(StackPointer(), 4 * size, PostIndex));
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void MacroAssembler::PushPreamble(Operand total_size) {
+  if (csp.Is(StackPointer())) {
+    // If the current stack pointer is csp, then it must be aligned to 16 bytes
+    // on entry and the total size of the specified registers must also be a
+    // multiple of 16 bytes.
+    if (total_size.IsImmediate()) {
+      DCHECK((total_size.ImmediateValue() % 16) == 0);
+    }
+
+    // Don't check access size for non-immediate sizes. It's difficult to do
+    // well, and it will be caught by hardware (or the simulator) anyway.
+  } else {
+    // Even if the current stack pointer is not the system stack pointer (csp),
+    // the system stack pointer will still be modified in order to comply with
+    // ABI rules about accessing memory below the system stack pointer.
+    BumpSystemStackPointer(total_size);
+  }
+}
+
+
+void MacroAssembler::PopPostamble(Operand total_size) {
+  if (csp.Is(StackPointer())) {
+    // If the current stack pointer is csp, then it must be aligned to 16 bytes
+    // on entry and the total size of the specified registers must also be a
+    // multiple of 16 bytes.
+    if (total_size.IsImmediate()) {
+      DCHECK((total_size.ImmediateValue() % 16) == 0);
+    }
+
+    // Don't check access size for non-immediate sizes. It's difficult to do
+    // well, and it will be caught by hardware (or the simulator) anyway.
+  } else if (emit_debug_code()) {
+    // It is safe to leave csp where it is when unwinding the JavaScript stack,
+    // but if we keep it matching StackPointer, the simulator can detect memory
+    // accesses in the now-free part of the stack.
+    SyncSystemStackPointer();
+  }
+}
+
+
+void MacroAssembler::Poke(const CPURegister& src, const Operand& offset) {
+  if (offset.IsImmediate()) {
+    DCHECK(offset.ImmediateValue() >= 0);
+  } else if (emit_debug_code()) {
+    Cmp(xzr, offset);
+    Check(le, kStackAccessBelowStackPointer);
+  }
+
+  Str(src, MemOperand(StackPointer(), offset));
+}
+
+
+void MacroAssembler::Peek(const CPURegister& dst, const Operand& offset) {
+  if (offset.IsImmediate()) {
+    DCHECK(offset.ImmediateValue() >= 0);
+  } else if (emit_debug_code()) {
+    Cmp(xzr, offset);
+    Check(le, kStackAccessBelowStackPointer);
+  }
+
+  Ldr(dst, MemOperand(StackPointer(), offset));
+}
+
+
+void MacroAssembler::PokePair(const CPURegister& src1,
+                              const CPURegister& src2,
+                              int offset) {
+  DCHECK(AreSameSizeAndType(src1, src2));
+  DCHECK((offset >= 0) && ((offset % src1.SizeInBytes()) == 0));
+  Stp(src1, src2, MemOperand(StackPointer(), offset));
+}
+
+
+void MacroAssembler::PeekPair(const CPURegister& dst1,
+                              const CPURegister& dst2,
+                              int offset) {
+  DCHECK(AreSameSizeAndType(dst1, dst2));
+  DCHECK((offset >= 0) && ((offset % dst1.SizeInBytes()) == 0));
+  Ldp(dst1, dst2, MemOperand(StackPointer(), offset));
+}
+
+
+void MacroAssembler::PushCalleeSavedRegisters() {
+  // Ensure that the macro-assembler doesn't use any scratch registers.
+  InstructionAccurateScope scope(this);
+
+  // This method must not be called unless the current stack pointer is the
+  // system stack pointer (csp).
+  DCHECK(csp.Is(StackPointer()));
+
+  MemOperand tos(csp, -2 * kXRegSize, PreIndex);
+
+  stp(d14, d15, tos);
+  stp(d12, d13, tos);
+  stp(d10, d11, tos);
+  stp(d8, d9, tos);
+
+  stp(x29, x30, tos);
+  stp(x27, x28, tos);    // x28 = jssp
+  stp(x25, x26, tos);
+  stp(x23, x24, tos);
+  stp(x21, x22, tos);
+  stp(x19, x20, tos);
+}
+
+
+void MacroAssembler::PopCalleeSavedRegisters() {
+  // Ensure that the macro-assembler doesn't use any scratch registers.
+  InstructionAccurateScope scope(this);
+
+  // This method must not be called unless the current stack pointer is the
+  // system stack pointer (csp).
+  DCHECK(csp.Is(StackPointer()));
+
+  MemOperand tos(csp, 2 * kXRegSize, PostIndex);
+
+  ldp(x19, x20, tos);
+  ldp(x21, x22, tos);
+  ldp(x23, x24, tos);
+  ldp(x25, x26, tos);
+  ldp(x27, x28, tos);    // x28 = jssp
+  ldp(x29, x30, tos);
+
+  ldp(d8, d9, tos);
+  ldp(d10, d11, tos);
+  ldp(d12, d13, tos);
+  ldp(d14, d15, tos);
+}
+
+
+void MacroAssembler::AssertStackConsistency() {
+  // Avoid emitting code when !use_real_abort() since non-real aborts cause too
+  // much code to be generated.
+  if (emit_debug_code() && use_real_aborts()) {
+    if (csp.Is(StackPointer()) || CpuFeatures::IsSupported(ALWAYS_ALIGN_CSP)) {
+      // Always check the alignment of csp if ALWAYS_ALIGN_CSP is true.  We
+      // can't check the alignment of csp without using a scratch register (or
+      // clobbering the flags), but the processor (or simulator) will abort if
+      // it is not properly aligned during a load.
+      ldr(xzr, MemOperand(csp, 0));
+    }
+    if (FLAG_enable_slow_asserts && !csp.Is(StackPointer())) {
+      Label ok;
+      // Check that csp <= StackPointer(), preserving all registers and NZCV.
+      sub(StackPointer(), csp, StackPointer());
+      cbz(StackPointer(), &ok);                 // Ok if csp == StackPointer().
+      tbnz(StackPointer(), kXSignBit, &ok);     // Ok if csp < StackPointer().
+
+      // Avoid generating AssertStackConsistency checks for the Push in Abort.
+      { DontEmitDebugCodeScope dont_emit_debug_code_scope(this);
+        Abort(kTheCurrentStackPointerIsBelowCsp);
+      }
+
+      bind(&ok);
+      // Restore StackPointer().
+      sub(StackPointer(), csp, StackPointer());
+    }
+  }
+}
+
+
+void MacroAssembler::AssertFPCRState(Register fpcr) {
+  if (emit_debug_code()) {
+    Label unexpected_mode, done;
+    UseScratchRegisterScope temps(this);
+    if (fpcr.IsNone()) {
+      fpcr = temps.AcquireX();
+      Mrs(fpcr, FPCR);
+    }
+
+    // Settings overridden by ConfiugreFPCR():
+    //   - Assert that default-NaN mode is set.
+    Tbz(fpcr, DN_offset, &unexpected_mode);
+
+    // Settings left to their default values:
+    //   - Assert that flush-to-zero is not set.
+    Tbnz(fpcr, FZ_offset, &unexpected_mode);
+    //   - Assert that the rounding mode is nearest-with-ties-to-even.
+    STATIC_ASSERT(FPTieEven == 0);
+    Tst(fpcr, RMode_mask);
+    B(eq, &done);
+
+    Bind(&unexpected_mode);
+    Abort(kUnexpectedFPCRMode);
+
+    Bind(&done);
+  }
+}
+
+
+void MacroAssembler::ConfigureFPCR() {
+  UseScratchRegisterScope temps(this);
+  Register fpcr = temps.AcquireX();
+  Mrs(fpcr, FPCR);
+
+  // If necessary, enable default-NaN mode. The default values of the other FPCR
+  // options should be suitable, and AssertFPCRState will verify that.
+  Label no_write_required;
+  Tbnz(fpcr, DN_offset, &no_write_required);
+
+  Orr(fpcr, fpcr, DN_mask);
+  Msr(FPCR, fpcr);
+
+  Bind(&no_write_required);
+  AssertFPCRState(fpcr);
+}
+
+
+void MacroAssembler::CanonicalizeNaN(const FPRegister& dst,
+                                     const FPRegister& src) {
+  AssertFPCRState();
+
+  // With DN=1 and RMode=FPTieEven, subtracting 0.0 preserves all inputs except
+  // for NaNs, which become the default NaN. We use fsub rather than fadd
+  // because sub preserves -0.0 inputs: -0.0 + 0.0 = 0.0, but -0.0 - 0.0 = -0.0.
+  Fsub(dst, src, fp_zero);
+}
+
+
+void MacroAssembler::LoadRoot(CPURegister destination,
+                              Heap::RootListIndex index) {
+  // TODO(jbramley): Most root values are constants, and can be synthesized
+  // without a load. Refer to the ARM back end for details.
+  Ldr(destination, MemOperand(root, index << kPointerSizeLog2));
+}
+
+
+void MacroAssembler::StoreRoot(Register source,
+                               Heap::RootListIndex index) {
+  Str(source, MemOperand(root, index << kPointerSizeLog2));
+}
+
+
+void MacroAssembler::LoadTrueFalseRoots(Register true_root,
+                                        Register false_root) {
+  STATIC_ASSERT((Heap::kTrueValueRootIndex + 1) == Heap::kFalseValueRootIndex);
+  Ldp(true_root, false_root,
+      MemOperand(root, Heap::kTrueValueRootIndex << kPointerSizeLog2));
+}
+
+
+void MacroAssembler::LoadHeapObject(Register result,
+                                    Handle<HeapObject> object) {
+  AllowDeferredHandleDereference using_raw_address;
+  if (isolate()->heap()->InNewSpace(*object)) {
+    Handle<Cell> cell = isolate()->factory()->NewCell(object);
+    Mov(result, Operand(cell));
+    Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
+  } else {
+    Mov(result, Operand(object));
+  }
+}
+
+
+void MacroAssembler::LoadInstanceDescriptors(Register map,
+                                             Register descriptors) {
+  Ldr(descriptors, FieldMemOperand(map, Map::kDescriptorsOffset));
+}
+
+
+void MacroAssembler::NumberOfOwnDescriptors(Register dst, Register map) {
+  Ldr(dst, FieldMemOperand(map, Map::kBitField3Offset));
+  DecodeField<Map::NumberOfOwnDescriptorsBits>(dst);
+}
+
+
+void MacroAssembler::EnumLengthUntagged(Register dst, Register map) {
+  STATIC_ASSERT(Map::EnumLengthBits::kShift == 0);
+  Ldrsw(dst, FieldMemOperand(map, Map::kBitField3Offset));
+  And(dst, dst, Map::EnumLengthBits::kMask);
+}
+
+
+void MacroAssembler::EnumLengthSmi(Register dst, Register map) {
+  EnumLengthUntagged(dst, map);
+  SmiTag(dst, dst);
+}
+
+
+void MacroAssembler::CheckEnumCache(Register object,
+                                    Register null_value,
+                                    Register scratch0,
+                                    Register scratch1,
+                                    Register scratch2,
+                                    Register scratch3,
+                                    Label* call_runtime) {
+  DCHECK(!AreAliased(object, null_value, scratch0, scratch1, scratch2,
+                     scratch3));
+
+  Register empty_fixed_array_value = scratch0;
+  Register current_object = scratch1;
+
+  LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
+  Label next, start;
+
+  Mov(current_object, object);
+
+  // Check if the enum length field is properly initialized, indicating that
+  // there is an enum cache.
+  Register map = scratch2;
+  Register enum_length = scratch3;
+  Ldr(map, FieldMemOperand(current_object, HeapObject::kMapOffset));
+
+  EnumLengthUntagged(enum_length, map);
+  Cmp(enum_length, kInvalidEnumCacheSentinel);
+  B(eq, call_runtime);
+
+  B(&start);
+
+  Bind(&next);
+  Ldr(map, FieldMemOperand(current_object, HeapObject::kMapOffset));
+
+  // For all objects but the receiver, check that the cache is empty.
+  EnumLengthUntagged(enum_length, map);
+  Cbnz(enum_length, call_runtime);
+
+  Bind(&start);
+
+  // Check that there are no elements. Register current_object contains the
+  // current JS object we've reached through the prototype chain.
+  Label no_elements;
+  Ldr(current_object, FieldMemOperand(current_object,
+                                      JSObject::kElementsOffset));
+  Cmp(current_object, empty_fixed_array_value);
+  B(eq, &no_elements);
+
+  // Second chance, the object may be using the empty slow element dictionary.
+  CompareRoot(current_object, Heap::kEmptySlowElementDictionaryRootIndex);
+  B(ne, call_runtime);
+
+  Bind(&no_elements);
+  Ldr(current_object, FieldMemOperand(map, Map::kPrototypeOffset));
+  Cmp(current_object, null_value);
+  B(ne, &next);
+}
+
+
+void MacroAssembler::TestJSArrayForAllocationMemento(Register receiver,
+                                                     Register scratch1,
+                                                     Register scratch2,
+                                                     Label* no_memento_found) {
+  ExternalReference new_space_start =
+      ExternalReference::new_space_start(isolate());
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address(isolate());
+
+  Add(scratch1, receiver,
+      JSArray::kSize + AllocationMemento::kSize - kHeapObjectTag);
+  Cmp(scratch1, new_space_start);
+  B(lt, no_memento_found);
+
+  Mov(scratch2, new_space_allocation_top);
+  Ldr(scratch2, MemOperand(scratch2));
+  Cmp(scratch1, scratch2);
+  B(gt, no_memento_found);
+
+  Ldr(scratch1, MemOperand(scratch1, -AllocationMemento::kSize));
+  Cmp(scratch1,
+      Operand(isolate()->factory()->allocation_memento_map()));
+}
+
+
+void MacroAssembler::JumpToHandlerEntry(Register exception,
+                                        Register object,
+                                        Register state,
+                                        Register scratch1,
+                                        Register scratch2) {
+  // Handler expects argument in x0.
+  DCHECK(exception.Is(x0));
+
+  // Compute the handler entry address and jump to it. The handler table is
+  // a fixed array of (smi-tagged) code offsets.
+  Ldr(scratch1, FieldMemOperand(object, Code::kHandlerTableOffset));
+  Add(scratch1, scratch1, FixedArray::kHeaderSize - kHeapObjectTag);
+  STATIC_ASSERT(StackHandler::kKindWidth < kPointerSizeLog2);
+  Lsr(scratch2, state, StackHandler::kKindWidth);
+  Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
+  Add(scratch1, object, Code::kHeaderSize - kHeapObjectTag);
+  Add(scratch1, scratch1, Operand::UntagSmi(scratch2));
+  Br(scratch1);
+}
+
+
+void MacroAssembler::InNewSpace(Register object,
+                                Condition cond,
+                                Label* branch) {
+  DCHECK(cond == eq || cond == ne);
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  And(temp, object, ExternalReference::new_space_mask(isolate()));
+  Cmp(temp, ExternalReference::new_space_start(isolate()));
+  B(cond, branch);
+}
+
+
+void MacroAssembler::Throw(Register value,
+                           Register scratch1,
+                           Register scratch2,
+                           Register scratch3,
+                           Register scratch4) {
+  // Adjust this code if not the case.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+
+  // The handler expects the exception in x0.
+  DCHECK(value.Is(x0));
+
+  // Drop the stack pointer to the top of the top handler.
+  DCHECK(jssp.Is(StackPointer()));
+  Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
+                                          isolate())));
+  Ldr(jssp, MemOperand(scratch1));
+  // Restore the next handler.
+  Pop(scratch2);
+  Str(scratch2, MemOperand(scratch1));
+
+  // Get the code object and state.  Restore the context and frame pointer.
+  Register object = scratch1;
+  Register state = scratch2;
+  Pop(object, state, cp, fp);
+
+  // If the handler is a JS frame, restore the context to the frame.
+  // (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
+  // or cp.
+  Label not_js_frame;
+  Cbz(cp, &not_js_frame);
+  Str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  Bind(&not_js_frame);
+
+  JumpToHandlerEntry(value, object, state, scratch3, scratch4);
+}
+
+
+void MacroAssembler::ThrowUncatchable(Register value,
+                                      Register scratch1,
+                                      Register scratch2,
+                                      Register scratch3,
+                                      Register scratch4) {
+  // Adjust this code if not the case.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+
+  // The handler expects the exception in x0.
+  DCHECK(value.Is(x0));
+
+  // Drop the stack pointer to the top of the top stack handler.
+  DCHECK(jssp.Is(StackPointer()));
+  Mov(scratch1, Operand(ExternalReference(Isolate::kHandlerAddress,
+                                          isolate())));
+  Ldr(jssp, MemOperand(scratch1));
+
+  // Unwind the handlers until the ENTRY handler is found.
+  Label fetch_next, check_kind;
+  B(&check_kind);
+  Bind(&fetch_next);
+  Peek(jssp, StackHandlerConstants::kNextOffset);
+
+  Bind(&check_kind);
+  STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
+  Peek(scratch2, StackHandlerConstants::kStateOffset);
+  TestAndBranchIfAnySet(scratch2, StackHandler::KindField::kMask, &fetch_next);
+
+  // Set the top handler address to next handler past the top ENTRY handler.
+  Pop(scratch2);
+  Str(scratch2, MemOperand(scratch1));
+
+  // Get the code object and state.  Clear the context and frame pointer (0 was
+  // saved in the handler).
+  Register object = scratch1;
+  Register state = scratch2;
+  Pop(object, state, cp, fp);
+
+  JumpToHandlerEntry(value, object, state, scratch3, scratch4);
+}
+
+
+void MacroAssembler::AssertSmi(Register object, BailoutReason reason) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    Tst(object, kSmiTagMask);
+    Check(eq, reason);
+  }
+}
+
+
+void MacroAssembler::AssertNotSmi(Register object, BailoutReason reason) {
+  if (emit_debug_code()) {
+    STATIC_ASSERT(kSmiTag == 0);
+    Tst(object, kSmiTagMask);
+    Check(ne, reason);
+  }
+}
+
+
+void MacroAssembler::AssertName(Register object) {
+  if (emit_debug_code()) {
+    AssertNotSmi(object, kOperandIsASmiAndNotAName);
+
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareInstanceType(temp, temp, LAST_NAME_TYPE);
+    Check(ls, kOperandIsNotAName);
+  }
+}
+
+
+void MacroAssembler::AssertUndefinedOrAllocationSite(Register object,
+                                                     Register scratch) {
+  if (emit_debug_code()) {
+    Label done_checking;
+    AssertNotSmi(object);
+    JumpIfRoot(object, Heap::kUndefinedValueRootIndex, &done_checking);
+    Ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareRoot(scratch, Heap::kAllocationSiteMapRootIndex);
+    Assert(eq, kExpectedUndefinedOrCell);
+    Bind(&done_checking);
+  }
+}
+
+
+void MacroAssembler::AssertString(Register object) {
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+    STATIC_ASSERT(kSmiTag == 0);
+    Tst(object, kSmiTagMask);
+    Check(ne, kOperandIsASmiAndNotAString);
+    Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE);
+    Check(lo, kOperandIsNotAString);
+  }
+}
+
+
+void MacroAssembler::CallStub(CodeStub* stub, TypeFeedbackId ast_id) {
+  DCHECK(AllowThisStubCall(stub));  // Stub calls are not allowed in some stubs.
+  Call(stub->GetCode(), RelocInfo::CODE_TARGET, ast_id);
+}
+
+
+void MacroAssembler::TailCallStub(CodeStub* stub) {
+  Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::CallRuntime(const Runtime::Function* f,
+                                 int num_arguments,
+                                 SaveFPRegsMode save_doubles) {
+  // All arguments must be on the stack before this function is called.
+  // x0 holds the return value after the call.
+
+  // Check that the number of arguments matches what the function expects.
+  // If f->nargs is -1, the function can accept a variable number of arguments.
+  CHECK(f->nargs < 0 || f->nargs == num_arguments);
+
+  // Place the necessary arguments.
+  Mov(x0, num_arguments);
+  Mov(x1, ExternalReference(f, isolate()));
+
+  CEntryStub stub(isolate(), 1, save_doubles);
+  CallStub(&stub);
+}
+
+
+static int AddressOffset(ExternalReference ref0, ExternalReference ref1) {
+  return ref0.address() - ref1.address();
+}
+
+
+void MacroAssembler::CallApiFunctionAndReturn(
+    Register function_address,
+    ExternalReference thunk_ref,
+    int stack_space,
+    int spill_offset,
+    MemOperand return_value_operand,
+    MemOperand* context_restore_operand) {
+  ASM_LOCATION("CallApiFunctionAndReturn");
+  ExternalReference next_address =
+      ExternalReference::handle_scope_next_address(isolate());
+  const int kNextOffset = 0;
+  const int kLimitOffset = AddressOffset(
+      ExternalReference::handle_scope_limit_address(isolate()),
+      next_address);
+  const int kLevelOffset = AddressOffset(
+      ExternalReference::handle_scope_level_address(isolate()),
+      next_address);
+
+  DCHECK(function_address.is(x1) || function_address.is(x2));
+
+  Label profiler_disabled;
+  Label end_profiler_check;
+  Mov(x10, ExternalReference::is_profiling_address(isolate()));
+  Ldrb(w10, MemOperand(x10));
+  Cbz(w10, &profiler_disabled);
+  Mov(x3, thunk_ref);
+  B(&end_profiler_check);
+
+  Bind(&profiler_disabled);
+  Mov(x3, function_address);
+  Bind(&end_profiler_check);
+
+  // Save the callee-save registers we are going to use.
+  // TODO(all): Is this necessary? ARM doesn't do it.
+  STATIC_ASSERT(kCallApiFunctionSpillSpace == 4);
+  Poke(x19, (spill_offset + 0) * kXRegSize);
+  Poke(x20, (spill_offset + 1) * kXRegSize);
+  Poke(x21, (spill_offset + 2) * kXRegSize);
+  Poke(x22, (spill_offset + 3) * kXRegSize);
+
+  // Allocate HandleScope in callee-save registers.
+  // We will need to restore the HandleScope after the call to the API function,
+  // by allocating it in callee-save registers they will be preserved by C code.
+  Register handle_scope_base = x22;
+  Register next_address_reg = x19;
+  Register limit_reg = x20;
+  Register level_reg = w21;
+
+  Mov(handle_scope_base, next_address);
+  Ldr(next_address_reg, MemOperand(handle_scope_base, kNextOffset));
+  Ldr(limit_reg, MemOperand(handle_scope_base, kLimitOffset));
+  Ldr(level_reg, MemOperand(handle_scope_base, kLevelOffset));
+  Add(level_reg, level_reg, 1);
+  Str(level_reg, MemOperand(handle_scope_base, kLevelOffset));
+
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    Mov(x0, ExternalReference::isolate_address(isolate()));
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 1);
+    PopSafepointRegisters();
+  }
+
+  // Native call returns to the DirectCEntry stub which redirects to the
+  // return address pushed on stack (could have moved after GC).
+  // DirectCEntry stub itself is generated early and never moves.
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(this, x3);
+
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    Mov(x0, ExternalReference::isolate_address(isolate()));
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 1);
+    PopSafepointRegisters();
+  }
+
+  Label promote_scheduled_exception;
+  Label exception_handled;
+  Label delete_allocated_handles;
+  Label leave_exit_frame;
+  Label return_value_loaded;
+
+  // Load value from ReturnValue.
+  Ldr(x0, return_value_operand);
+  Bind(&return_value_loaded);
+  // No more valid handles (the result handle was the last one). Restore
+  // previous handle scope.
+  Str(next_address_reg, MemOperand(handle_scope_base, kNextOffset));
+  if (emit_debug_code()) {
+    Ldr(w1, MemOperand(handle_scope_base, kLevelOffset));
+    Cmp(w1, level_reg);
+    Check(eq, kUnexpectedLevelAfterReturnFromApiCall);
+  }
+  Sub(level_reg, level_reg, 1);
+  Str(level_reg, MemOperand(handle_scope_base, kLevelOffset));
+  Ldr(x1, MemOperand(handle_scope_base, kLimitOffset));
+  Cmp(limit_reg, x1);
+  B(ne, &delete_allocated_handles);
+
+  Bind(&leave_exit_frame);
+  // Restore callee-saved registers.
+  Peek(x19, (spill_offset + 0) * kXRegSize);
+  Peek(x20, (spill_offset + 1) * kXRegSize);
+  Peek(x21, (spill_offset + 2) * kXRegSize);
+  Peek(x22, (spill_offset + 3) * kXRegSize);
+
+  // Check if the function scheduled an exception.
+  Mov(x5, ExternalReference::scheduled_exception_address(isolate()));
+  Ldr(x5, MemOperand(x5));
+  JumpIfNotRoot(x5, Heap::kTheHoleValueRootIndex, &promote_scheduled_exception);
+  Bind(&exception_handled);
+
+  bool restore_context = context_restore_operand != NULL;
+  if (restore_context) {
+    Ldr(cp, *context_restore_operand);
+  }
+
+  LeaveExitFrame(false, x1, !restore_context);
+  Drop(stack_space);
+  Ret();
+
+  Bind(&promote_scheduled_exception);
+  {
+    FrameScope frame(this, StackFrame::INTERNAL);
+    CallExternalReference(
+        ExternalReference(
+            Runtime::kPromoteScheduledException, isolate()), 0);
+  }
+  B(&exception_handled);
+
+  // HandleScope limit has changed. Delete allocated extensions.
+  Bind(&delete_allocated_handles);
+  Str(limit_reg, MemOperand(handle_scope_base, kLimitOffset));
+  // Save the return value in a callee-save register.
+  Register saved_result = x19;
+  Mov(saved_result, x0);
+  Mov(x0, ExternalReference::isolate_address(isolate()));
+  CallCFunction(
+      ExternalReference::delete_handle_scope_extensions(isolate()), 1);
+  Mov(x0, saved_result);
+  B(&leave_exit_frame);
+}
+
+
+void MacroAssembler::CallExternalReference(const ExternalReference& ext,
+                                           int num_arguments) {
+  Mov(x0, num_arguments);
+  Mov(x1, ext);
+
+  CEntryStub stub(isolate(), 1);
+  CallStub(&stub);
+}
+
+
+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
+  Mov(x1, builtin);
+  CEntryStub stub(isolate(), 1);
+  Jump(stub.GetCode(), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::GetBuiltinFunction(Register target,
+                                        Builtins::JavaScript id) {
+  // Load the builtins object into target register.
+  Ldr(target, GlobalObjectMemOperand());
+  Ldr(target, FieldMemOperand(target, GlobalObject::kBuiltinsOffset));
+  // Load the JavaScript builtin function from the builtins object.
+  Ldr(target, FieldMemOperand(target,
+                          JSBuiltinsObject::OffsetOfFunctionWithId(id)));
+}
+
+
+void MacroAssembler::GetBuiltinEntry(Register target,
+                                     Register function,
+                                     Builtins::JavaScript id) {
+  DCHECK(!AreAliased(target, function));
+  GetBuiltinFunction(function, id);
+  // Load the code entry point from the builtins object.
+  Ldr(target, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+}
+
+
+void MacroAssembler::InvokeBuiltin(Builtins::JavaScript id,
+                                   InvokeFlag flag,
+                                   const CallWrapper& call_wrapper) {
+  ASM_LOCATION("MacroAssembler::InvokeBuiltin");
+  // You can't call a builtin without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  // Get the builtin entry in x2 and setup the function object in x1.
+  GetBuiltinEntry(x2, x1, id);
+  if (flag == CALL_FUNCTION) {
+    call_wrapper.BeforeCall(CallSize(x2));
+    Call(x2);
+    call_wrapper.AfterCall();
+  } else {
+    DCHECK(flag == JUMP_FUNCTION);
+    Jump(x2);
+  }
+}
+
+
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  Mov(x0, num_arguments);
+  JumpToExternalReference(ext);
+}
+
+
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
+                                     int num_arguments,
+                                     int result_size) {
+  TailCallExternalReference(ExternalReference(fid, isolate()),
+                            num_arguments,
+                            result_size);
+}
+
+
+void MacroAssembler::InitializeNewString(Register string,
+                                         Register length,
+                                         Heap::RootListIndex map_index,
+                                         Register scratch1,
+                                         Register scratch2) {
+  DCHECK(!AreAliased(string, length, scratch1, scratch2));
+  LoadRoot(scratch2, map_index);
+  SmiTag(scratch1, length);
+  Str(scratch2, FieldMemOperand(string, HeapObject::kMapOffset));
+
+  Mov(scratch2, String::kEmptyHashField);
+  Str(scratch1, FieldMemOperand(string, String::kLengthOffset));
+  Str(scratch2, FieldMemOperand(string, String::kHashFieldOffset));
+}
+
+
+int MacroAssembler::ActivationFrameAlignment() {
+#if V8_HOST_ARCH_ARM64
+  // Running on the real platform. Use the alignment as mandated by the local
+  // environment.
+  // Note: This will break if we ever start generating snapshots on one ARM
+  // platform for another ARM platform with a different alignment.
+  return base::OS::ActivationFrameAlignment();
+#else  // V8_HOST_ARCH_ARM64
+  // If we are using the simulator then we should always align to the expected
+  // alignment. As the simulator is used to generate snapshots we do not know
+  // if the target platform will need alignment, so this is controlled from a
+  // flag.
+  return FLAG_sim_stack_alignment;
+#endif  // V8_HOST_ARCH_ARM64
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+                                   int num_of_reg_args) {
+  CallCFunction(function, num_of_reg_args, 0);
+}
+
+
+void MacroAssembler::CallCFunction(ExternalReference function,
+                                   int num_of_reg_args,
+                                   int num_of_double_args) {
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Mov(temp, function);
+  CallCFunction(temp, num_of_reg_args, num_of_double_args);
+}
+
+
+void MacroAssembler::CallCFunction(Register function,
+                                   int num_of_reg_args,
+                                   int num_of_double_args) {
+  DCHECK(has_frame());
+  // We can pass 8 integer arguments in registers. If we need to pass more than
+  // that, we'll need to implement support for passing them on the stack.
+  DCHECK(num_of_reg_args <= 8);
+
+  // If we're passing doubles, we're limited to the following prototypes
+  // (defined by ExternalReference::Type):
+  //  BUILTIN_COMPARE_CALL:  int f(double, double)
+  //  BUILTIN_FP_FP_CALL:    double f(double, double)
+  //  BUILTIN_FP_CALL:       double f(double)
+  //  BUILTIN_FP_INT_CALL:   double f(double, int)
+  if (num_of_double_args > 0) {
+    DCHECK(num_of_reg_args <= 1);
+    DCHECK((num_of_double_args + num_of_reg_args) <= 2);
+  }
+
+
+  // If the stack pointer is not csp, we need to derive an aligned csp from the
+  // current stack pointer.
+  const Register old_stack_pointer = StackPointer();
+  if (!csp.Is(old_stack_pointer)) {
+    AssertStackConsistency();
+
+    int sp_alignment = ActivationFrameAlignment();
+    // The ABI mandates at least 16-byte alignment.
+    DCHECK(sp_alignment >= 16);
+    DCHECK(base::bits::IsPowerOfTwo32(sp_alignment));
+
+    // The current stack pointer is a callee saved register, and is preserved
+    // across the call.
+    DCHECK(kCalleeSaved.IncludesAliasOf(old_stack_pointer));
+
+    // Align and synchronize the system stack pointer with jssp.
+    Bic(csp, old_stack_pointer, sp_alignment - 1);
+    SetStackPointer(csp);
+  }
+
+  // Call directly. The function called cannot cause a GC, or allow preemption,
+  // so the return address in the link register stays correct.
+  Call(function);
+
+  if (!csp.Is(old_stack_pointer)) {
+    if (emit_debug_code()) {
+      // Because the stack pointer must be aligned on a 16-byte boundary, the
+      // aligned csp can be up to 12 bytes below the jssp. This is the case
+      // where we only pushed one W register on top of an aligned jssp.
+      UseScratchRegisterScope temps(this);
+      Register temp = temps.AcquireX();
+      DCHECK(ActivationFrameAlignment() == 16);
+      Sub(temp, csp, old_stack_pointer);
+      // We want temp <= 0 && temp >= -12.
+      Cmp(temp, 0);
+      Ccmp(temp, -12, NFlag, le);
+      Check(ge, kTheStackWasCorruptedByMacroAssemblerCall);
+    }
+    SetStackPointer(old_stack_pointer);
+  }
+}
+
+
+void MacroAssembler::Jump(Register target) {
+  Br(target);
+}
+
+
+void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode) {
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Mov(temp, Operand(target, rmode));
+  Br(temp);
+}
+
+
+void MacroAssembler::Jump(Address target, RelocInfo::Mode rmode) {
+  DCHECK(!RelocInfo::IsCodeTarget(rmode));
+  Jump(reinterpret_cast<intptr_t>(target), rmode);
+}
+
+
+void MacroAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode) {
+  DCHECK(RelocInfo::IsCodeTarget(rmode));
+  AllowDeferredHandleDereference embedding_raw_address;
+  Jump(reinterpret_cast<intptr_t>(code.location()), rmode);
+}
+
+
+void MacroAssembler::Call(Register target) {
+  BlockPoolsScope scope(this);
+#ifdef DEBUG
+  Label start_call;
+  Bind(&start_call);
+#endif
+
+  Blr(target);
+
+#ifdef DEBUG
+  AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target));
+#endif
+}
+
+
+void MacroAssembler::Call(Label* target) {
+  BlockPoolsScope scope(this);
+#ifdef DEBUG
+  Label start_call;
+  Bind(&start_call);
+#endif
+
+  Bl(target);
+
+#ifdef DEBUG
+  AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target));
+#endif
+}
+
+
+// MacroAssembler::CallSize is sensitive to changes in this function, as it
+// requires to know how many instructions are used to branch to the target.
+void MacroAssembler::Call(Address target, RelocInfo::Mode rmode) {
+  BlockPoolsScope scope(this);
+#ifdef DEBUG
+  Label start_call;
+  Bind(&start_call);
+#endif
+  // Statement positions are expected to be recorded when the target
+  // address is loaded.
+  positions_recorder()->WriteRecordedPositions();
+
+  // Addresses always have 64 bits, so we shouldn't encounter NONE32.
+  DCHECK(rmode != RelocInfo::NONE32);
+
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+
+  if (rmode == RelocInfo::NONE64) {
+    // Addresses are 48 bits so we never need to load the upper 16 bits.
+    uint64_t imm = reinterpret_cast<uint64_t>(target);
+    // If we don't use ARM tagged addresses, the 16 higher bits must be 0.
+    DCHECK(((imm >> 48) & 0xffff) == 0);
+    movz(temp, (imm >> 0) & 0xffff, 0);
+    movk(temp, (imm >> 16) & 0xffff, 16);
+    movk(temp, (imm >> 32) & 0xffff, 32);
+  } else {
+    Ldr(temp, Immediate(reinterpret_cast<intptr_t>(target), rmode));
+  }
+  Blr(temp);
+#ifdef DEBUG
+  AssertSizeOfCodeGeneratedSince(&start_call, CallSize(target, rmode));
+#endif
+}
+
+
+void MacroAssembler::Call(Handle<Code> code,
+                          RelocInfo::Mode rmode,
+                          TypeFeedbackId ast_id) {
+#ifdef DEBUG
+  Label start_call;
+  Bind(&start_call);
+#endif
+
+  if ((rmode == RelocInfo::CODE_TARGET) && (!ast_id.IsNone())) {
+    SetRecordedAstId(ast_id);
+    rmode = RelocInfo::CODE_TARGET_WITH_ID;
+  }
+
+  AllowDeferredHandleDereference embedding_raw_address;
+  Call(reinterpret_cast<Address>(code.location()), rmode);
+
+#ifdef DEBUG
+  // Check the size of the code generated.
+  AssertSizeOfCodeGeneratedSince(&start_call, CallSize(code, rmode, ast_id));
+#endif
+}
+
+
+int MacroAssembler::CallSize(Register target) {
+  USE(target);
+  return kInstructionSize;
+}
+
+
+int MacroAssembler::CallSize(Label* target) {
+  USE(target);
+  return kInstructionSize;
+}
+
+
+int MacroAssembler::CallSize(Address target, RelocInfo::Mode rmode) {
+  USE(target);
+
+  // Addresses always have 64 bits, so we shouldn't encounter NONE32.
+  DCHECK(rmode != RelocInfo::NONE32);
+
+  if (rmode == RelocInfo::NONE64) {
+    return kCallSizeWithoutRelocation;
+  } else {
+    return kCallSizeWithRelocation;
+  }
+}
+
+
+int MacroAssembler::CallSize(Handle<Code> code,
+                             RelocInfo::Mode rmode,
+                             TypeFeedbackId ast_id) {
+  USE(code);
+  USE(ast_id);
+
+  // Addresses always have 64 bits, so we shouldn't encounter NONE32.
+  DCHECK(rmode != RelocInfo::NONE32);
+
+  if (rmode == RelocInfo::NONE64) {
+    return kCallSizeWithoutRelocation;
+  } else {
+    return kCallSizeWithRelocation;
+  }
+}
+
+
+void MacroAssembler::JumpIfHeapNumber(Register object, Label* on_heap_number,
+                                      SmiCheckType smi_check_type) {
+  Label on_not_heap_number;
+
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(object, &on_not_heap_number);
+  }
+
+  AssertNotSmi(object);
+
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+  JumpIfRoot(temp, Heap::kHeapNumberMapRootIndex, on_heap_number);
+
+  Bind(&on_not_heap_number);
+}
+
+
+void MacroAssembler::JumpIfNotHeapNumber(Register object,
+                                         Label* on_not_heap_number,
+                                         SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(object, on_not_heap_number);
+  }
+
+  AssertNotSmi(object);
+
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+  JumpIfNotRoot(temp, Heap::kHeapNumberMapRootIndex, on_not_heap_number);
+}
+
+
+void MacroAssembler::LookupNumberStringCache(Register object,
+                                             Register result,
+                                             Register scratch1,
+                                             Register scratch2,
+                                             Register scratch3,
+                                             Label* not_found) {
+  DCHECK(!AreAliased(object, result, scratch1, scratch2, scratch3));
+
+  // Use of registers. Register result is used as a temporary.
+  Register number_string_cache = result;
+  Register mask = scratch3;
+
+  // Load the number string cache.
+  LoadRoot(number_string_cache, Heap::kNumberStringCacheRootIndex);
+
+  // Make the hash mask from the length of the number string cache. It
+  // contains two elements (number and string) for each cache entry.
+  Ldrsw(mask, UntagSmiFieldMemOperand(number_string_cache,
+                                      FixedArray::kLengthOffset));
+  Asr(mask, mask, 1);  // Divide length by two.
+  Sub(mask, mask, 1);  // Make mask.
+
+  // Calculate the entry in the number string cache. The hash value in the
+  // number string cache for smis is just the smi value, and the hash for
+  // doubles is the xor of the upper and lower words. See
+  // Heap::GetNumberStringCache.
+  Label is_smi;
+  Label load_result_from_cache;
+
+  JumpIfSmi(object, &is_smi);
+  JumpIfNotHeapNumber(object, not_found);
+
+  STATIC_ASSERT(kDoubleSize == (kWRegSize * 2));
+  Add(scratch1, object, HeapNumber::kValueOffset - kHeapObjectTag);
+  Ldp(scratch1.W(), scratch2.W(), MemOperand(scratch1));
+  Eor(scratch1, scratch1, scratch2);
+  And(scratch1, scratch1, mask);
+
+  // Calculate address of entry in string cache: each entry consists of two
+  // pointer sized fields.
+  Add(scratch1, number_string_cache,
+      Operand(scratch1, LSL, kPointerSizeLog2 + 1));
+
+  Register probe = mask;
+  Ldr(probe, FieldMemOperand(scratch1, FixedArray::kHeaderSize));
+  JumpIfSmi(probe, not_found);
+  Ldr(d0, FieldMemOperand(object, HeapNumber::kValueOffset));
+  Ldr(d1, FieldMemOperand(probe, HeapNumber::kValueOffset));
+  Fcmp(d0, d1);
+  B(ne, not_found);
+  B(&load_result_from_cache);
+
+  Bind(&is_smi);
+  Register scratch = scratch1;
+  And(scratch, mask, Operand::UntagSmi(object));
+  // Calculate address of entry in string cache: each entry consists
+  // of two pointer sized fields.
+  Add(scratch, number_string_cache,
+      Operand(scratch, LSL, kPointerSizeLog2 + 1));
+
+  // Check if the entry is the smi we are looking for.
+  Ldr(probe, FieldMemOperand(scratch, FixedArray::kHeaderSize));
+  Cmp(object, probe);
+  B(ne, not_found);
+
+  // Get the result from the cache.
+  Bind(&load_result_from_cache);
+  Ldr(result, FieldMemOperand(scratch, FixedArray::kHeaderSize + kPointerSize));
+  IncrementCounter(isolate()->counters()->number_to_string_native(), 1,
+                   scratch1, scratch2);
+}
+
+
+void MacroAssembler::TryRepresentDoubleAsInt(Register as_int,
+                                             FPRegister value,
+                                             FPRegister scratch_d,
+                                             Label* on_successful_conversion,
+                                             Label* on_failed_conversion) {
+  // Convert to an int and back again, then compare with the original value.
+  Fcvtzs(as_int, value);
+  Scvtf(scratch_d, as_int);
+  Fcmp(value, scratch_d);
+
+  if (on_successful_conversion) {
+    B(on_successful_conversion, eq);
+  }
+  if (on_failed_conversion) {
+    B(on_failed_conversion, ne);
+  }
+}
+
+
+void MacroAssembler::TestForMinusZero(DoubleRegister input) {
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  // Floating point -0.0 is kMinInt as an integer, so subtracting 1 (cmp) will
+  // cause overflow.
+  Fmov(temp, input);
+  Cmp(temp, 1);
+}
+
+
+void MacroAssembler::JumpIfMinusZero(DoubleRegister input,
+                                     Label* on_negative_zero) {
+  TestForMinusZero(input);
+  B(vs, on_negative_zero);
+}
+
+
+void MacroAssembler::JumpIfMinusZero(Register input,
+                                     Label* on_negative_zero) {
+  DCHECK(input.Is64Bits());
+  // Floating point value is in an integer register. Detect -0.0 by subtracting
+  // 1 (cmp), which will cause overflow.
+  Cmp(input, 1);
+  B(vs, on_negative_zero);
+}
+
+
+void MacroAssembler::ClampInt32ToUint8(Register output, Register input) {
+  // Clamp the value to [0..255].
+  Cmp(input.W(), Operand(input.W(), UXTB));
+  // If input < input & 0xff, it must be < 0, so saturate to 0.
+  Csel(output.W(), wzr, input.W(), lt);
+  // If input <= input & 0xff, it must be <= 255. Otherwise, saturate to 255.
+  Csel(output.W(), output.W(), 255, le);
+}
+
+
+void MacroAssembler::ClampInt32ToUint8(Register in_out) {
+  ClampInt32ToUint8(in_out, in_out);
+}
+
+
+void MacroAssembler::ClampDoubleToUint8(Register output,
+                                        DoubleRegister input,
+                                        DoubleRegister dbl_scratch) {
+  // This conversion follows the WebIDL "[Clamp]" rules for PIXEL types:
+  //   - Inputs lower than 0 (including -infinity) produce 0.
+  //   - Inputs higher than 255 (including +infinity) produce 255.
+  // Also, it seems that PIXEL types use round-to-nearest rather than
+  // round-towards-zero.
+
+  // Squash +infinity before the conversion, since Fcvtnu will normally
+  // convert it to 0.
+  Fmov(dbl_scratch, 255);
+  Fmin(dbl_scratch, dbl_scratch, input);
+
+  // Convert double to unsigned integer. Values less than zero become zero.
+  // Values greater than 255 have already been clamped to 255.
+  Fcvtnu(output, dbl_scratch);
+}
+
+
+void MacroAssembler::CopyFieldsLoopPairsHelper(Register dst,
+                                               Register src,
+                                               unsigned count,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Register scratch3,
+                                               Register scratch4,
+                                               Register scratch5) {
+  // Untag src and dst into scratch registers.
+  // Copy src->dst in a tight loop.
+  DCHECK(!AreAliased(dst, src,
+                     scratch1, scratch2, scratch3, scratch4, scratch5));
+  DCHECK(count >= 2);
+
+  const Register& remaining = scratch3;
+  Mov(remaining, count / 2);
+
+  const Register& dst_untagged = scratch1;
+  const Register& src_untagged = scratch2;
+  Sub(dst_untagged, dst, kHeapObjectTag);
+  Sub(src_untagged, src, kHeapObjectTag);
+
+  // Copy fields in pairs.
+  Label loop;
+  Bind(&loop);
+  Ldp(scratch4, scratch5,
+      MemOperand(src_untagged, kXRegSize* 2, PostIndex));
+  Stp(scratch4, scratch5,
+      MemOperand(dst_untagged, kXRegSize* 2, PostIndex));
+  Sub(remaining, remaining, 1);
+  Cbnz(remaining, &loop);
+
+  // Handle the leftovers.
+  if (count & 1) {
+    Ldr(scratch4, MemOperand(src_untagged));
+    Str(scratch4, MemOperand(dst_untagged));
+  }
+}
+
+
+void MacroAssembler::CopyFieldsUnrolledPairsHelper(Register dst,
+                                                   Register src,
+                                                   unsigned count,
+                                                   Register scratch1,
+                                                   Register scratch2,
+                                                   Register scratch3,
+                                                   Register scratch4) {
+  // Untag src and dst into scratch registers.
+  // Copy src->dst in an unrolled loop.
+  DCHECK(!AreAliased(dst, src, scratch1, scratch2, scratch3, scratch4));
+
+  const Register& dst_untagged = scratch1;
+  const Register& src_untagged = scratch2;
+  sub(dst_untagged, dst, kHeapObjectTag);
+  sub(src_untagged, src, kHeapObjectTag);
+
+  // Copy fields in pairs.
+  for (unsigned i = 0; i < count / 2; i++) {
+    Ldp(scratch3, scratch4, MemOperand(src_untagged, kXRegSize * 2, PostIndex));
+    Stp(scratch3, scratch4, MemOperand(dst_untagged, kXRegSize * 2, PostIndex));
+  }
+
+  // Handle the leftovers.
+  if (count & 1) {
+    Ldr(scratch3, MemOperand(src_untagged));
+    Str(scratch3, MemOperand(dst_untagged));
+  }
+}
+
+
+void MacroAssembler::CopyFieldsUnrolledHelper(Register dst,
+                                              Register src,
+                                              unsigned count,
+                                              Register scratch1,
+                                              Register scratch2,
+                                              Register scratch3) {
+  // Untag src and dst into scratch registers.
+  // Copy src->dst in an unrolled loop.
+  DCHECK(!AreAliased(dst, src, scratch1, scratch2, scratch3));
+
+  const Register& dst_untagged = scratch1;
+  const Register& src_untagged = scratch2;
+  Sub(dst_untagged, dst, kHeapObjectTag);
+  Sub(src_untagged, src, kHeapObjectTag);
+
+  // Copy fields one by one.
+  for (unsigned i = 0; i < count; i++) {
+    Ldr(scratch3, MemOperand(src_untagged, kXRegSize, PostIndex));
+    Str(scratch3, MemOperand(dst_untagged, kXRegSize, PostIndex));
+  }
+}
+
+
+void MacroAssembler::CopyFields(Register dst, Register src, CPURegList temps,
+                                unsigned count) {
+  // One of two methods is used:
+  //
+  // For high 'count' values where many scratch registers are available:
+  //    Untag src and dst into scratch registers.
+  //    Copy src->dst in a tight loop.
+  //
+  // For low 'count' values or where few scratch registers are available:
+  //    Untag src and dst into scratch registers.
+  //    Copy src->dst in an unrolled loop.
+  //
+  // In both cases, fields are copied in pairs if possible, and left-overs are
+  // handled separately.
+  DCHECK(!AreAliased(dst, src));
+  DCHECK(!temps.IncludesAliasOf(dst));
+  DCHECK(!temps.IncludesAliasOf(src));
+  DCHECK(!temps.IncludesAliasOf(xzr));
+
+  if (emit_debug_code()) {
+    Cmp(dst, src);
+    Check(ne, kTheSourceAndDestinationAreTheSame);
+  }
+
+  // The value of 'count' at which a loop will be generated (if there are
+  // enough scratch registers).
+  static const unsigned kLoopThreshold = 8;
+
+  UseScratchRegisterScope masm_temps(this);
+  if ((temps.Count() >= 3) && (count >= kLoopThreshold)) {
+    CopyFieldsLoopPairsHelper(dst, src, count,
+                              Register(temps.PopLowestIndex()),
+                              Register(temps.PopLowestIndex()),
+                              Register(temps.PopLowestIndex()),
+                              masm_temps.AcquireX(),
+                              masm_temps.AcquireX());
+  } else if (temps.Count() >= 2) {
+    CopyFieldsUnrolledPairsHelper(dst, src, count,
+                                  Register(temps.PopLowestIndex()),
+                                  Register(temps.PopLowestIndex()),
+                                  masm_temps.AcquireX(),
+                                  masm_temps.AcquireX());
+  } else if (temps.Count() == 1) {
+    CopyFieldsUnrolledHelper(dst, src, count,
+                             Register(temps.PopLowestIndex()),
+                             masm_temps.AcquireX(),
+                             masm_temps.AcquireX());
+  } else {
+    UNREACHABLE();
+  }
+}
+
+
+void MacroAssembler::CopyBytes(Register dst,
+                               Register src,
+                               Register length,
+                               Register scratch,
+                               CopyHint hint) {
+  UseScratchRegisterScope temps(this);
+  Register tmp1 = temps.AcquireX();
+  Register tmp2 = temps.AcquireX();
+  DCHECK(!AreAliased(src, dst, length, scratch, tmp1, tmp2));
+  DCHECK(!AreAliased(src, dst, csp));
+
+  if (emit_debug_code()) {
+    // Check copy length.
+    Cmp(length, 0);
+    Assert(ge, kUnexpectedNegativeValue);
+
+    // Check src and dst buffers don't overlap.
+    Add(scratch, src, length);  // Calculate end of src buffer.
+    Cmp(scratch, dst);
+    Add(scratch, dst, length);  // Calculate end of dst buffer.
+    Ccmp(scratch, src, ZFlag, gt);
+    Assert(le, kCopyBuffersOverlap);
+  }
+
+  Label short_copy, short_loop, bulk_loop, done;
+
+  if ((hint == kCopyLong || hint == kCopyUnknown) && !FLAG_optimize_for_size) {
+    Register bulk_length = scratch;
+    int pair_size = 2 * kXRegSize;
+    int pair_mask = pair_size - 1;
+
+    Bic(bulk_length, length, pair_mask);
+    Cbz(bulk_length, &short_copy);
+    Bind(&bulk_loop);
+    Sub(bulk_length, bulk_length, pair_size);
+    Ldp(tmp1, tmp2, MemOperand(src, pair_size, PostIndex));
+    Stp(tmp1, tmp2, MemOperand(dst, pair_size, PostIndex));
+    Cbnz(bulk_length, &bulk_loop);
+
+    And(length, length, pair_mask);
+  }
+
+  Bind(&short_copy);
+  Cbz(length, &done);
+  Bind(&short_loop);
+  Sub(length, length, 1);
+  Ldrb(tmp1, MemOperand(src, 1, PostIndex));
+  Strb(tmp1, MemOperand(dst, 1, PostIndex));
+  Cbnz(length, &short_loop);
+
+
+  Bind(&done);
+}
+
+
+void MacroAssembler::FillFields(Register dst,
+                                Register field_count,
+                                Register filler) {
+  DCHECK(!dst.Is(csp));
+  UseScratchRegisterScope temps(this);
+  Register field_ptr = temps.AcquireX();
+  Register counter = temps.AcquireX();
+  Label done;
+
+  // Decrement count. If the result < zero, count was zero, and there's nothing
+  // to do. If count was one, flags are set to fail the gt condition at the end
+  // of the pairs loop.
+  Subs(counter, field_count, 1);
+  B(lt, &done);
+
+  // There's at least one field to fill, so do this unconditionally.
+  Str(filler, MemOperand(dst, kPointerSize, PostIndex));
+
+  // If the bottom bit of counter is set, there are an even number of fields to
+  // fill, so pull the start pointer back by one field, allowing the pairs loop
+  // to overwrite the field that was stored above.
+  And(field_ptr, counter, 1);
+  Sub(field_ptr, dst, Operand(field_ptr, LSL, kPointerSizeLog2));
+
+  // Store filler to memory in pairs.
+  Label entry, loop;
+  B(&entry);
+  Bind(&loop);
+  Stp(filler, filler, MemOperand(field_ptr, 2 * kPointerSize, PostIndex));
+  Subs(counter, counter, 2);
+  Bind(&entry);
+  B(gt, &loop);
+
+  Bind(&done);
+}
+
+
+void MacroAssembler::JumpIfEitherIsNotSequentialOneByteStrings(
+    Register first, Register second, Register scratch1, Register scratch2,
+    Label* failure, SmiCheckType smi_check) {
+  if (smi_check == DO_SMI_CHECK) {
+    JumpIfEitherSmi(first, second, failure);
+  } else if (emit_debug_code()) {
+    DCHECK(smi_check == DONT_DO_SMI_CHECK);
+    Label not_smi;
+    JumpIfEitherSmi(first, second, NULL, &not_smi);
+
+    // At least one input is a smi, but the flags indicated a smi check wasn't
+    // needed.
+    Abort(kUnexpectedSmi);
+
+    Bind(&not_smi);
+  }
+
+  // Test that both first and second are sequential one-byte strings.
+  Ldr(scratch1, FieldMemOperand(first, HeapObject::kMapOffset));
+  Ldr(scratch2, FieldMemOperand(second, HeapObject::kMapOffset));
+  Ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
+  Ldrb(scratch2, FieldMemOperand(scratch2, Map::kInstanceTypeOffset));
+
+  JumpIfEitherInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, scratch1,
+                                                 scratch2, failure);
+}
+
+
+void MacroAssembler::JumpIfEitherInstanceTypeIsNotSequentialOneByte(
+    Register first, Register second, Register scratch1, Register scratch2,
+    Label* failure) {
+  DCHECK(!AreAliased(scratch1, second));
+  DCHECK(!AreAliased(scratch1, scratch2));
+  static const int kFlatOneByteStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  static const int kFlatOneByteStringTag = ONE_BYTE_STRING_TYPE;
+  And(scratch1, first, kFlatOneByteStringMask);
+  And(scratch2, second, kFlatOneByteStringMask);
+  Cmp(scratch1, kFlatOneByteStringTag);
+  Ccmp(scratch2, kFlatOneByteStringTag, NoFlag, eq);
+  B(ne, failure);
+}
+
+
+void MacroAssembler::JumpIfInstanceTypeIsNotSequentialOneByte(Register type,
+                                                              Register scratch,
+                                                              Label* failure) {
+  const int kFlatOneByteStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  const int kFlatOneByteStringTag =
+      kStringTag | kOneByteStringTag | kSeqStringTag;
+  And(scratch, type, kFlatOneByteStringMask);
+  Cmp(scratch, kFlatOneByteStringTag);
+  B(ne, failure);
+}
+
+
+void MacroAssembler::JumpIfBothInstanceTypesAreNotSequentialOneByte(
+    Register first, Register second, Register scratch1, Register scratch2,
+    Label* failure) {
+  DCHECK(!AreAliased(first, second, scratch1, scratch2));
+  const int kFlatOneByteStringMask =
+      kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask;
+  const int kFlatOneByteStringTag =
+      kStringTag | kOneByteStringTag | kSeqStringTag;
+  And(scratch1, first, kFlatOneByteStringMask);
+  And(scratch2, second, kFlatOneByteStringMask);
+  Cmp(scratch1, kFlatOneByteStringTag);
+  Ccmp(scratch2, kFlatOneByteStringTag, NoFlag, eq);
+  B(ne, failure);
+}
+
+
+void MacroAssembler::JumpIfNotUniqueNameInstanceType(Register type,
+                                                     Label* not_unique_name) {
+  STATIC_ASSERT((kInternalizedTag == 0) && (kStringTag == 0));
+  // if ((type is string && type is internalized) || type == SYMBOL_TYPE) {
+  //   continue
+  // } else {
+  //   goto not_unique_name
+  // }
+  Tst(type, kIsNotStringMask | kIsNotInternalizedMask);
+  Ccmp(type, SYMBOL_TYPE, ZFlag, ne);
+  B(ne, not_unique_name);
+}
+
+
+void MacroAssembler::InvokePrologue(const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    Handle<Code> code_constant,
+                                    Register code_reg,
+                                    Label* done,
+                                    InvokeFlag flag,
+                                    bool* definitely_mismatches,
+                                    const CallWrapper& call_wrapper) {
+  bool definitely_matches = false;
+  *definitely_mismatches = false;
+  Label regular_invoke;
+
+  // Check whether the expected and actual arguments count match. If not,
+  // setup registers according to contract with ArgumentsAdaptorTrampoline:
+  //  x0: actual arguments count.
+  //  x1: function (passed through to callee).
+  //  x2: expected arguments count.
+
+  // The code below is made a lot easier because the calling code already sets
+  // up actual and expected registers according to the contract if values are
+  // passed in registers.
+  DCHECK(actual.is_immediate() || actual.reg().is(x0));
+  DCHECK(expected.is_immediate() || expected.reg().is(x2));
+  DCHECK((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(x3));
+
+  if (expected.is_immediate()) {
+    DCHECK(actual.is_immediate());
+    if (expected.immediate() == actual.immediate()) {
+      definitely_matches = true;
+
+    } else {
+      Mov(x0, actual.immediate());
+      if (expected.immediate() ==
+          SharedFunctionInfo::kDontAdaptArgumentsSentinel) {
+        // Don't worry about adapting arguments for builtins that
+        // don't want that done. Skip adaption code by making it look
+        // like we have a match between expected and actual number of
+        // arguments.
+        definitely_matches = true;
+      } else {
+        *definitely_mismatches = true;
+        // Set up x2 for the argument adaptor.
+        Mov(x2, expected.immediate());
+      }
+    }
+
+  } else {  // expected is a register.
+    Operand actual_op = actual.is_immediate() ? Operand(actual.immediate())
+                                              : Operand(actual.reg());
+    // If actual == expected perform a regular invocation.
+    Cmp(expected.reg(), actual_op);
+    B(eq, &regular_invoke);
+    // Otherwise set up x0 for the argument adaptor.
+    Mov(x0, actual_op);
+  }
+
+  // If the argument counts may mismatch, generate a call to the argument
+  // adaptor.
+  if (!definitely_matches) {
+    if (!code_constant.is_null()) {
+      Mov(x3, Operand(code_constant));
+      Add(x3, x3, Code::kHeaderSize - kHeapObjectTag);
+    }
+
+    Handle<Code> adaptor =
+        isolate()->builtins()->ArgumentsAdaptorTrampoline();
+    if (flag == CALL_FUNCTION) {
+      call_wrapper.BeforeCall(CallSize(adaptor));
+      Call(adaptor);
+      call_wrapper.AfterCall();
+      if (!*definitely_mismatches) {
+        // If the arg counts don't match, no extra code is emitted by
+        // MAsm::InvokeCode and we can just fall through.
+        B(done);
+      }
+    } else {
+      Jump(adaptor, RelocInfo::CODE_TARGET);
+    }
+  }
+  Bind(&regular_invoke);
+}
+
+
+void MacroAssembler::InvokeCode(Register code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                InvokeFlag flag,
+                                const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  Label done;
+
+  bool definitely_mismatches = false;
+  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag,
+                 &definitely_mismatches, call_wrapper);
+
+  // If we are certain that actual != expected, then we know InvokePrologue will
+  // have handled the call through the argument adaptor mechanism.
+  // The called function expects the call kind in x5.
+  if (!definitely_mismatches) {
+    if (flag == CALL_FUNCTION) {
+      call_wrapper.BeforeCall(CallSize(code));
+      Call(code);
+      call_wrapper.AfterCall();
+    } else {
+      DCHECK(flag == JUMP_FUNCTION);
+      Jump(code);
+    }
+  }
+
+  // Continue here if InvokePrologue does handle the invocation due to
+  // mismatched parameter counts.
+  Bind(&done);
+}
+
+
+void MacroAssembler::InvokeFunction(Register function,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  // Contract with called JS functions requires that function is passed in x1.
+  // (See FullCodeGenerator::Generate().)
+  DCHECK(function.is(x1));
+
+  Register expected_reg = x2;
+  Register code_reg = x3;
+
+  Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
+  // The number of arguments is stored as an int32_t, and -1 is a marker
+  // (SharedFunctionInfo::kDontAdaptArgumentsSentinel), so we need sign
+  // extension to correctly handle it.
+  Ldr(expected_reg, FieldMemOperand(function,
+                                    JSFunction::kSharedFunctionInfoOffset));
+  Ldrsw(expected_reg,
+        FieldMemOperand(expected_reg,
+                        SharedFunctionInfo::kFormalParameterCountOffset));
+  Ldr(code_reg,
+      FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+
+  ParameterCount expected(expected_reg);
+  InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Register function,
+                                    const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  // You can't call a function without a valid frame.
+  DCHECK(flag == JUMP_FUNCTION || has_frame());
+
+  // Contract with called JS functions requires that function is passed in x1.
+  // (See FullCodeGenerator::Generate().)
+  DCHECK(function.Is(x1));
+
+  Register code_reg = x3;
+
+  // Set up the context.
+  Ldr(cp, FieldMemOperand(function, JSFunction::kContextOffset));
+
+  // We call indirectly through the code field in the function to
+  // allow recompilation to take effect without changing any of the
+  // call sites.
+  Ldr(code_reg, FieldMemOperand(function, JSFunction::kCodeEntryOffset));
+  InvokeCode(code_reg, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::InvokeFunction(Handle<JSFunction> function,
+                                    const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag,
+                                    const CallWrapper& call_wrapper) {
+  // Contract with called JS functions requires that function is passed in x1.
+  // (See FullCodeGenerator::Generate().)
+  __ LoadObject(x1, function);
+  InvokeFunction(x1, expected, actual, flag, call_wrapper);
+}
+
+
+void MacroAssembler::TryConvertDoubleToInt64(Register result,
+                                             DoubleRegister double_input,
+                                             Label* done) {
+  // Try to convert with an FPU convert instruction. It's trivial to compute
+  // the modulo operation on an integer register so we convert to a 64-bit
+  // integer.
+  //
+  // Fcvtzs will saturate to INT64_MIN (0x800...00) or INT64_MAX (0x7ff...ff)
+  // when the double is out of range. NaNs and infinities will be converted to 0
+  // (as ECMA-262 requires).
+  Fcvtzs(result.X(), double_input);
+
+  // The values INT64_MIN (0x800...00) or INT64_MAX (0x7ff...ff) are not
+  // representable using a double, so if the result is one of those then we know
+  // that saturation occured, and we need to manually handle the conversion.
+  //
+  // It is easy to detect INT64_MIN and INT64_MAX because adding or subtracting
+  // 1 will cause signed overflow.
+  Cmp(result.X(), 1);
+  Ccmp(result.X(), -1, VFlag, vc);
+
+  B(vc, done);
+}
+
+
+void MacroAssembler::TruncateDoubleToI(Register result,
+                                       DoubleRegister double_input) {
+  Label done;
+
+  // Try to convert the double to an int64. If successful, the bottom 32 bits
+  // contain our truncated int32 result.
+  TryConvertDoubleToInt64(result, double_input, &done);
+
+  const Register old_stack_pointer = StackPointer();
+  if (csp.Is(old_stack_pointer)) {
+    // This currently only happens during compiler-unittest. If it arises
+    // during regular code generation the DoubleToI stub should be updated to
+    // cope with csp and have an extra parameter indicating which stack pointer
+    // it should use.
+    Push(jssp, xzr);  // Push xzr to maintain csp required 16-bytes alignment.
+    Mov(jssp, csp);
+    SetStackPointer(jssp);
+  }
+
+  // If we fell through then inline version didn't succeed - call stub instead.
+  Push(lr, double_input);
+
+  DoubleToIStub stub(isolate(),
+                     jssp,
+                     result,
+                     0,
+                     true,   // is_truncating
+                     true);  // skip_fastpath
+  CallStub(&stub);  // DoubleToIStub preserves any registers it needs to clobber
+
+  DCHECK_EQ(xzr.SizeInBytes(), double_input.SizeInBytes());
+  Pop(xzr, lr);  // xzr to drop the double input on the stack.
+
+  if (csp.Is(old_stack_pointer)) {
+    Mov(csp, jssp);
+    SetStackPointer(csp);
+    AssertStackConsistency();
+    Pop(xzr, jssp);
+  }
+
+  Bind(&done);
+}
+
+
+void MacroAssembler::TruncateHeapNumberToI(Register result,
+                                           Register object) {
+  Label done;
+  DCHECK(!result.is(object));
+  DCHECK(jssp.Is(StackPointer()));
+
+  Ldr(fp_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
+
+  // Try to convert the double to an int64. If successful, the bottom 32 bits
+  // contain our truncated int32 result.
+  TryConvertDoubleToInt64(result, fp_scratch, &done);
+
+  // If we fell through then inline version didn't succeed - call stub instead.
+  Push(lr);
+  DoubleToIStub stub(isolate(),
+                     object,
+                     result,
+                     HeapNumber::kValueOffset - kHeapObjectTag,
+                     true,   // is_truncating
+                     true);  // skip_fastpath
+  CallStub(&stub);  // DoubleToIStub preserves any registers it needs to clobber
+  Pop(lr);
+
+  Bind(&done);
+}
+
+
+void MacroAssembler::StubPrologue() {
+  DCHECK(StackPointer().Is(jssp));
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  __ Mov(temp, Smi::FromInt(StackFrame::STUB));
+  // Compiled stubs don't age, and so they don't need the predictable code
+  // ageing sequence.
+  __ Push(lr, fp, cp, temp);
+  __ Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
+}
+
+
+void MacroAssembler::Prologue(bool code_pre_aging) {
+  if (code_pre_aging) {
+    Code* stub = Code::GetPreAgedCodeAgeStub(isolate());
+    __ EmitCodeAgeSequence(stub);
+  } else {
+    __ EmitFrameSetupForCodeAgePatching();
+  }
+}
+
+
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
+  DCHECK(jssp.Is(StackPointer()));
+  UseScratchRegisterScope temps(this);
+  Register type_reg = temps.AcquireX();
+  Register code_reg = temps.AcquireX();
+
+  Push(lr, fp, cp);
+  Mov(type_reg, Smi::FromInt(type));
+  Mov(code_reg, Operand(CodeObject()));
+  Push(type_reg, code_reg);
+  // jssp[4] : lr
+  // jssp[3] : fp
+  // jssp[2] : cp
+  // jssp[1] : type
+  // jssp[0] : code object
+
+  // Adjust FP to point to saved FP.
+  Add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp + kPointerSize);
+}
+
+
+void MacroAssembler::LeaveFrame(StackFrame::Type type) {
+  DCHECK(jssp.Is(StackPointer()));
+  // Drop the execution stack down to the frame pointer and restore
+  // the caller frame pointer and return address.
+  Mov(jssp, fp);
+  AssertStackConsistency();
+  Pop(fp, lr);
+}
+
+
+void MacroAssembler::ExitFramePreserveFPRegs() {
+  PushCPURegList(kCallerSavedFP);
+}
+
+
+void MacroAssembler::ExitFrameRestoreFPRegs() {
+  // Read the registers from the stack without popping them. The stack pointer
+  // will be reset as part of the unwinding process.
+  CPURegList saved_fp_regs = kCallerSavedFP;
+  DCHECK(saved_fp_regs.Count() % 2 == 0);
+
+  int offset = ExitFrameConstants::kLastExitFrameField;
+  while (!saved_fp_regs.IsEmpty()) {
+    const CPURegister& dst0 = saved_fp_regs.PopHighestIndex();
+    const CPURegister& dst1 = saved_fp_regs.PopHighestIndex();
+    offset -= 2 * kDRegSize;
+    Ldp(dst1, dst0, MemOperand(fp, offset));
+  }
+}
+
+
+void MacroAssembler::EnterExitFrame(bool save_doubles,
+                                    const Register& scratch,
+                                    int extra_space) {
+  DCHECK(jssp.Is(StackPointer()));
+
+  // Set up the new stack frame.
+  Mov(scratch, Operand(CodeObject()));
+  Push(lr, fp);
+  Mov(fp, StackPointer());
+  Push(xzr, scratch);
+  //          fp[8]: CallerPC (lr)
+  //    fp -> fp[0]: CallerFP (old fp)
+  //          fp[-8]: Space reserved for SPOffset.
+  //  jssp -> fp[-16]: CodeObject()
+  STATIC_ASSERT((2 * kPointerSize) ==
+                ExitFrameConstants::kCallerSPDisplacement);
+  STATIC_ASSERT((1 * kPointerSize) == ExitFrameConstants::kCallerPCOffset);
+  STATIC_ASSERT((0 * kPointerSize) == ExitFrameConstants::kCallerFPOffset);
+  STATIC_ASSERT((-1 * kPointerSize) == ExitFrameConstants::kSPOffset);
+  STATIC_ASSERT((-2 * kPointerSize) == ExitFrameConstants::kCodeOffset);
+
+  // Save the frame pointer and context pointer in the top frame.
+  Mov(scratch, Operand(ExternalReference(Isolate::kCEntryFPAddress,
+                                         isolate())));
+  Str(fp, MemOperand(scratch));
+  Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
+                                         isolate())));
+  Str(cp, MemOperand(scratch));
+
+  STATIC_ASSERT((-2 * kPointerSize) ==
+                ExitFrameConstants::kLastExitFrameField);
+  if (save_doubles) {
+    ExitFramePreserveFPRegs();
+  }
+
+  // Reserve space for the return address and for user requested memory.
+  // We do this before aligning to make sure that we end up correctly
+  // aligned with the minimum of wasted space.
+  Claim(extra_space + 1, kXRegSize);
+  //         fp[8]: CallerPC (lr)
+  //   fp -> fp[0]: CallerFP (old fp)
+  //         fp[-8]: Space reserved for SPOffset.
+  //         fp[-16]: CodeObject()
+  //         fp[-16 - fp_size]: Saved doubles (if save_doubles is true).
+  //         jssp[8]: Extra space reserved for caller (if extra_space != 0).
+  // jssp -> jssp[0]: Space reserved for the return address.
+
+  // Align and synchronize the system stack pointer with jssp.
+  AlignAndSetCSPForFrame();
+  DCHECK(csp.Is(StackPointer()));
+
+  //         fp[8]: CallerPC (lr)
+  //   fp -> fp[0]: CallerFP (old fp)
+  //         fp[-8]: Space reserved for SPOffset.
+  //         fp[-16]: CodeObject()
+  //         fp[-16 - fp_size]: Saved doubles (if save_doubles is true).
+  //         csp[8]: Memory reserved for the caller if extra_space != 0.
+  //                 Alignment padding, if necessary.
+  //  csp -> csp[0]: Space reserved for the return address.
+
+  // ExitFrame::GetStateForFramePointer expects to find the return address at
+  // the memory address immediately below the pointer stored in SPOffset.
+  // It is not safe to derive much else from SPOffset, because the size of the
+  // padding can vary.
+  Add(scratch, csp, kXRegSize);
+  Str(scratch, MemOperand(fp, ExitFrameConstants::kSPOffset));
+}
+
+
+// Leave the current exit frame.
+void MacroAssembler::LeaveExitFrame(bool restore_doubles,
+                                    const Register& scratch,
+                                    bool restore_context) {
+  DCHECK(csp.Is(StackPointer()));
+
+  if (restore_doubles) {
+    ExitFrameRestoreFPRegs();
+  }
+
+  // Restore the context pointer from the top frame.
+  if (restore_context) {
+    Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
+                                           isolate())));
+    Ldr(cp, MemOperand(scratch));
+  }
+
+  if (emit_debug_code()) {
+    // Also emit debug code to clear the cp in the top frame.
+    Mov(scratch, Operand(ExternalReference(Isolate::kContextAddress,
+                                           isolate())));
+    Str(xzr, MemOperand(scratch));
+  }
+  // Clear the frame pointer from the top frame.
+  Mov(scratch, Operand(ExternalReference(Isolate::kCEntryFPAddress,
+                                         isolate())));
+  Str(xzr, MemOperand(scratch));
+
+  // Pop the exit frame.
+  //         fp[8]: CallerPC (lr)
+  //   fp -> fp[0]: CallerFP (old fp)
+  //         fp[...]: The rest of the frame.
+  Mov(jssp, fp);
+  SetStackPointer(jssp);
+  AssertStackConsistency();
+  Pop(fp, lr);
+}
+
+
+void MacroAssembler::SetCounter(StatsCounter* counter, int value,
+                                Register scratch1, Register scratch2) {
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    Mov(scratch1, value);
+    Mov(scratch2, ExternalReference(counter));
+    Str(scratch1, MemOperand(scratch2));
+  }
+}
+
+
+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value,
+                                      Register scratch1, Register scratch2) {
+  DCHECK(value != 0);
+  if (FLAG_native_code_counters && counter->Enabled()) {
+    Mov(scratch2, ExternalReference(counter));
+    Ldr(scratch1, MemOperand(scratch2));
+    Add(scratch1, scratch1, value);
+    Str(scratch1, MemOperand(scratch2));
+  }
+}
+
+
+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value,
+                                      Register scratch1, Register scratch2) {
+  IncrementCounter(counter, -value, scratch1, scratch2);
+}
+
+
+void MacroAssembler::LoadContext(Register dst, int context_chain_length) {
+  if (context_chain_length > 0) {
+    // Move up the chain of contexts to the context containing the slot.
+    Ldr(dst, MemOperand(cp, Context::SlotOffset(Context::PREVIOUS_INDEX)));
+    for (int i = 1; i < context_chain_length; i++) {
+      Ldr(dst, MemOperand(dst, Context::SlotOffset(Context::PREVIOUS_INDEX)));
+    }
+  } else {
+    // Slot is in the current function context.  Move it into the
+    // destination register in case we store into it (the write barrier
+    // cannot be allowed to destroy the context in cp).
+    Mov(dst, cp);
+  }
+}
+
+
+void MacroAssembler::DebugBreak() {
+  Mov(x0, 0);
+  Mov(x1, ExternalReference(Runtime::kDebugBreak, isolate()));
+  CEntryStub ces(isolate(), 1);
+  DCHECK(AllowThisStubCall(&ces));
+  Call(ces.GetCode(), RelocInfo::DEBUG_BREAK);
+}
+
+
+void MacroAssembler::PushTryHandler(StackHandler::Kind kind,
+                                    int handler_index) {
+  DCHECK(jssp.Is(StackPointer()));
+  // Adjust this code if the asserts don't hold.
+  STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
+  STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
+
+  // For the JSEntry handler, we must preserve the live registers x0-x4.
+  // (See JSEntryStub::GenerateBody().)
+
+  unsigned state =
+      StackHandler::IndexField::encode(handler_index) |
+      StackHandler::KindField::encode(kind);
+
+  // Set up the code object and the state for pushing.
+  Mov(x10, Operand(CodeObject()));
+  Mov(x11, state);
+
+  // Push the frame pointer, context, state, and code object.
+  if (kind == StackHandler::JS_ENTRY) {
+    DCHECK(Smi::FromInt(0) == 0);
+    Push(xzr, xzr, x11, x10);
+  } else {
+    Push(fp, cp, x11, x10);
+  }
+
+  // Link the current handler as the next handler.
+  Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
+  Ldr(x10, MemOperand(x11));
+  Push(x10);
+  // Set this new handler as the current one.
+  Str(jssp, MemOperand(x11));
+}
+
+
+void MacroAssembler::PopTryHandler() {
+  STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
+  Pop(x10);
+  Mov(x11, ExternalReference(Isolate::kHandlerAddress, isolate()));
+  Drop(StackHandlerConstants::kSize - kXRegSize, kByteSizeInBytes);
+  Str(x10, MemOperand(x11));
+}
+
+
+void MacroAssembler::Allocate(int object_size,
+                              Register result,
+                              Register scratch1,
+                              Register scratch2,
+                              Label* gc_required,
+                              AllocationFlags flags) {
+  DCHECK(object_size <= Page::kMaxRegularHeapObjectSize);
+  if (!FLAG_inline_new) {
+    if (emit_debug_code()) {
+      // Trash the registers to simulate an allocation failure.
+      // We apply salt to the original zap value to easily spot the values.
+      Mov(result, (kDebugZapValue & ~0xffL) | 0x11L);
+      Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L);
+      Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L);
+    }
+    B(gc_required);
+    return;
+  }
+
+  UseScratchRegisterScope temps(this);
+  Register scratch3 = temps.AcquireX();
+
+  DCHECK(!AreAliased(result, scratch1, scratch2, scratch3));
+  DCHECK(result.Is64Bits() && scratch1.Is64Bits() && scratch2.Is64Bits());
+
+  // Make object size into bytes.
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    object_size *= kPointerSize;
+  }
+  DCHECK(0 == (object_size & kObjectAlignmentMask));
+
+  // Check relative positions of allocation top and limit addresses.
+  // The values must be adjacent in memory to allow the use of LDP.
+  ExternalReference heap_allocation_top =
+      AllocationUtils::GetAllocationTopReference(isolate(), flags);
+  ExternalReference heap_allocation_limit =
+      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
+  intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address());
+  intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address());
+  DCHECK((limit - top) == kPointerSize);
+
+  // Set up allocation top address and object size registers.
+  Register top_address = scratch1;
+  Register allocation_limit = scratch2;
+  Mov(top_address, Operand(heap_allocation_top));
+
+  if ((flags & RESULT_CONTAINS_TOP) == 0) {
+    // Load allocation top into result and the allocation limit.
+    Ldp(result, allocation_limit, MemOperand(top_address));
+  } else {
+    if (emit_debug_code()) {
+      // Assert that result actually contains top on entry.
+      Ldr(scratch3, MemOperand(top_address));
+      Cmp(result, scratch3);
+      Check(eq, kUnexpectedAllocationTop);
+    }
+    // Load the allocation limit. 'result' already contains the allocation top.
+    Ldr(allocation_limit, MemOperand(top_address, limit - top));
+  }
+
+  // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
+  // the same alignment on ARM64.
+  STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+
+  // Calculate new top and bail out if new space is exhausted.
+  Adds(scratch3, result, object_size);
+  Ccmp(scratch3, allocation_limit, CFlag, cc);
+  B(hi, gc_required);
+  Str(scratch3, MemOperand(top_address));
+
+  // Tag the object if requested.
+  if ((flags & TAG_OBJECT) != 0) {
+    ObjectTag(result, result);
+  }
+}
+
+
+void MacroAssembler::Allocate(Register object_size,
+                              Register result,
+                              Register scratch1,
+                              Register scratch2,
+                              Label* gc_required,
+                              AllocationFlags flags) {
+  if (!FLAG_inline_new) {
+    if (emit_debug_code()) {
+      // Trash the registers to simulate an allocation failure.
+      // We apply salt to the original zap value to easily spot the values.
+      Mov(result, (kDebugZapValue & ~0xffL) | 0x11L);
+      Mov(scratch1, (kDebugZapValue & ~0xffL) | 0x21L);
+      Mov(scratch2, (kDebugZapValue & ~0xffL) | 0x21L);
+    }
+    B(gc_required);
+    return;
+  }
+
+  UseScratchRegisterScope temps(this);
+  Register scratch3 = temps.AcquireX();
+
+  DCHECK(!AreAliased(object_size, result, scratch1, scratch2, scratch3));
+  DCHECK(object_size.Is64Bits() && result.Is64Bits() &&
+         scratch1.Is64Bits() && scratch2.Is64Bits());
+
+  // Check relative positions of allocation top and limit addresses.
+  // The values must be adjacent in memory to allow the use of LDP.
+  ExternalReference heap_allocation_top =
+      AllocationUtils::GetAllocationTopReference(isolate(), flags);
+  ExternalReference heap_allocation_limit =
+      AllocationUtils::GetAllocationLimitReference(isolate(), flags);
+  intptr_t top = reinterpret_cast<intptr_t>(heap_allocation_top.address());
+  intptr_t limit = reinterpret_cast<intptr_t>(heap_allocation_limit.address());
+  DCHECK((limit - top) == kPointerSize);
+
+  // Set up allocation top address and object size registers.
+  Register top_address = scratch1;
+  Register allocation_limit = scratch2;
+  Mov(top_address, heap_allocation_top);
+
+  if ((flags & RESULT_CONTAINS_TOP) == 0) {
+    // Load allocation top into result and the allocation limit.
+    Ldp(result, allocation_limit, MemOperand(top_address));
+  } else {
+    if (emit_debug_code()) {
+      // Assert that result actually contains top on entry.
+      Ldr(scratch3, MemOperand(top_address));
+      Cmp(result, scratch3);
+      Check(eq, kUnexpectedAllocationTop);
+    }
+    // Load the allocation limit. 'result' already contains the allocation top.
+    Ldr(allocation_limit, MemOperand(top_address, limit - top));
+  }
+
+  // We can ignore DOUBLE_ALIGNMENT flags here because doubles and pointers have
+  // the same alignment on ARM64.
+  STATIC_ASSERT(kPointerAlignment == kDoubleAlignment);
+
+  // Calculate new top and bail out if new space is exhausted
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    Adds(scratch3, result, Operand(object_size, LSL, kPointerSizeLog2));
+  } else {
+    Adds(scratch3, result, object_size);
+  }
+
+  if (emit_debug_code()) {
+    Tst(scratch3, kObjectAlignmentMask);
+    Check(eq, kUnalignedAllocationInNewSpace);
+  }
+
+  Ccmp(scratch3, allocation_limit, CFlag, cc);
+  B(hi, gc_required);
+  Str(scratch3, MemOperand(top_address));
+
+  // Tag the object if requested.
+  if ((flags & TAG_OBJECT) != 0) {
+    ObjectTag(result, result);
+  }
+}
+
+
+void MacroAssembler::UndoAllocationInNewSpace(Register object,
+                                              Register scratch) {
+  ExternalReference new_space_allocation_top =
+      ExternalReference::new_space_allocation_top_address(isolate());
+
+  // Make sure the object has no tag before resetting top.
+  Bic(object, object, kHeapObjectTagMask);
+#ifdef DEBUG
+  // Check that the object un-allocated is below the current top.
+  Mov(scratch, new_space_allocation_top);
+  Ldr(scratch, MemOperand(scratch));
+  Cmp(object, scratch);
+  Check(lt, kUndoAllocationOfNonAllocatedMemory);
+#endif
+  // Write the address of the object to un-allocate as the current top.
+  Mov(scratch, new_space_allocation_top);
+  Str(object, MemOperand(scratch));
+}
+
+
+void MacroAssembler::AllocateTwoByteString(Register result,
+                                           Register length,
+                                           Register scratch1,
+                                           Register scratch2,
+                                           Register scratch3,
+                                           Label* gc_required) {
+  DCHECK(!AreAliased(result, length, scratch1, scratch2, scratch3));
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  STATIC_ASSERT((SeqTwoByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  Add(scratch1, length, length);  // Length in bytes, not chars.
+  Add(scratch1, scratch1, kObjectAlignmentMask + SeqTwoByteString::kHeaderSize);
+  Bic(scratch1, scratch1, kObjectAlignmentMask);
+
+  // Allocate two-byte string in new space.
+  Allocate(scratch1,
+           result,
+           scratch2,
+           scratch3,
+           gc_required,
+           TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  InitializeNewString(result,
+                      length,
+                      Heap::kStringMapRootIndex,
+                      scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteString(Register result, Register length,
+                                           Register scratch1, Register scratch2,
+                                           Register scratch3,
+                                           Label* gc_required) {
+  DCHECK(!AreAliased(result, length, scratch1, scratch2, scratch3));
+  // Calculate the number of bytes needed for the characters in the string while
+  // observing object alignment.
+  STATIC_ASSERT((SeqOneByteString::kHeaderSize & kObjectAlignmentMask) == 0);
+  STATIC_ASSERT(kCharSize == 1);
+  Add(scratch1, length, kObjectAlignmentMask + SeqOneByteString::kHeaderSize);
+  Bic(scratch1, scratch1, kObjectAlignmentMask);
+
+  // Allocate one-byte string in new space.
+  Allocate(scratch1,
+           result,
+           scratch2,
+           scratch3,
+           gc_required,
+           TAG_OBJECT);
+
+  // Set the map, length and hash field.
+  InitializeNewString(result, length, Heap::kOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+void MacroAssembler::AllocateTwoByteConsString(Register result,
+                                               Register length,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required) {
+  Allocate(ConsString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result,
+                      length,
+                      Heap::kConsStringMapRootIndex,
+                      scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteConsString(Register result, Register length,
+                                               Register scratch1,
+                                               Register scratch2,
+                                               Label* gc_required) {
+  Allocate(ConsString::kSize,
+           result,
+           scratch1,
+           scratch2,
+           gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kConsOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+void MacroAssembler::AllocateTwoByteSlicedString(Register result,
+                                                 Register length,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* gc_required) {
+  DCHECK(!AreAliased(result, length, scratch1, scratch2));
+  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result,
+                      length,
+                      Heap::kSlicedStringMapRootIndex,
+                      scratch1,
+                      scratch2);
+}
+
+
+void MacroAssembler::AllocateOneByteSlicedString(Register result,
+                                                 Register length,
+                                                 Register scratch1,
+                                                 Register scratch2,
+                                                 Label* gc_required) {
+  DCHECK(!AreAliased(result, length, scratch1, scratch2));
+  Allocate(SlicedString::kSize, result, scratch1, scratch2, gc_required,
+           TAG_OBJECT);
+
+  InitializeNewString(result, length, Heap::kSlicedOneByteStringMapRootIndex,
+                      scratch1, scratch2);
+}
+
+
+// Allocates a heap number or jumps to the need_gc label if the young space
+// is full and a scavenge is needed.
+void MacroAssembler::AllocateHeapNumber(Register result,
+                                        Label* gc_required,
+                                        Register scratch1,
+                                        Register scratch2,
+                                        CPURegister value,
+                                        CPURegister heap_number_map,
+                                        MutableMode mode) {
+  DCHECK(!value.IsValid() || value.Is64Bits());
+  UseScratchRegisterScope temps(this);
+
+  // Allocate an object in the heap for the heap number and tag it as a heap
+  // object.
+  Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
+           NO_ALLOCATION_FLAGS);
+
+  Heap::RootListIndex map_index = mode == MUTABLE
+      ? Heap::kMutableHeapNumberMapRootIndex
+      : Heap::kHeapNumberMapRootIndex;
+
+  // Prepare the heap number map.
+  if (!heap_number_map.IsValid()) {
+    // If we have a valid value register, use the same type of register to store
+    // the map so we can use STP to store both in one instruction.
+    if (value.IsValid() && value.IsFPRegister()) {
+      heap_number_map = temps.AcquireD();
+    } else {
+      heap_number_map = scratch1;
+    }
+    LoadRoot(heap_number_map, map_index);
+  }
+  if (emit_debug_code()) {
+    Register map;
+    if (heap_number_map.IsFPRegister()) {
+      map = scratch1;
+      Fmov(map, DoubleRegister(heap_number_map));
+    } else {
+      map = Register(heap_number_map);
+    }
+    AssertRegisterIsRoot(map, map_index);
+  }
+
+  // Store the heap number map and the value in the allocated object.
+  if (value.IsSameSizeAndType(heap_number_map)) {
+    STATIC_ASSERT(HeapObject::kMapOffset + kPointerSize ==
+                  HeapNumber::kValueOffset);
+    Stp(heap_number_map, value, MemOperand(result, HeapObject::kMapOffset));
+  } else {
+    Str(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
+    if (value.IsValid()) {
+      Str(value, MemOperand(result, HeapNumber::kValueOffset));
+    }
+  }
+  ObjectTag(result, result);
+}
+
+
+void MacroAssembler::JumpIfObjectType(Register object,
+                                      Register map,
+                                      Register type_reg,
+                                      InstanceType type,
+                                      Label* if_cond_pass,
+                                      Condition cond) {
+  CompareObjectType(object, map, type_reg, type);
+  B(cond, if_cond_pass);
+}
+
+
+void MacroAssembler::JumpIfNotObjectType(Register object,
+                                         Register map,
+                                         Register type_reg,
+                                         InstanceType type,
+                                         Label* if_not_object) {
+  JumpIfObjectType(object, map, type_reg, type, if_not_object, ne);
+}
+
+
+// Sets condition flags based on comparison, and returns type in type_reg.
+void MacroAssembler::CompareObjectType(Register object,
+                                       Register map,
+                                       Register type_reg,
+                                       InstanceType type) {
+  Ldr(map, FieldMemOperand(object, HeapObject::kMapOffset));
+  CompareInstanceType(map, type_reg, type);
+}
+
+
+// Sets condition flags based on comparison, and returns type in type_reg.
+void MacroAssembler::CompareInstanceType(Register map,
+                                         Register type_reg,
+                                         InstanceType type) {
+  Ldrb(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  Cmp(type_reg, type);
+}
+
+
+void MacroAssembler::CompareObjectMap(Register obj, Heap::RootListIndex index) {
+  UseScratchRegisterScope temps(this);
+  Register obj_map = temps.AcquireX();
+  Ldr(obj_map, FieldMemOperand(obj, HeapObject::kMapOffset));
+  CompareRoot(obj_map, index);
+}
+
+
+void MacroAssembler::CompareObjectMap(Register obj, Register scratch,
+                                      Handle<Map> map) {
+  Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  CompareMap(scratch, map);
+}
+
+
+void MacroAssembler::CompareMap(Register obj_map,
+                                Handle<Map> map) {
+  Cmp(obj_map, Operand(map));
+}
+
+
+void MacroAssembler::CheckMap(Register obj,
+                              Register scratch,
+                              Handle<Map> map,
+                              Label* fail,
+                              SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, fail);
+  }
+
+  CompareObjectMap(obj, scratch, map);
+  B(ne, fail);
+}
+
+
+void MacroAssembler::CheckMap(Register obj,
+                              Register scratch,
+                              Heap::RootListIndex index,
+                              Label* fail,
+                              SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, fail);
+  }
+  Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  JumpIfNotRoot(scratch, index, fail);
+}
+
+
+void MacroAssembler::CheckMap(Register obj_map,
+                              Handle<Map> map,
+                              Label* fail,
+                              SmiCheckType smi_check_type) {
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj_map, fail);
+  }
+
+  CompareMap(obj_map, map);
+  B(ne, fail);
+}
+
+
+void MacroAssembler::DispatchMap(Register obj,
+                                 Register scratch,
+                                 Handle<Map> map,
+                                 Handle<Code> success,
+                                 SmiCheckType smi_check_type) {
+  Label fail;
+  if (smi_check_type == DO_SMI_CHECK) {
+    JumpIfSmi(obj, &fail);
+  }
+  Ldr(scratch, FieldMemOperand(obj, HeapObject::kMapOffset));
+  Cmp(scratch, Operand(map));
+  B(ne, &fail);
+  Jump(success, RelocInfo::CODE_TARGET);
+  Bind(&fail);
+}
+
+
+void MacroAssembler::TestMapBitfield(Register object, uint64_t mask) {
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+  Ldrb(temp, FieldMemOperand(temp, Map::kBitFieldOffset));
+  Tst(temp, mask);
+}
+
+
+void MacroAssembler::LoadElementsKindFromMap(Register result, Register map) {
+  // Load the map's "bit field 2".
+  __ Ldrb(result, FieldMemOperand(map, Map::kBitField2Offset));
+  // Retrieve elements_kind from bit field 2.
+  DecodeField<Map::ElementsKindBits>(result);
+}
+
+
+void MacroAssembler::TryGetFunctionPrototype(Register function,
+                                             Register result,
+                                             Register scratch,
+                                             Label* miss,
+                                             BoundFunctionAction action) {
+  DCHECK(!AreAliased(function, result, scratch));
+
+  Label non_instance;
+  if (action == kMissOnBoundFunction) {
+    // Check that the receiver isn't a smi.
+    JumpIfSmi(function, miss);
+
+    // Check that the function really is a function. Load map into result reg.
+    JumpIfNotObjectType(function, result, scratch, JS_FUNCTION_TYPE, miss);
+
+    Register scratch_w = scratch.W();
+    Ldr(scratch,
+        FieldMemOperand(function, JSFunction::kSharedFunctionInfoOffset));
+    // On 64-bit platforms, compiler hints field is not a smi. See definition of
+    // kCompilerHintsOffset in src/objects.h.
+    Ldr(scratch_w,
+        FieldMemOperand(scratch, SharedFunctionInfo::kCompilerHintsOffset));
+    Tbnz(scratch, SharedFunctionInfo::kBoundFunction, miss);
+
+    // Make sure that the function has an instance prototype.
+    Ldrb(scratch, FieldMemOperand(result, Map::kBitFieldOffset));
+    Tbnz(scratch, Map::kHasNonInstancePrototype, &non_instance);
+  }
+
+  // Get the prototype or initial map from the function.
+  Ldr(result,
+      FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+
+  // If the prototype or initial map is the hole, don't return it and simply
+  // miss the cache instead. This will allow us to allocate a prototype object
+  // on-demand in the runtime system.
+  JumpIfRoot(result, Heap::kTheHoleValueRootIndex, miss);
+
+  // If the function does not have an initial map, we're done.
+  Label done;
+  JumpIfNotObjectType(result, scratch, scratch, MAP_TYPE, &done);
+
+  // Get the prototype from the initial map.
+  Ldr(result, FieldMemOperand(result, Map::kPrototypeOffset));
+
+  if (action == kMissOnBoundFunction) {
+    B(&done);
+
+    // Non-instance prototype: fetch prototype from constructor field in initial
+    // map.
+    Bind(&non_instance);
+    Ldr(result, FieldMemOperand(result, Map::kConstructorOffset));
+  }
+
+  // All done.
+  Bind(&done);
+}
+
+
+void MacroAssembler::CompareRoot(const Register& obj,
+                                 Heap::RootListIndex index) {
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  DCHECK(!AreAliased(obj, temp));
+  LoadRoot(temp, index);
+  Cmp(obj, temp);
+}
+
+
+void MacroAssembler::JumpIfRoot(const Register& obj,
+                                Heap::RootListIndex index,
+                                Label* if_equal) {
+  CompareRoot(obj, index);
+  B(eq, if_equal);
+}
+
+
+void MacroAssembler::JumpIfNotRoot(const Register& obj,
+                                   Heap::RootListIndex index,
+                                   Label* if_not_equal) {
+  CompareRoot(obj, index);
+  B(ne, if_not_equal);
+}
+
+
+void MacroAssembler::CompareAndSplit(const Register& lhs,
+                                     const Operand& rhs,
+                                     Condition cond,
+                                     Label* if_true,
+                                     Label* if_false,
+                                     Label* fall_through) {
+  if ((if_true == if_false) && (if_false == fall_through)) {
+    // Fall through.
+  } else if (if_true == if_false) {
+    B(if_true);
+  } else if (if_false == fall_through) {
+    CompareAndBranch(lhs, rhs, cond, if_true);
+  } else if (if_true == fall_through) {
+    CompareAndBranch(lhs, rhs, NegateCondition(cond), if_false);
+  } else {
+    CompareAndBranch(lhs, rhs, cond, if_true);
+    B(if_false);
+  }
+}
+
+
+void MacroAssembler::TestAndSplit(const Register& reg,
+                                  uint64_t bit_pattern,
+                                  Label* if_all_clear,
+                                  Label* if_any_set,
+                                  Label* fall_through) {
+  if ((if_all_clear == if_any_set) && (if_any_set == fall_through)) {
+    // Fall through.
+  } else if (if_all_clear == if_any_set) {
+    B(if_all_clear);
+  } else if (if_all_clear == fall_through) {
+    TestAndBranchIfAnySet(reg, bit_pattern, if_any_set);
+  } else if (if_any_set == fall_through) {
+    TestAndBranchIfAllClear(reg, bit_pattern, if_all_clear);
+  } else {
+    TestAndBranchIfAnySet(reg, bit_pattern, if_any_set);
+    B(if_all_clear);
+  }
+}
+
+
+void MacroAssembler::CheckFastElements(Register map,
+                                       Register scratch,
+                                       Label* fail) {
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  STATIC_ASSERT(FAST_ELEMENTS == 2);
+  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+  Ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
+  Cmp(scratch, Map::kMaximumBitField2FastHoleyElementValue);
+  B(hi, fail);
+}
+
+
+void MacroAssembler::CheckFastObjectElements(Register map,
+                                             Register scratch,
+                                             Label* fail) {
+  STATIC_ASSERT(FAST_SMI_ELEMENTS == 0);
+  STATIC_ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1);
+  STATIC_ASSERT(FAST_ELEMENTS == 2);
+  STATIC_ASSERT(FAST_HOLEY_ELEMENTS == 3);
+  Ldrb(scratch, FieldMemOperand(map, Map::kBitField2Offset));
+  Cmp(scratch, Operand(Map::kMaximumBitField2FastHoleySmiElementValue));
+  // If cond==ls, set cond=hi, otherwise compare.
+  Ccmp(scratch,
+       Operand(Map::kMaximumBitField2FastHoleyElementValue), CFlag, hi);
+  B(hi, fail);
+}
+
+
+// Note: The ARM version of this clobbers elements_reg, but this version does
+// not. Some uses of this in ARM64 assume that elements_reg will be preserved.
+void MacroAssembler::StoreNumberToDoubleElements(Register value_reg,
+                                                 Register key_reg,
+                                                 Register elements_reg,
+                                                 Register scratch1,
+                                                 FPRegister fpscratch1,
+                                                 Label* fail,
+                                                 int elements_offset) {
+  DCHECK(!AreAliased(value_reg, key_reg, elements_reg, scratch1));
+  Label store_num;
+
+  // Speculatively convert the smi to a double - all smis can be exactly
+  // represented as a double.
+  SmiUntagToDouble(fpscratch1, value_reg, kSpeculativeUntag);
+
+  // If value_reg is a smi, we're done.
+  JumpIfSmi(value_reg, &store_num);
+
+  // Ensure that the object is a heap number.
+  JumpIfNotHeapNumber(value_reg, fail);
+
+  Ldr(fpscratch1, FieldMemOperand(value_reg, HeapNumber::kValueOffset));
+
+  // Canonicalize NaNs.
+  CanonicalizeNaN(fpscratch1);
+
+  // Store the result.
+  Bind(&store_num);
+  Add(scratch1, elements_reg,
+      Operand::UntagSmiAndScale(key_reg, kDoubleSizeLog2));
+  Str(fpscratch1,
+      FieldMemOperand(scratch1,
+                      FixedDoubleArray::kHeaderSize - elements_offset));
+}
+
+
+bool MacroAssembler::AllowThisStubCall(CodeStub* stub) {
+  return has_frame_ || !stub->SometimesSetsUpAFrame();
+}
+
+
+void MacroAssembler::IndexFromHash(Register hash, Register index) {
+  // If the hash field contains an array index pick it out. The assert checks
+  // that the constants for the maximum number of digits for an array index
+  // cached in the hash field and the number of bits reserved for it does not
+  // conflict.
+  DCHECK(TenToThe(String::kMaxCachedArrayIndexLength) <
+         (1 << String::kArrayIndexValueBits));
+  DecodeField<String::ArrayIndexValueBits>(index, hash);
+  SmiTag(index, index);
+}
+
+
+void MacroAssembler::EmitSeqStringSetCharCheck(
+    Register string,
+    Register index,
+    SeqStringSetCharCheckIndexType index_type,
+    Register scratch,
+    uint32_t encoding_mask) {
+  DCHECK(!AreAliased(string, index, scratch));
+
+  if (index_type == kIndexIsSmi) {
+    AssertSmi(index);
+  }
+
+  // Check that string is an object.
+  AssertNotSmi(string, kNonObject);
+
+  // Check that string has an appropriate map.
+  Ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
+  Ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+
+  And(scratch, scratch, kStringRepresentationMask | kStringEncodingMask);
+  Cmp(scratch, encoding_mask);
+  Check(eq, kUnexpectedStringType);
+
+  Ldr(scratch, FieldMemOperand(string, String::kLengthOffset));
+  Cmp(index, index_type == kIndexIsSmi ? scratch : Operand::UntagSmi(scratch));
+  Check(lt, kIndexIsTooLarge);
+
+  DCHECK_EQ(0, Smi::FromInt(0));
+  Cmp(index, 0);
+  Check(ge, kIndexIsNegative);
+}
+
+
+void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
+                                            Register scratch1,
+                                            Register scratch2,
+                                            Label* miss) {
+  DCHECK(!AreAliased(holder_reg, scratch1, scratch2));
+  Label same_contexts;
+
+  // Load current lexical context from the stack frame.
+  Ldr(scratch1, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  // In debug mode, make sure the lexical context is set.
+#ifdef DEBUG
+  Cmp(scratch1, 0);
+  Check(ne, kWeShouldNotHaveAnEmptyLexicalContext);
+#endif
+
+  // Load the native context of the current context.
+  int offset =
+      Context::kHeaderSize + Context::GLOBAL_OBJECT_INDEX * kPointerSize;
+  Ldr(scratch1, FieldMemOperand(scratch1, offset));
+  Ldr(scratch1, FieldMemOperand(scratch1, GlobalObject::kNativeContextOffset));
+
+  // Check the context is a native context.
+  if (emit_debug_code()) {
+    // Read the first word and compare to the global_context_map.
+    Ldr(scratch2, FieldMemOperand(scratch1, HeapObject::kMapOffset));
+    CompareRoot(scratch2, Heap::kNativeContextMapRootIndex);
+    Check(eq, kExpectedNativeContext);
+  }
+
+  // Check if both contexts are the same.
+  Ldr(scratch2, FieldMemOperand(holder_reg,
+                                JSGlobalProxy::kNativeContextOffset));
+  Cmp(scratch1, scratch2);
+  B(&same_contexts, eq);
+
+  // Check the context is a native context.
+  if (emit_debug_code()) {
+    // We're short on scratch registers here, so use holder_reg as a scratch.
+    Push(holder_reg);
+    Register scratch3 = holder_reg;
+
+    CompareRoot(scratch2, Heap::kNullValueRootIndex);
+    Check(ne, kExpectedNonNullContext);
+
+    Ldr(scratch3, FieldMemOperand(scratch2, HeapObject::kMapOffset));
+    CompareRoot(scratch3, Heap::kNativeContextMapRootIndex);
+    Check(eq, kExpectedNativeContext);
+    Pop(holder_reg);
+  }
+
+  // Check that the security token in the calling global object is
+  // compatible with the security token in the receiving global
+  // object.
+  int token_offset = Context::kHeaderSize +
+                     Context::SECURITY_TOKEN_INDEX * kPointerSize;
+
+  Ldr(scratch1, FieldMemOperand(scratch1, token_offset));
+  Ldr(scratch2, FieldMemOperand(scratch2, token_offset));
+  Cmp(scratch1, scratch2);
+  B(miss, ne);
+
+  Bind(&same_contexts);
+}
+
+
+// Compute the hash code from the untagged key. This must be kept in sync with
+// ComputeIntegerHash in utils.h and KeyedLoadGenericStub in
+// code-stub-hydrogen.cc
+void MacroAssembler::GetNumberHash(Register key, Register scratch) {
+  DCHECK(!AreAliased(key, scratch));
+
+  // Xor original key with a seed.
+  LoadRoot(scratch, Heap::kHashSeedRootIndex);
+  Eor(key, key, Operand::UntagSmi(scratch));
+
+  // The algorithm uses 32-bit integer values.
+  key = key.W();
+  scratch = scratch.W();
+
+  // Compute the hash code from the untagged key.  This must be kept in sync
+  // with ComputeIntegerHash in utils.h.
+  //
+  // hash = ~hash + (hash <<1 15);
+  Mvn(scratch, key);
+  Add(key, scratch, Operand(key, LSL, 15));
+  // hash = hash ^ (hash >> 12);
+  Eor(key, key, Operand(key, LSR, 12));
+  // hash = hash + (hash << 2);
+  Add(key, key, Operand(key, LSL, 2));
+  // hash = hash ^ (hash >> 4);
+  Eor(key, key, Operand(key, LSR, 4));
+  // hash = hash * 2057;
+  Mov(scratch, Operand(key, LSL, 11));
+  Add(key, key, Operand(key, LSL, 3));
+  Add(key, key, scratch);
+  // hash = hash ^ (hash >> 16);
+  Eor(key, key, Operand(key, LSR, 16));
+}
+
+
+void MacroAssembler::LoadFromNumberDictionary(Label* miss,
+                                              Register elements,
+                                              Register key,
+                                              Register result,
+                                              Register scratch0,
+                                              Register scratch1,
+                                              Register scratch2,
+                                              Register scratch3) {
+  DCHECK(!AreAliased(elements, key, scratch0, scratch1, scratch2, scratch3));
+
+  Label done;
+
+  SmiUntag(scratch0, key);
+  GetNumberHash(scratch0, scratch1);
+
+  // Compute the capacity mask.
+  Ldrsw(scratch1,
+        UntagSmiFieldMemOperand(elements,
+                                SeededNumberDictionary::kCapacityOffset));
+  Sub(scratch1, scratch1, 1);
+
+  // Generate an unrolled loop that performs a few probes before giving up.
+  for (int i = 0; i < kNumberDictionaryProbes; i++) {
+    // Compute the masked index: (hash + i + i * i) & mask.
+    if (i > 0) {
+      Add(scratch2, scratch0, SeededNumberDictionary::GetProbeOffset(i));
+    } else {
+      Mov(scratch2, scratch0);
+    }
+    And(scratch2, scratch2, scratch1);
+
+    // Scale the index by multiplying by the element size.
+    DCHECK(SeededNumberDictionary::kEntrySize == 3);
+    Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
+
+    // Check if the key is identical to the name.
+    Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
+    Ldr(scratch3,
+        FieldMemOperand(scratch2,
+                        SeededNumberDictionary::kElementsStartOffset));
+    Cmp(key, scratch3);
+    if (i != (kNumberDictionaryProbes - 1)) {
+      B(eq, &done);
+    } else {
+      B(ne, miss);
+    }
+  }
+
+  Bind(&done);
+  // Check that the value is a normal property.
+  const int kDetailsOffset =
+      SeededNumberDictionary::kElementsStartOffset + 2 * kPointerSize;
+  Ldrsw(scratch1, UntagSmiFieldMemOperand(scratch2, kDetailsOffset));
+  TestAndBranchIfAnySet(scratch1, PropertyDetails::TypeField::kMask, miss);
+
+  // Get the value at the masked, scaled index and return.
+  const int kValueOffset =
+      SeededNumberDictionary::kElementsStartOffset + kPointerSize;
+  Ldr(result, FieldMemOperand(scratch2, kValueOffset));
+}
+
+
+void MacroAssembler::RememberedSetHelper(Register object,  // For debug tests.
+                                         Register address,
+                                         Register scratch1,
+                                         SaveFPRegsMode fp_mode,
+                                         RememberedSetFinalAction and_then) {
+  DCHECK(!AreAliased(object, address, scratch1));
+  Label done, store_buffer_overflow;
+  if (emit_debug_code()) {
+    Label ok;
+    JumpIfNotInNewSpace(object, &ok);
+    Abort(kRememberedSetPointerInNewSpace);
+    bind(&ok);
+  }
+  UseScratchRegisterScope temps(this);
+  Register scratch2 = temps.AcquireX();
+
+  // Load store buffer top.
+  Mov(scratch2, ExternalReference::store_buffer_top(isolate()));
+  Ldr(scratch1, MemOperand(scratch2));
+  // Store pointer to buffer and increment buffer top.
+  Str(address, MemOperand(scratch1, kPointerSize, PostIndex));
+  // Write back new top of buffer.
+  Str(scratch1, MemOperand(scratch2));
+  // Call stub on end of buffer.
+  // Check for end of buffer.
+  DCHECK(StoreBuffer::kStoreBufferOverflowBit ==
+         (1 << (14 + kPointerSizeLog2)));
+  if (and_then == kFallThroughAtEnd) {
+    Tbz(scratch1, (14 + kPointerSizeLog2), &done);
+  } else {
+    DCHECK(and_then == kReturnAtEnd);
+    Tbnz(scratch1, (14 + kPointerSizeLog2), &store_buffer_overflow);
+    Ret();
+  }
+
+  Bind(&store_buffer_overflow);
+  Push(lr);
+  StoreBufferOverflowStub store_buffer_overflow_stub(isolate(), fp_mode);
+  CallStub(&store_buffer_overflow_stub);
+  Pop(lr);
+
+  Bind(&done);
+  if (and_then == kReturnAtEnd) {
+    Ret();
+  }
+}
+
+
+void MacroAssembler::PopSafepointRegisters() {
+  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
+  PopXRegList(kSafepointSavedRegisters);
+  Drop(num_unsaved);
+}
+
+
+void MacroAssembler::PushSafepointRegisters() {
+  // Safepoints expect a block of kNumSafepointRegisters values on the stack, so
+  // adjust the stack for unsaved registers.
+  const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
+  DCHECK(num_unsaved >= 0);
+  Claim(num_unsaved);
+  PushXRegList(kSafepointSavedRegisters);
+}
+
+
+void MacroAssembler::PushSafepointRegistersAndDoubles() {
+  PushSafepointRegisters();
+  PushCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
+                            FPRegister::kAllocatableFPRegisters));
+}
+
+
+void MacroAssembler::PopSafepointRegistersAndDoubles() {
+  PopCPURegList(CPURegList(CPURegister::kFPRegister, kDRegSizeInBits,
+                           FPRegister::kAllocatableFPRegisters));
+  PopSafepointRegisters();
+}
+
+
+int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
+  // Make sure the safepoint registers list is what we expect.
+  DCHECK(CPURegList::GetSafepointSavedRegisters().list() == 0x6ffcffff);
+
+  // Safepoint registers are stored contiguously on the stack, but not all the
+  // registers are saved. The following registers are excluded:
+  //  - x16 and x17 (ip0 and ip1) because they shouldn't be preserved outside of
+  //    the macro assembler.
+  //  - x28 (jssp) because JS stack pointer doesn't need to be included in
+  //    safepoint registers.
+  //  - x31 (csp) because the system stack pointer doesn't need to be included
+  //    in safepoint registers.
+  //
+  // This function implements the mapping of register code to index into the
+  // safepoint register slots.
+  if ((reg_code >= 0) && (reg_code <= 15)) {
+    return reg_code;
+  } else if ((reg_code >= 18) && (reg_code <= 27)) {
+    // Skip ip0 and ip1.
+    return reg_code - 2;
+  } else if ((reg_code == 29) || (reg_code == 30)) {
+    // Also skip jssp.
+    return reg_code - 3;
+  } else {
+    // This register has no safepoint register slot.
+    UNREACHABLE();
+    return -1;
+  }
+}
+
+
+void MacroAssembler::CheckPageFlagSet(const Register& object,
+                                      const Register& scratch,
+                                      int mask,
+                                      Label* if_any_set) {
+  And(scratch, object, ~Page::kPageAlignmentMask);
+  Ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
+  TestAndBranchIfAnySet(scratch, mask, if_any_set);
+}
+
+
+void MacroAssembler::CheckPageFlagClear(const Register& object,
+                                        const Register& scratch,
+                                        int mask,
+                                        Label* if_all_clear) {
+  And(scratch, object, ~Page::kPageAlignmentMask);
+  Ldr(scratch, MemOperand(scratch, MemoryChunk::kFlagsOffset));
+  TestAndBranchIfAllClear(scratch, mask, if_all_clear);
+}
+
+
+void MacroAssembler::RecordWriteField(
+    Register object,
+    int offset,
+    Register value,
+    Register scratch,
+    LinkRegisterStatus lr_status,
+    SaveFPRegsMode save_fp,
+    RememberedSetAction remembered_set_action,
+    SmiCheck smi_check,
+    PointersToHereCheck pointers_to_here_check_for_value) {
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of Smis.
+  Label done;
+
+  // Skip the barrier if writing a smi.
+  if (smi_check == INLINE_SMI_CHECK) {
+    JumpIfSmi(value, &done);
+  }
+
+  // Although the object register is tagged, the offset is relative to the start
+  // of the object, so offset must be a multiple of kPointerSize.
+  DCHECK(IsAligned(offset, kPointerSize));
+
+  Add(scratch, object, offset - kHeapObjectTag);
+  if (emit_debug_code()) {
+    Label ok;
+    Tst(scratch, (1 << kPointerSizeLog2) - 1);
+    B(eq, &ok);
+    Abort(kUnalignedCellInWriteBarrier);
+    Bind(&ok);
+  }
+
+  RecordWrite(object,
+              scratch,
+              value,
+              lr_status,
+              save_fp,
+              remembered_set_action,
+              OMIT_SMI_CHECK,
+              pointers_to_here_check_for_value);
+
+  Bind(&done);
+
+  // Clobber clobbered input registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    Mov(value, Operand(bit_cast<int64_t>(kZapValue + 4)));
+    Mov(scratch, Operand(bit_cast<int64_t>(kZapValue + 8)));
+  }
+}
+
+
+// Will clobber: object, map, dst.
+// If lr_status is kLRHasBeenSaved, lr will also be clobbered.
+void MacroAssembler::RecordWriteForMap(Register object,
+                                       Register map,
+                                       Register dst,
+                                       LinkRegisterStatus lr_status,
+                                       SaveFPRegsMode fp_mode) {
+  ASM_LOCATION("MacroAssembler::RecordWrite");
+  DCHECK(!AreAliased(object, map));
+
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    CompareObjectMap(map, temp, isolate()->factory()->meta_map());
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  if (!FLAG_incremental_marking) {
+    return;
+  }
+
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+    Cmp(temp, map);
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of smis and stores into the young generation.
+  Label done;
+
+  // A single check of the map's pages interesting flag suffices, since it is
+  // only set during incremental collection, and then it's also guaranteed that
+  // the from object's page's interesting flag is also set.  This optimization
+  // relies on the fact that maps can never be in new space.
+  CheckPageFlagClear(map,
+                     map,  // Used as scratch.
+                     MemoryChunk::kPointersToHereAreInterestingMask,
+                     &done);
+
+  // Record the actual write.
+  if (lr_status == kLRHasNotBeenSaved) {
+    Push(lr);
+  }
+  Add(dst, object, HeapObject::kMapOffset - kHeapObjectTag);
+  RecordWriteStub stub(isolate(), object, map, dst, OMIT_REMEMBERED_SET,
+                       fp_mode);
+  CallStub(&stub);
+  if (lr_status == kLRHasNotBeenSaved) {
+    Pop(lr);
+  }
+
+  Bind(&done);
+
+  // Count number of write barriers in generated code.
+  isolate()->counters()->write_barriers_static()->Increment();
+  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, map,
+                   dst);
+
+  // Clobber clobbered registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    Mov(dst, Operand(bit_cast<int64_t>(kZapValue + 12)));
+    Mov(map, Operand(bit_cast<int64_t>(kZapValue + 16)));
+  }
+}
+
+
+// Will clobber: object, address, value.
+// If lr_status is kLRHasBeenSaved, lr will also be clobbered.
+//
+// The register 'object' contains a heap object pointer. The heap object tag is
+// shifted away.
+void MacroAssembler::RecordWrite(
+    Register object,
+    Register address,
+    Register value,
+    LinkRegisterStatus lr_status,
+    SaveFPRegsMode fp_mode,
+    RememberedSetAction remembered_set_action,
+    SmiCheck smi_check,
+    PointersToHereCheck pointers_to_here_check_for_value) {
+  ASM_LOCATION("MacroAssembler::RecordWrite");
+  DCHECK(!AreAliased(object, value));
+
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+
+    Ldr(temp, MemOperand(address));
+    Cmp(temp, value);
+    Check(eq, kWrongAddressOrValuePassedToRecordWrite);
+  }
+
+  // First, check if a write barrier is even needed. The tests below
+  // catch stores of smis and stores into the young generation.
+  Label done;
+
+  if (smi_check == INLINE_SMI_CHECK) {
+    DCHECK_EQ(0, kSmiTag);
+    JumpIfSmi(value, &done);
+  }
+
+  if (pointers_to_here_check_for_value != kPointersToHereAreAlwaysInteresting) {
+    CheckPageFlagClear(value,
+                       value,  // Used as scratch.
+                       MemoryChunk::kPointersToHereAreInterestingMask,
+                       &done);
+  }
+  CheckPageFlagClear(object,
+                     value,  // Used as scratch.
+                     MemoryChunk::kPointersFromHereAreInterestingMask,
+                     &done);
+
+  // Record the actual write.
+  if (lr_status == kLRHasNotBeenSaved) {
+    Push(lr);
+  }
+  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
+                       fp_mode);
+  CallStub(&stub);
+  if (lr_status == kLRHasNotBeenSaved) {
+    Pop(lr);
+  }
+
+  Bind(&done);
+
+  // Count number of write barriers in generated code.
+  isolate()->counters()->write_barriers_static()->Increment();
+  IncrementCounter(isolate()->counters()->write_barriers_dynamic(), 1, address,
+                   value);
+
+  // Clobber clobbered registers when running with the debug-code flag
+  // turned on to provoke errors.
+  if (emit_debug_code()) {
+    Mov(address, Operand(bit_cast<int64_t>(kZapValue + 12)));
+    Mov(value, Operand(bit_cast<int64_t>(kZapValue + 16)));
+  }
+}
+
+
+void MacroAssembler::AssertHasValidColor(const Register& reg) {
+  if (emit_debug_code()) {
+    // The bit sequence is backward. The first character in the string
+    // represents the least significant bit.
+    DCHECK(strcmp(Marking::kImpossibleBitPattern, "01") == 0);
+
+    Label color_is_valid;
+    Tbnz(reg, 0, &color_is_valid);
+    Tbz(reg, 1, &color_is_valid);
+    Abort(kUnexpectedColorFound);
+    Bind(&color_is_valid);
+  }
+}
+
+
+void MacroAssembler::GetMarkBits(Register addr_reg,
+                                 Register bitmap_reg,
+                                 Register shift_reg) {
+  DCHECK(!AreAliased(addr_reg, bitmap_reg, shift_reg));
+  DCHECK(addr_reg.Is64Bits() && bitmap_reg.Is64Bits() && shift_reg.Is64Bits());
+  // addr_reg is divided into fields:
+  // |63        page base        20|19    high      8|7   shift   3|2  0|
+  // 'high' gives the index of the cell holding color bits for the object.
+  // 'shift' gives the offset in the cell for this object's color.
+  const int kShiftBits = kPointerSizeLog2 + Bitmap::kBitsPerCellLog2;
+  UseScratchRegisterScope temps(this);
+  Register temp = temps.AcquireX();
+  Ubfx(temp, addr_reg, kShiftBits, kPageSizeBits - kShiftBits);
+  Bic(bitmap_reg, addr_reg, Page::kPageAlignmentMask);
+  Add(bitmap_reg, bitmap_reg, Operand(temp, LSL, Bitmap::kBytesPerCellLog2));
+  // bitmap_reg:
+  // |63        page base        20|19 zeros 15|14      high      3|2  0|
+  Ubfx(shift_reg, addr_reg, kPointerSizeLog2, Bitmap::kBitsPerCellLog2);
+}
+
+
+void MacroAssembler::HasColor(Register object,
+                              Register bitmap_scratch,
+                              Register shift_scratch,
+                              Label* has_color,
+                              int first_bit,
+                              int second_bit) {
+  // See mark-compact.h for color definitions.
+  DCHECK(!AreAliased(object, bitmap_scratch, shift_scratch));
+
+  GetMarkBits(object, bitmap_scratch, shift_scratch);
+  Ldr(bitmap_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  // Shift the bitmap down to get the color of the object in bits [1:0].
+  Lsr(bitmap_scratch, bitmap_scratch, shift_scratch);
+
+  AssertHasValidColor(bitmap_scratch);
+
+  // These bit sequences are backwards. The first character in the string
+  // represents the least significant bit.
+  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
+  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+  DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+
+  // Check for the color.
+  if (first_bit == 0) {
+    // Checking for white.
+    DCHECK(second_bit == 0);
+    // We only need to test the first bit.
+    Tbz(bitmap_scratch, 0, has_color);
+  } else {
+    Label other_color;
+    // Checking for grey or black.
+    Tbz(bitmap_scratch, 0, &other_color);
+    if (second_bit == 0) {
+      Tbz(bitmap_scratch, 1, has_color);
+    } else {
+      Tbnz(bitmap_scratch, 1, has_color);
+    }
+    Bind(&other_color);
+  }
+
+  // Fall through if it does not have the right color.
+}
+
+
+void MacroAssembler::CheckMapDeprecated(Handle<Map> map,
+                                        Register scratch,
+                                        Label* if_deprecated) {
+  if (map->CanBeDeprecated()) {
+    Mov(scratch, Operand(map));
+    Ldrsw(scratch, FieldMemOperand(scratch, Map::kBitField3Offset));
+    TestAndBranchIfAnySet(scratch, Map::Deprecated::kMask, if_deprecated);
+  }
+}
+
+
+void MacroAssembler::JumpIfBlack(Register object,
+                                 Register scratch0,
+                                 Register scratch1,
+                                 Label* on_black) {
+  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+  HasColor(object, scratch0, scratch1, on_black, 1, 0);  // kBlackBitPattern.
+}
+
+
+void MacroAssembler::JumpIfDictionaryInPrototypeChain(
+    Register object,
+    Register scratch0,
+    Register scratch1,
+    Label* found) {
+  DCHECK(!AreAliased(object, scratch0, scratch1));
+  Factory* factory = isolate()->factory();
+  Register current = scratch0;
+  Label loop_again;
+
+  // Scratch contains elements pointer.
+  Mov(current, object);
+
+  // Loop based on the map going up the prototype chain.
+  Bind(&loop_again);
+  Ldr(current, FieldMemOperand(current, HeapObject::kMapOffset));
+  Ldrb(scratch1, FieldMemOperand(current, Map::kBitField2Offset));
+  DecodeField<Map::ElementsKindBits>(scratch1);
+  CompareAndBranch(scratch1, DICTIONARY_ELEMENTS, eq, found);
+  Ldr(current, FieldMemOperand(current, Map::kPrototypeOffset));
+  CompareAndBranch(current, Operand(factory->null_value()), ne, &loop_again);
+}
+
+
+void MacroAssembler::GetRelocatedValueLocation(Register ldr_location,
+                                               Register result) {
+  DCHECK(!result.Is(ldr_location));
+  const uint32_t kLdrLitOffset_lsb = 5;
+  const uint32_t kLdrLitOffset_width = 19;
+  Ldr(result, MemOperand(ldr_location));
+  if (emit_debug_code()) {
+    And(result, result, LoadLiteralFMask);
+    Cmp(result, LoadLiteralFixed);
+    Check(eq, kTheInstructionToPatchShouldBeAnLdrLiteral);
+    // The instruction was clobbered. Reload it.
+    Ldr(result, MemOperand(ldr_location));
+  }
+  Sbfx(result, result, kLdrLitOffset_lsb, kLdrLitOffset_width);
+  Add(result, ldr_location, Operand(result, LSL, kWordSizeInBytesLog2));
+}
+
+
+void MacroAssembler::EnsureNotWhite(
+    Register value,
+    Register bitmap_scratch,
+    Register shift_scratch,
+    Register load_scratch,
+    Register length_scratch,
+    Label* value_is_white_and_not_data) {
+  DCHECK(!AreAliased(
+      value, bitmap_scratch, shift_scratch, load_scratch, length_scratch));
+
+  // These bit sequences are backwards. The first character in the string
+  // represents the least significant bit.
+  DCHECK(strcmp(Marking::kWhiteBitPattern, "00") == 0);
+  DCHECK(strcmp(Marking::kBlackBitPattern, "10") == 0);
+  DCHECK(strcmp(Marking::kGreyBitPattern, "11") == 0);
+
+  GetMarkBits(value, bitmap_scratch, shift_scratch);
+  Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  Lsr(load_scratch, load_scratch, shift_scratch);
+
+  AssertHasValidColor(load_scratch);
+
+  // If the value is black or grey we don't need to do anything.
+  // Since both black and grey have a 1 in the first position and white does
+  // not have a 1 there we only need to check one bit.
+  Label done;
+  Tbnz(load_scratch, 0, &done);
+
+  // Value is white.  We check whether it is data that doesn't need scanning.
+  Register map = load_scratch;  // Holds map while checking type.
+  Label is_data_object;
+
+  // Check for heap-number.
+  Ldr(map, FieldMemOperand(value, HeapObject::kMapOffset));
+  Mov(length_scratch, HeapNumber::kSize);
+  JumpIfRoot(map, Heap::kHeapNumberMapRootIndex, &is_data_object);
+
+  // Check for strings.
+  DCHECK(kIsIndirectStringTag == 1 && kIsIndirectStringMask == 1);
+  DCHECK(kNotStringTag == 0x80 && kIsNotStringMask == 0x80);
+  // If it's a string and it's not a cons string then it's an object containing
+  // no GC pointers.
+  Register instance_type = load_scratch;
+  Ldrb(instance_type, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  TestAndBranchIfAnySet(instance_type,
+                        kIsIndirectStringMask | kIsNotStringMask,
+                        value_is_white_and_not_data);
+
+  // It's a non-indirect (non-cons and non-slice) string.
+  // If it's external, the length is just ExternalString::kSize.
+  // Otherwise it's String::kHeaderSize + string->length() * (1 or 2).
+  // External strings are the only ones with the kExternalStringTag bit
+  // set.
+  DCHECK_EQ(0, kSeqStringTag & kExternalStringTag);
+  DCHECK_EQ(0, kConsStringTag & kExternalStringTag);
+  Mov(length_scratch, ExternalString::kSize);
+  TestAndBranchIfAnySet(instance_type, kExternalStringTag, &is_data_object);
+
+  // Sequential string, either Latin1 or UC16.
+  // For Latin1 (char-size of 1) we shift the smi tag away to get the length.
+  // For UC16 (char-size of 2) we just leave the smi tag in place, thereby
+  // getting the length multiplied by 2.
+  DCHECK(kOneByteStringTag == 4 && kStringEncodingMask == 4);
+  Ldrsw(length_scratch, UntagSmiFieldMemOperand(value,
+                                                String::kLengthOffset));
+  Tst(instance_type, kStringEncodingMask);
+  Cset(load_scratch, eq);
+  Lsl(length_scratch, length_scratch, load_scratch);
+  Add(length_scratch,
+      length_scratch,
+      SeqString::kHeaderSize + kObjectAlignmentMask);
+  Bic(length_scratch, length_scratch, kObjectAlignmentMask);
+
+  Bind(&is_data_object);
+  // Value is a data object, and it is white.  Mark it black.  Since we know
+  // that the object is white we can make it black by flipping one bit.
+  Register mask = shift_scratch;
+  Mov(load_scratch, 1);
+  Lsl(mask, load_scratch, shift_scratch);
+
+  Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+  Orr(load_scratch, load_scratch, mask);
+  Str(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kHeaderSize));
+
+  Bic(bitmap_scratch, bitmap_scratch, Page::kPageAlignmentMask);
+  Ldr(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
+  Add(load_scratch, load_scratch, length_scratch);
+  Str(load_scratch, MemOperand(bitmap_scratch, MemoryChunk::kLiveBytesOffset));
+
+  Bind(&done);
+}
+
+
+void MacroAssembler::Assert(Condition cond, BailoutReason reason) {
+  if (emit_debug_code()) {
+    Check(cond, reason);
+  }
+}
+
+
+
+void MacroAssembler::AssertRegisterIsClear(Register reg, BailoutReason reason) {
+  if (emit_debug_code()) {
+    CheckRegisterIsClear(reg, reason);
+  }
+}
+
+
+void MacroAssembler::AssertRegisterIsRoot(Register reg,
+                                          Heap::RootListIndex index,
+                                          BailoutReason reason) {
+  if (emit_debug_code()) {
+    CompareRoot(reg, index);
+    Check(eq, reason);
+  }
+}
+
+
+void MacroAssembler::AssertFastElements(Register elements) {
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+    Label ok;
+    Ldr(temp, FieldMemOperand(elements, HeapObject::kMapOffset));
+    JumpIfRoot(temp, Heap::kFixedArrayMapRootIndex, &ok);
+    JumpIfRoot(temp, Heap::kFixedDoubleArrayMapRootIndex, &ok);
+    JumpIfRoot(temp, Heap::kFixedCOWArrayMapRootIndex, &ok);
+    Abort(kJSObjectWithFastElementsMapHasSlowElements);
+    Bind(&ok);
+  }
+}
+
+
+void MacroAssembler::AssertIsString(const Register& object) {
+  if (emit_debug_code()) {
+    UseScratchRegisterScope temps(this);
+    Register temp = temps.AcquireX();
+    STATIC_ASSERT(kSmiTag == 0);
+    Tst(object, kSmiTagMask);
+    Check(ne, kOperandIsNotAString);
+    Ldr(temp, FieldMemOperand(object, HeapObject::kMapOffset));
+    CompareInstanceType(temp, temp, FIRST_NONSTRING_TYPE);
+    Check(lo, kOperandIsNotAString);
+  }
+}
+
+
+void MacroAssembler::Check(Condition cond, BailoutReason reason) {
+  Label ok;
+  B(cond, &ok);
+  Abort(reason);
+  // Will not return here.
+  Bind(&ok);
+}
+
+
+void MacroAssembler::CheckRegisterIsClear(Register reg, BailoutReason reason) {
+  Label ok;
+  Cbz(reg, &ok);
+  Abort(reason);
+  // Will not return here.
+  Bind(&ok);
+}
+
+
+void MacroAssembler::Abort(BailoutReason reason) {
+#ifdef DEBUG
+  RecordComment("Abort message: ");
+  RecordComment(GetBailoutReason(reason));
+
+  if (FLAG_trap_on_abort) {
+    Brk(0);
+    return;
+  }
+#endif
+
+  // Abort is used in some contexts where csp is the stack pointer. In order to
+  // simplify the CallRuntime code, make sure that jssp is the stack pointer.
+  // There is no risk of register corruption here because Abort doesn't return.
+  Register old_stack_pointer = StackPointer();
+  SetStackPointer(jssp);
+  Mov(jssp, old_stack_pointer);
+
+  // We need some scratch registers for the MacroAssembler, so make sure we have
+  // some. This is safe here because Abort never returns.
+  RegList old_tmp_list = TmpList()->list();
+  TmpList()->Combine(MacroAssembler::DefaultTmpList());
+
+  if (use_real_aborts()) {
+    // Avoid infinite recursion; Push contains some assertions that use Abort.
+    NoUseRealAbortsScope no_real_aborts(this);
+
+    Mov(x0, Smi::FromInt(reason));
+    Push(x0);
+
+    if (!has_frame_) {
+      // We don't actually want to generate a pile of code for this, so just
+      // claim there is a stack frame, without generating one.
+      FrameScope scope(this, StackFrame::NONE);
+      CallRuntime(Runtime::kAbort, 1);
+    } else {
+      CallRuntime(Runtime::kAbort, 1);
+    }
+  } else {
+    // Load the string to pass to Printf.
+    Label msg_address;
+    Adr(x0, &msg_address);
+
+    // Call Printf directly to report the error.
+    CallPrintf();
+
+    // We need a way to stop execution on both the simulator and real hardware,
+    // and Unreachable() is the best option.
+    Unreachable();
+
+    // Emit the message string directly in the instruction stream.
+    {
+      BlockPoolsScope scope(this);
+      Bind(&msg_address);
+      EmitStringData(GetBailoutReason(reason));
+    }
+  }
+
+  SetStackPointer(old_stack_pointer);
+  TmpList()->set_list(old_tmp_list);
+}
+
+
+void MacroAssembler::LoadTransitionedArrayMapConditional(
+    ElementsKind expected_kind,
+    ElementsKind transitioned_kind,
+    Register map_in_out,
+    Register scratch1,
+    Register scratch2,
+    Label* no_map_match) {
+  // Load the global or builtins object from the current context.
+  Ldr(scratch1, GlobalObjectMemOperand());
+  Ldr(scratch1, FieldMemOperand(scratch1, GlobalObject::kNativeContextOffset));
+
+  // Check that the function's map is the same as the expected cached map.
+  Ldr(scratch1, ContextMemOperand(scratch1, Context::JS_ARRAY_MAPS_INDEX));
+  size_t offset = (expected_kind * kPointerSize) + FixedArrayBase::kHeaderSize;
+  Ldr(scratch2, FieldMemOperand(scratch1, offset));
+  Cmp(map_in_out, scratch2);
+  B(ne, no_map_match);
+
+  // Use the transitioned cached map.
+  offset = (transitioned_kind * kPointerSize) + FixedArrayBase::kHeaderSize;
+  Ldr(map_in_out, FieldMemOperand(scratch1, offset));
+}
+
+
+void MacroAssembler::LoadGlobalFunction(int index, Register function) {
+  // Load the global or builtins object from the current context.
+  Ldr(function, GlobalObjectMemOperand());
+  // Load the native context from the global or builtins object.
+  Ldr(function, FieldMemOperand(function,
+                                GlobalObject::kNativeContextOffset));
+  // Load the function from the native context.
+  Ldr(function, ContextMemOperand(function, index));
+}
+
+
+void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
+                                                  Register map,
+                                                  Register scratch) {
+  // Load the initial map. The global functions all have initial maps.
+  Ldr(map, FieldMemOperand(function, JSFunction::kPrototypeOrInitialMapOffset));
+  if (emit_debug_code()) {
+    Label ok, fail;
+    CheckMap(map, scratch, Heap::kMetaMapRootIndex, &fail, DO_SMI_CHECK);
+    B(&ok);
+    Bind(&fail);
+    Abort(kGlobalFunctionsMustHaveInitialMap);
+    Bind(&ok);
+  }
+}
+
+
+// This is the main Printf implementation. All other Printf variants call
+// PrintfNoPreserve after setting up one or more PreserveRegisterScopes.
+void MacroAssembler::PrintfNoPreserve(const char * format,
+                                      const CPURegister& arg0,
+                                      const CPURegister& arg1,
+                                      const CPURegister& arg2,
+                                      const CPURegister& arg3) {
+  // We cannot handle a caller-saved stack pointer. It doesn't make much sense
+  // in most cases anyway, so this restriction shouldn't be too serious.
+  DCHECK(!kCallerSaved.IncludesAliasOf(__ StackPointer()));
+
+  // The provided arguments, and their proper procedure-call standard registers.
+  CPURegister args[kPrintfMaxArgCount] = {arg0, arg1, arg2, arg3};
+  CPURegister pcs[kPrintfMaxArgCount] = {NoReg, NoReg, NoReg, NoReg};
+
+  int arg_count = kPrintfMaxArgCount;
+
+  // The PCS varargs registers for printf. Note that x0 is used for the printf
+  // format string.
+  static const CPURegList kPCSVarargs =
+      CPURegList(CPURegister::kRegister, kXRegSizeInBits, 1, arg_count);
+  static const CPURegList kPCSVarargsFP =
+      CPURegList(CPURegister::kFPRegister, kDRegSizeInBits, 0, arg_count - 1);
+
+  // We can use caller-saved registers as scratch values, except for the
+  // arguments and the PCS registers where they might need to go.
+  CPURegList tmp_list = kCallerSaved;
+  tmp_list.Remove(x0);      // Used to pass the format string.
+  tmp_list.Remove(kPCSVarargs);
+  tmp_list.Remove(arg0, arg1, arg2, arg3);
+
+  CPURegList fp_tmp_list = kCallerSavedFP;
+  fp_tmp_list.Remove(kPCSVarargsFP);
+  fp_tmp_list.Remove(arg0, arg1, arg2, arg3);
+
+  // Override the MacroAssembler's scratch register list. The lists will be
+  // reset automatically at the end of the UseScratchRegisterScope.
+  UseScratchRegisterScope temps(this);
+  TmpList()->set_list(tmp_list.list());
+  FPTmpList()->set_list(fp_tmp_list.list());
+
+  // Copies of the printf vararg registers that we can pop from.
+  CPURegList pcs_varargs = kPCSVarargs;
+  CPURegList pcs_varargs_fp = kPCSVarargsFP;
+
+  // Place the arguments. There are lots of clever tricks and optimizations we
+  // could use here, but Printf is a debug tool so instead we just try to keep
+  // it simple: Move each input that isn't already in the right place to a
+  // scratch register, then move everything back.
+  for (unsigned i = 0; i < kPrintfMaxArgCount; i++) {
+    // Work out the proper PCS register for this argument.
+    if (args[i].IsRegister()) {
+      pcs[i] = pcs_varargs.PopLowestIndex().X();
+      // We might only need a W register here. We need to know the size of the
+      // argument so we can properly encode it for the simulator call.
+      if (args[i].Is32Bits()) pcs[i] = pcs[i].W();
+    } else if (args[i].IsFPRegister()) {
+      // In C, floats are always cast to doubles for varargs calls.
+      pcs[i] = pcs_varargs_fp.PopLowestIndex().D();
+    } else {
+      DCHECK(args[i].IsNone());
+      arg_count = i;
+      break;
+    }
+
+    // If the argument is already in the right place, leave it where it is.
+    if (args[i].Aliases(pcs[i])) continue;
+
+    // Otherwise, if the argument is in a PCS argument register, allocate an
+    // appropriate scratch register and then move it out of the way.
+    if (kPCSVarargs.IncludesAliasOf(args[i]) ||
+        kPCSVarargsFP.IncludesAliasOf(args[i])) {
+      if (args[i].IsRegister()) {
+        Register old_arg = Register(args[i]);
+        Register new_arg = temps.AcquireSameSizeAs(old_arg);
+        Mov(new_arg, old_arg);
+        args[i] = new_arg;
+      } else {
+        FPRegister old_arg = FPRegister(args[i]);
+        FPRegister new_arg = temps.AcquireSameSizeAs(old_arg);
+        Fmov(new_arg, old_arg);
+        args[i] = new_arg;
+      }
+    }
+  }
+
+  // Do a second pass to move values into their final positions and perform any
+  // conversions that may be required.
+  for (int i = 0; i < arg_count; i++) {
+    DCHECK(pcs[i].type() == args[i].type());
+    if (pcs[i].IsRegister()) {
+      Mov(Register(pcs[i]), Register(args[i]), kDiscardForSameWReg);
+    } else {
+      DCHECK(pcs[i].IsFPRegister());
+      if (pcs[i].SizeInBytes() == args[i].SizeInBytes()) {
+        Fmov(FPRegister(pcs[i]), FPRegister(args[i]));
+      } else {
+        Fcvt(FPRegister(pcs[i]), FPRegister(args[i]));
+      }
+    }
+  }
+
+  // Load the format string into x0, as per the procedure-call standard.
+  //
+  // To make the code as portable as possible, the format string is encoded
+  // directly in the instruction stream. It might be cleaner to encode it in a
+  // literal pool, but since Printf is usually used for debugging, it is
+  // beneficial for it to be minimally dependent on other features.
+  Label format_address;
+  Adr(x0, &format_address);
+
+  // Emit the format string directly in the instruction stream.
+  { BlockPoolsScope scope(this);
+    Label after_data;
+    B(&after_data);
+    Bind(&format_address);
+    EmitStringData(format);
+    Unreachable();
+    Bind(&after_data);
+  }
+
+  // We don't pass any arguments on the stack, but we still need to align the C
+  // stack pointer to a 16-byte boundary for PCS compliance.
+  if (!csp.Is(StackPointer())) {
+    Bic(csp, StackPointer(), 0xf);
+  }
+
+  CallPrintf(arg_count, pcs);
+}
+
+
+void MacroAssembler::CallPrintf(int arg_count, const CPURegister * args) {
+  // A call to printf needs special handling for the simulator, since the system
+  // printf function will use a different instruction set and the procedure-call
+  // standard will not be compatible.
+#ifdef USE_SIMULATOR
+  { InstructionAccurateScope scope(this, kPrintfLength / kInstructionSize);
+    hlt(kImmExceptionIsPrintf);
+    dc32(arg_count);          // kPrintfArgCountOffset
+
+    // Determine the argument pattern.
+    uint32_t arg_pattern_list = 0;
+    for (int i = 0; i < arg_count; i++) {
+      uint32_t arg_pattern;
+      if (args[i].IsRegister()) {
+        arg_pattern = args[i].Is32Bits() ? kPrintfArgW : kPrintfArgX;
+      } else {
+        DCHECK(args[i].Is64Bits());
+        arg_pattern = kPrintfArgD;
+      }
+      DCHECK(arg_pattern < (1 << kPrintfArgPatternBits));
+      arg_pattern_list |= (arg_pattern << (kPrintfArgPatternBits * i));
+    }
+    dc32(arg_pattern_list);   // kPrintfArgPatternListOffset
+  }
+#else
+  Call(FUNCTION_ADDR(printf), RelocInfo::EXTERNAL_REFERENCE);
+#endif
+}
+
+
+void MacroAssembler::Printf(const char * format,
+                            CPURegister arg0,
+                            CPURegister arg1,
+                            CPURegister arg2,
+                            CPURegister arg3) {
+  // We can only print sp if it is the current stack pointer.
+  if (!csp.Is(StackPointer())) {
+    DCHECK(!csp.Aliases(arg0));
+    DCHECK(!csp.Aliases(arg1));
+    DCHECK(!csp.Aliases(arg2));
+    DCHECK(!csp.Aliases(arg3));
+  }
+
+  // Printf is expected to preserve all registers, so make sure that none are
+  // available as scratch registers until we've preserved them.
+  RegList old_tmp_list = TmpList()->list();
+  RegList old_fp_tmp_list = FPTmpList()->list();
+  TmpList()->set_list(0);
+  FPTmpList()->set_list(0);
+
+  // Preserve all caller-saved registers as well as NZCV.
+  // If csp is the stack pointer, PushCPURegList asserts that the size of each
+  // list is a multiple of 16 bytes.
+  PushCPURegList(kCallerSaved);
+  PushCPURegList(kCallerSavedFP);
+
+  // We can use caller-saved registers as scratch values (except for argN).
+  CPURegList tmp_list = kCallerSaved;
+  CPURegList fp_tmp_list = kCallerSavedFP;
+  tmp_list.Remove(arg0, arg1, arg2, arg3);
+  fp_tmp_list.Remove(arg0, arg1, arg2, arg3);
+  TmpList()->set_list(tmp_list.list());
+  FPTmpList()->set_list(fp_tmp_list.list());
+
+  { UseScratchRegisterScope temps(this);
+    // If any of the arguments are the current stack pointer, allocate a new
+    // register for them, and adjust the value to compensate for pushing the
+    // caller-saved registers.
+    bool arg0_sp = StackPointer().Aliases(arg0);
+    bool arg1_sp = StackPointer().Aliases(arg1);
+    bool arg2_sp = StackPointer().Aliases(arg2);
+    bool arg3_sp = StackPointer().Aliases(arg3);
+    if (arg0_sp || arg1_sp || arg2_sp || arg3_sp) {
+      // Allocate a register to hold the original stack pointer value, to pass
+      // to PrintfNoPreserve as an argument.
+      Register arg_sp = temps.AcquireX();
+      Add(arg_sp, StackPointer(),
+          kCallerSaved.TotalSizeInBytes() + kCallerSavedFP.TotalSizeInBytes());
+      if (arg0_sp) arg0 = Register::Create(arg_sp.code(), arg0.SizeInBits());
+      if (arg1_sp) arg1 = Register::Create(arg_sp.code(), arg1.SizeInBits());
+      if (arg2_sp) arg2 = Register::Create(arg_sp.code(), arg2.SizeInBits());
+      if (arg3_sp) arg3 = Register::Create(arg_sp.code(), arg3.SizeInBits());
+    }
+
+    // Preserve NZCV.
+    { UseScratchRegisterScope temps(this);
+      Register tmp = temps.AcquireX();
+      Mrs(tmp, NZCV);
+      Push(tmp, xzr);
+    }
+
+    PrintfNoPreserve(format, arg0, arg1, arg2, arg3);
+
+    // Restore NZCV.
+    { UseScratchRegisterScope temps(this);
+      Register tmp = temps.AcquireX();
+      Pop(xzr, tmp);
+      Msr(NZCV, tmp);
+    }
+  }
+
+  PopCPURegList(kCallerSavedFP);
+  PopCPURegList(kCallerSaved);
+
+  TmpList()->set_list(old_tmp_list);
+  FPTmpList()->set_list(old_fp_tmp_list);
+}
+
+
+void MacroAssembler::EmitFrameSetupForCodeAgePatching() {
+  // TODO(jbramley): Other architectures use the internal memcpy to copy the
+  // sequence. If this is a performance bottleneck, we should consider caching
+  // the sequence and copying it in the same way.
+  InstructionAccurateScope scope(this,
+                                 kNoCodeAgeSequenceLength / kInstructionSize);
+  DCHECK(jssp.Is(StackPointer()));
+  EmitFrameSetupForCodeAgePatching(this);
+}
+
+
+
+void MacroAssembler::EmitCodeAgeSequence(Code* stub) {
+  InstructionAccurateScope scope(this,
+                                 kNoCodeAgeSequenceLength / kInstructionSize);
+  DCHECK(jssp.Is(StackPointer()));
+  EmitCodeAgeSequence(this, stub);
+}
+
+
+#undef __
+#define __ assm->
+
+
+void MacroAssembler::EmitFrameSetupForCodeAgePatching(Assembler * assm) {
+  Label start;
+  __ bind(&start);
+
+  // We can do this sequence using four instructions, but the code ageing
+  // sequence that patches it needs five, so we use the extra space to try to
+  // simplify some addressing modes and remove some dependencies (compared to
+  // using two stp instructions with write-back).
+  __ sub(jssp, jssp, 4 * kXRegSize);
+  __ sub(csp, csp, 4 * kXRegSize);
+  __ stp(x1, cp, MemOperand(jssp, 0 * kXRegSize));
+  __ stp(fp, lr, MemOperand(jssp, 2 * kXRegSize));
+  __ add(fp, jssp, StandardFrameConstants::kFixedFrameSizeFromFp);
+
+  __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength);
+}
+
+
+void MacroAssembler::EmitCodeAgeSequence(Assembler * assm,
+                                         Code * stub) {
+  Label start;
+  __ bind(&start);
+  // When the stub is called, the sequence is replaced with the young sequence
+  // (as in EmitFrameSetupForCodeAgePatching). After the code is replaced, the
+  // stub jumps to &start, stored in x0. The young sequence does not call the
+  // stub so there is no infinite loop here.
+  //
+  // A branch (br) is used rather than a call (blr) because this code replaces
+  // the frame setup code that would normally preserve lr.
+  __ ldr_pcrel(ip0, kCodeAgeStubEntryOffset >> kLoadLiteralScaleLog2);
+  __ adr(x0, &start);
+  __ br(ip0);
+  // IsCodeAgeSequence in codegen-arm64.cc assumes that the code generated up
+  // until now (kCodeAgeStubEntryOffset) is the same for all code age sequences.
+  __ AssertSizeOfCodeGeneratedSince(&start, kCodeAgeStubEntryOffset);
+  if (stub) {
+    __ dc64(reinterpret_cast<uint64_t>(stub->instruction_start()));
+    __ AssertSizeOfCodeGeneratedSince(&start, kNoCodeAgeSequenceLength);
+  }
+}
+
+
+bool MacroAssembler::IsYoungSequence(Isolate* isolate, byte* sequence) {
+  bool is_young = isolate->code_aging_helper()->IsYoung(sequence);
+  DCHECK(is_young ||
+         isolate->code_aging_helper()->IsOld(sequence));
+  return is_young;
+}
+
+
+void MacroAssembler::TruncatingDiv(Register result,
+                                   Register dividend,
+                                   int32_t divisor) {
+  DCHECK(!AreAliased(result, dividend));
+  DCHECK(result.Is32Bits() && dividend.Is32Bits());
+  base::MagicNumbersForDivision<uint32_t> mag =
+      base::SignedDivisionByConstant(static_cast<uint32_t>(divisor));
+  Mov(result, mag.multiplier);
+  Smull(result.X(), dividend, result);
+  Asr(result.X(), result.X(), 32);
+  bool neg = (mag.multiplier & (static_cast<uint32_t>(1) << 31)) != 0;
+  if (divisor > 0 && neg) Add(result, result, dividend);
+  if (divisor < 0 && !neg && mag.multiplier > 0) Sub(result, result, dividend);
+  if (mag.shift > 0) Asr(result, result, mag.shift);
+  Add(result, result, Operand(dividend, LSR, 31));
+}
+
+
+#undef __
+
+
+UseScratchRegisterScope::~UseScratchRegisterScope() {
+  available_->set_list(old_available_);
+  availablefp_->set_list(old_availablefp_);
+}
+
+
+Register UseScratchRegisterScope::AcquireSameSizeAs(const Register& reg) {
+  int code = AcquireNextAvailable(available_).code();
+  return Register::Create(code, reg.SizeInBits());
+}
+
+
+FPRegister UseScratchRegisterScope::AcquireSameSizeAs(const FPRegister& reg) {
+  int code = AcquireNextAvailable(availablefp_).code();
+  return FPRegister::Create(code, reg.SizeInBits());
+}
+
+
+CPURegister UseScratchRegisterScope::AcquireNextAvailable(
+    CPURegList* available) {
+  CHECK(!available->IsEmpty());
+  CPURegister result = available->PopLowestIndex();
+  DCHECK(!AreAliased(result, xzr, csp));
+  return result;
+}
+
+
+CPURegister UseScratchRegisterScope::UnsafeAcquire(CPURegList* available,
+                                                   const CPURegister& reg) {
+  DCHECK(available->IncludesAliasOf(reg));
+  available->Remove(reg);
+  return reg;
+}
+
+
+#define __ masm->
+
+
+void InlineSmiCheckInfo::Emit(MacroAssembler* masm, const Register& reg,
+                              const Label* smi_check) {
+  Assembler::BlockPoolsScope scope(masm);
+  if (reg.IsValid()) {
+    DCHECK(smi_check->is_bound());
+    DCHECK(reg.Is64Bits());
+
+    // Encode the register (x0-x30) in the lowest 5 bits, then the offset to
+    // 'check' in the other bits. The possible offset is limited in that we
+    // use BitField to pack the data, and the underlying data type is a
+    // uint32_t.
+    uint32_t delta = __ InstructionsGeneratedSince(smi_check);
+    __ InlineData(RegisterBits::encode(reg.code()) | DeltaBits::encode(delta));
+  } else {
+    DCHECK(!smi_check->is_bound());
+
+    // An offset of 0 indicates that there is no patch site.
+    __ InlineData(0);
+  }
+}
+
+
+InlineSmiCheckInfo::InlineSmiCheckInfo(Address info)
+    : reg_(NoReg), smi_check_(NULL) {
+  InstructionSequence* inline_data = InstructionSequence::At(info);
+  DCHECK(inline_data->IsInlineData());
+  if (inline_data->IsInlineData()) {
+    uint64_t payload = inline_data->InlineData();
+    // We use BitField to decode the payload, and BitField can only handle
+    // 32-bit values.
+    DCHECK(is_uint32(payload));
+    if (payload != 0) {
+      int reg_code = RegisterBits::decode(payload);
+      reg_ = Register::XRegFromCode(reg_code);
+      uint64_t smi_check_delta = DeltaBits::decode(payload);
+      DCHECK(smi_check_delta != 0);
+      smi_check_ = inline_data->preceding(smi_check_delta);
+    }
+  }
+}
+
+
+#undef __
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/macro-assembler-arm64.h b/src/arm64/macro-assembler-arm64.h
new file mode 100644
index 0000000..7a106a1
--- /dev/null
+++ b/src/arm64/macro-assembler-arm64.h
@@ -0,0 +1,2338 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
+#define V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
+
+#include <vector>
+
+#include "src/bailout-reason.h"
+#include "src/globals.h"
+
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/base/bits.h"
+
+// Simulator specific helpers.
+#if USE_SIMULATOR
+  // TODO(all): If possible automatically prepend an indicator like
+  // UNIMPLEMENTED or LOCATION.
+  #define ASM_UNIMPLEMENTED(message)                                         \
+  __ Debug(message, __LINE__, NO_PARAM)
+  #define ASM_UNIMPLEMENTED_BREAK(message)                                   \
+  __ Debug(message, __LINE__,                                                \
+           FLAG_ignore_asm_unimplemented_break ? NO_PARAM : BREAK)
+  #define ASM_LOCATION(message)                                              \
+  __ Debug("LOCATION: " message, __LINE__, NO_PARAM)
+#else
+  #define ASM_UNIMPLEMENTED(message)
+  #define ASM_UNIMPLEMENTED_BREAK(message)
+  #define ASM_LOCATION(message)
+#endif
+
+
+namespace v8 {
+namespace internal {
+
+#define LS_MACRO_LIST(V)                                      \
+  V(Ldrb, Register&, rt, LDRB_w)                              \
+  V(Strb, Register&, rt, STRB_w)                              \
+  V(Ldrsb, Register&, rt, rt.Is64Bits() ? LDRSB_x : LDRSB_w)  \
+  V(Ldrh, Register&, rt, LDRH_w)                              \
+  V(Strh, Register&, rt, STRH_w)                              \
+  V(Ldrsh, Register&, rt, rt.Is64Bits() ? LDRSH_x : LDRSH_w)  \
+  V(Ldr, CPURegister&, rt, LoadOpFor(rt))                     \
+  V(Str, CPURegister&, rt, StoreOpFor(rt))                    \
+  V(Ldrsw, Register&, rt, LDRSW_x)
+
+#define LSPAIR_MACRO_LIST(V)                             \
+  V(Ldp, CPURegister&, rt, rt2, LoadPairOpFor(rt, rt2))  \
+  V(Stp, CPURegister&, rt, rt2, StorePairOpFor(rt, rt2)) \
+  V(Ldpsw, CPURegister&, rt, rt2, LDPSW_x)
+
+
+// ----------------------------------------------------------------------------
+// Static helper functions
+
+// Generate a MemOperand for loading a field from an object.
+inline MemOperand FieldMemOperand(Register object, int offset);
+inline MemOperand UntagSmiFieldMemOperand(Register object, int offset);
+
+// Generate a MemOperand for loading a SMI from memory.
+inline MemOperand UntagSmiMemOperand(Register object, int offset);
+
+
+// ----------------------------------------------------------------------------
+// MacroAssembler
+
+enum BranchType {
+  // Copies of architectural conditions.
+  // The associated conditions can be used in place of those, the code will
+  // take care of reinterpreting them with the correct type.
+  integer_eq = eq,
+  integer_ne = ne,
+  integer_hs = hs,
+  integer_lo = lo,
+  integer_mi = mi,
+  integer_pl = pl,
+  integer_vs = vs,
+  integer_vc = vc,
+  integer_hi = hi,
+  integer_ls = ls,
+  integer_ge = ge,
+  integer_lt = lt,
+  integer_gt = gt,
+  integer_le = le,
+  integer_al = al,
+  integer_nv = nv,
+
+  // These two are *different* from the architectural codes al and nv.
+  // 'always' is used to generate unconditional branches.
+  // 'never' is used to not generate a branch (generally as the inverse
+  // branch type of 'always).
+  always, never,
+  // cbz and cbnz
+  reg_zero, reg_not_zero,
+  // tbz and tbnz
+  reg_bit_clear, reg_bit_set,
+
+  // Aliases.
+  kBranchTypeFirstCondition = eq,
+  kBranchTypeLastCondition = nv,
+  kBranchTypeFirstUsingReg = reg_zero,
+  kBranchTypeFirstUsingBit = reg_bit_clear
+};
+
+inline BranchType InvertBranchType(BranchType type) {
+  if (kBranchTypeFirstCondition <= type && type <= kBranchTypeLastCondition) {
+    return static_cast<BranchType>(
+        NegateCondition(static_cast<Condition>(type)));
+  } else {
+    return static_cast<BranchType>(type ^ 1);
+  }
+}
+
+enum RememberedSetAction { EMIT_REMEMBERED_SET, OMIT_REMEMBERED_SET };
+enum SmiCheck { INLINE_SMI_CHECK, OMIT_SMI_CHECK };
+enum PointersToHereCheck {
+  kPointersToHereMaybeInteresting,
+  kPointersToHereAreAlwaysInteresting
+};
+enum LinkRegisterStatus { kLRHasNotBeenSaved, kLRHasBeenSaved };
+enum TargetAddressStorageMode {
+  CAN_INLINE_TARGET_ADDRESS,
+  NEVER_INLINE_TARGET_ADDRESS
+};
+enum UntagMode { kNotSpeculativeUntag, kSpeculativeUntag };
+enum ArrayHasHoles { kArrayCantHaveHoles, kArrayCanHaveHoles };
+enum CopyHint { kCopyUnknown, kCopyShort, kCopyLong };
+enum DiscardMoveMode { kDontDiscardForSameWReg, kDiscardForSameWReg };
+enum SeqStringSetCharCheckIndexType { kIndexIsSmi, kIndexIsInteger32 };
+
+class MacroAssembler : public Assembler {
+ public:
+  MacroAssembler(Isolate* isolate, byte * buffer, unsigned buffer_size);
+
+  inline Handle<Object> CodeObject();
+
+  // Instruction set functions ------------------------------------------------
+  // Logical macros.
+  inline void And(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Ands(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Bic(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Bics(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Orr(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Orn(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Eor(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Eon(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Tst(const Register& rn, const Operand& operand);
+  void LogicalMacro(const Register& rd,
+                    const Register& rn,
+                    const Operand& operand,
+                    LogicalOp op);
+
+  // Add and sub macros.
+  inline void Add(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Adds(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Sub(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Subs(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Cmn(const Register& rn, const Operand& operand);
+  inline void Cmp(const Register& rn, const Operand& operand);
+  inline void Neg(const Register& rd,
+                  const Operand& operand);
+  inline void Negs(const Register& rd,
+                   const Operand& operand);
+
+  void AddSubMacro(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand,
+                   FlagsUpdate S,
+                   AddSubOp op);
+
+  // Add/sub with carry macros.
+  inline void Adc(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Adcs(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Sbc(const Register& rd,
+                  const Register& rn,
+                  const Operand& operand);
+  inline void Sbcs(const Register& rd,
+                   const Register& rn,
+                   const Operand& operand);
+  inline void Ngc(const Register& rd,
+                  const Operand& operand);
+  inline void Ngcs(const Register& rd,
+                   const Operand& operand);
+  void AddSubWithCarryMacro(const Register& rd,
+                            const Register& rn,
+                            const Operand& operand,
+                            FlagsUpdate S,
+                            AddSubWithCarryOp op);
+
+  // Move macros.
+  void Mov(const Register& rd,
+           const Operand& operand,
+           DiscardMoveMode discard_mode = kDontDiscardForSameWReg);
+  void Mov(const Register& rd, uint64_t imm);
+  inline void Mvn(const Register& rd, uint64_t imm);
+  void Mvn(const Register& rd, const Operand& operand);
+  static bool IsImmMovn(uint64_t imm, unsigned reg_size);
+  static bool IsImmMovz(uint64_t imm, unsigned reg_size);
+  static unsigned CountClearHalfWords(uint64_t imm, unsigned reg_size);
+
+  // Try to move an immediate into the destination register in a single
+  // instruction. Returns true for success, and updates the contents of dst.
+  // Returns false, otherwise.
+  bool TryOneInstrMoveImmediate(const Register& dst, int64_t imm);
+
+  // Move an immediate into register dst, and return an Operand object for use
+  // with a subsequent instruction that accepts a shift. The value moved into
+  // dst is not necessarily equal to imm; it may have had a shifting operation
+  // applied to it that will be subsequently undone by the shift applied in the
+  // Operand.
+  Operand MoveImmediateForShiftedOp(const Register& dst, int64_t imm);
+
+  // Conditional macros.
+  inline void Ccmp(const Register& rn,
+                   const Operand& operand,
+                   StatusFlags nzcv,
+                   Condition cond);
+  inline void Ccmn(const Register& rn,
+                   const Operand& operand,
+                   StatusFlags nzcv,
+                   Condition cond);
+  void ConditionalCompareMacro(const Register& rn,
+                               const Operand& operand,
+                               StatusFlags nzcv,
+                               Condition cond,
+                               ConditionalCompareOp op);
+  void Csel(const Register& rd,
+            const Register& rn,
+            const Operand& operand,
+            Condition cond);
+
+  // Load/store macros.
+#define DECLARE_FUNCTION(FN, REGTYPE, REG, OP) \
+  inline void FN(const REGTYPE REG, const MemOperand& addr);
+  LS_MACRO_LIST(DECLARE_FUNCTION)
+#undef DECLARE_FUNCTION
+
+  void LoadStoreMacro(const CPURegister& rt,
+                      const MemOperand& addr,
+                      LoadStoreOp op);
+
+#define DECLARE_FUNCTION(FN, REGTYPE, REG, REG2, OP) \
+  inline void FN(const REGTYPE REG, const REGTYPE REG2, const MemOperand& addr);
+  LSPAIR_MACRO_LIST(DECLARE_FUNCTION)
+#undef DECLARE_FUNCTION
+
+  void LoadStorePairMacro(const CPURegister& rt, const CPURegister& rt2,
+                          const MemOperand& addr, LoadStorePairOp op);
+
+  // V8-specific load/store helpers.
+  void Load(const Register& rt, const MemOperand& addr, Representation r);
+  void Store(const Register& rt, const MemOperand& addr, Representation r);
+
+  enum AdrHint {
+    // The target must be within the immediate range of adr.
+    kAdrNear,
+    // The target may be outside of the immediate range of adr. Additional
+    // instructions may be emitted.
+    kAdrFar
+  };
+  void Adr(const Register& rd, Label* label, AdrHint = kAdrNear);
+
+  // Remaining instructions are simple pass-through calls to the assembler.
+  inline void Asr(const Register& rd, const Register& rn, unsigned shift);
+  inline void Asr(const Register& rd, const Register& rn, const Register& rm);
+
+  // Branch type inversion relies on these relations.
+  STATIC_ASSERT((reg_zero      == (reg_not_zero ^ 1)) &&
+                (reg_bit_clear == (reg_bit_set ^ 1)) &&
+                (always        == (never ^ 1)));
+
+  void B(Label* label, BranchType type, Register reg = NoReg, int bit = -1);
+
+  inline void B(Label* label);
+  inline void B(Condition cond, Label* label);
+  void B(Label* label, Condition cond);
+  inline void Bfi(const Register& rd,
+                  const Register& rn,
+                  unsigned lsb,
+                  unsigned width);
+  inline void Bfxil(const Register& rd,
+                    const Register& rn,
+                    unsigned lsb,
+                    unsigned width);
+  inline void Bind(Label* label);
+  inline void Bl(Label* label);
+  inline void Blr(const Register& xn);
+  inline void Br(const Register& xn);
+  inline void Brk(int code);
+  void Cbnz(const Register& rt, Label* label);
+  void Cbz(const Register& rt, Label* label);
+  inline void Cinc(const Register& rd, const Register& rn, Condition cond);
+  inline void Cinv(const Register& rd, const Register& rn, Condition cond);
+  inline void Cls(const Register& rd, const Register& rn);
+  inline void Clz(const Register& rd, const Register& rn);
+  inline void Cneg(const Register& rd, const Register& rn, Condition cond);
+  inline void CzeroX(const Register& rd, Condition cond);
+  inline void CmovX(const Register& rd, const Register& rn, Condition cond);
+  inline void Cset(const Register& rd, Condition cond);
+  inline void Csetm(const Register& rd, Condition cond);
+  inline void Csinc(const Register& rd,
+                    const Register& rn,
+                    const Register& rm,
+                    Condition cond);
+  inline void Csinv(const Register& rd,
+                    const Register& rn,
+                    const Register& rm,
+                    Condition cond);
+  inline void Csneg(const Register& rd,
+                    const Register& rn,
+                    const Register& rm,
+                    Condition cond);
+  inline void Dmb(BarrierDomain domain, BarrierType type);
+  inline void Dsb(BarrierDomain domain, BarrierType type);
+  inline void Debug(const char* message, uint32_t code, Instr params = BREAK);
+  inline void Extr(const Register& rd,
+                   const Register& rn,
+                   const Register& rm,
+                   unsigned lsb);
+  inline void Fabs(const FPRegister& fd, const FPRegister& fn);
+  inline void Fadd(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Fccmp(const FPRegister& fn,
+                    const FPRegister& fm,
+                    StatusFlags nzcv,
+                    Condition cond);
+  inline void Fcmp(const FPRegister& fn, const FPRegister& fm);
+  inline void Fcmp(const FPRegister& fn, double value);
+  inline void Fcsel(const FPRegister& fd,
+                    const FPRegister& fn,
+                    const FPRegister& fm,
+                    Condition cond);
+  inline void Fcvt(const FPRegister& fd, const FPRegister& fn);
+  inline void Fcvtas(const Register& rd, const FPRegister& fn);
+  inline void Fcvtau(const Register& rd, const FPRegister& fn);
+  inline void Fcvtms(const Register& rd, const FPRegister& fn);
+  inline void Fcvtmu(const Register& rd, const FPRegister& fn);
+  inline void Fcvtns(const Register& rd, const FPRegister& fn);
+  inline void Fcvtnu(const Register& rd, const FPRegister& fn);
+  inline void Fcvtzs(const Register& rd, const FPRegister& fn);
+  inline void Fcvtzu(const Register& rd, const FPRegister& fn);
+  inline void Fdiv(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Fmadd(const FPRegister& fd,
+                    const FPRegister& fn,
+                    const FPRegister& fm,
+                    const FPRegister& fa);
+  inline void Fmax(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Fmaxnm(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm);
+  inline void Fmin(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Fminnm(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm);
+  inline void Fmov(FPRegister fd, FPRegister fn);
+  inline void Fmov(FPRegister fd, Register rn);
+  // Provide explicit double and float interfaces for FP immediate moves, rather
+  // than relying on implicit C++ casts. This allows signalling NaNs to be
+  // preserved when the immediate matches the format of fd. Most systems convert
+  // signalling NaNs to quiet NaNs when converting between float and double.
+  inline void Fmov(FPRegister fd, double imm);
+  inline void Fmov(FPRegister fd, float imm);
+  // Provide a template to allow other types to be converted automatically.
+  template<typename T>
+  void Fmov(FPRegister fd, T imm) {
+    DCHECK(allow_macro_instructions_);
+    Fmov(fd, static_cast<double>(imm));
+  }
+  inline void Fmov(Register rd, FPRegister fn);
+  inline void Fmsub(const FPRegister& fd,
+                    const FPRegister& fn,
+                    const FPRegister& fm,
+                    const FPRegister& fa);
+  inline void Fmul(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Fneg(const FPRegister& fd, const FPRegister& fn);
+  inline void Fnmadd(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm,
+                     const FPRegister& fa);
+  inline void Fnmsub(const FPRegister& fd,
+                     const FPRegister& fn,
+                     const FPRegister& fm,
+                     const FPRegister& fa);
+  inline void Frinta(const FPRegister& fd, const FPRegister& fn);
+  inline void Frintm(const FPRegister& fd, const FPRegister& fn);
+  inline void Frintn(const FPRegister& fd, const FPRegister& fn);
+  inline void Frintz(const FPRegister& fd, const FPRegister& fn);
+  inline void Fsqrt(const FPRegister& fd, const FPRegister& fn);
+  inline void Fsub(const FPRegister& fd,
+                   const FPRegister& fn,
+                   const FPRegister& fm);
+  inline void Hint(SystemHint code);
+  inline void Hlt(int code);
+  inline void Isb();
+  inline void Ldnp(const CPURegister& rt,
+                   const CPURegister& rt2,
+                   const MemOperand& src);
+  // Load a literal from the inline constant pool.
+  inline void Ldr(const CPURegister& rt, const Immediate& imm);
+  // Helper function for double immediate.
+  inline void Ldr(const CPURegister& rt, double imm);
+  inline void Lsl(const Register& rd, const Register& rn, unsigned shift);
+  inline void Lsl(const Register& rd, const Register& rn, const Register& rm);
+  inline void Lsr(const Register& rd, const Register& rn, unsigned shift);
+  inline void Lsr(const Register& rd, const Register& rn, const Register& rm);
+  inline void Madd(const Register& rd,
+                   const Register& rn,
+                   const Register& rm,
+                   const Register& ra);
+  inline void Mneg(const Register& rd, const Register& rn, const Register& rm);
+  inline void Mov(const Register& rd, const Register& rm);
+  inline void Movk(const Register& rd, uint64_t imm, int shift = -1);
+  inline void Mrs(const Register& rt, SystemRegister sysreg);
+  inline void Msr(SystemRegister sysreg, const Register& rt);
+  inline void Msub(const Register& rd,
+                   const Register& rn,
+                   const Register& rm,
+                   const Register& ra);
+  inline void Mul(const Register& rd, const Register& rn, const Register& rm);
+  inline void Nop() { nop(); }
+  inline void Rbit(const Register& rd, const Register& rn);
+  inline void Ret(const Register& xn = lr);
+  inline void Rev(const Register& rd, const Register& rn);
+  inline void Rev16(const Register& rd, const Register& rn);
+  inline void Rev32(const Register& rd, const Register& rn);
+  inline void Ror(const Register& rd, const Register& rs, unsigned shift);
+  inline void Ror(const Register& rd, const Register& rn, const Register& rm);
+  inline void Sbfiz(const Register& rd,
+                    const Register& rn,
+                    unsigned lsb,
+                    unsigned width);
+  inline void Sbfx(const Register& rd,
+                   const Register& rn,
+                   unsigned lsb,
+                   unsigned width);
+  inline void Scvtf(const FPRegister& fd,
+                    const Register& rn,
+                    unsigned fbits = 0);
+  inline void Sdiv(const Register& rd, const Register& rn, const Register& rm);
+  inline void Smaddl(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra);
+  inline void Smsubl(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra);
+  inline void Smull(const Register& rd,
+                    const Register& rn,
+                    const Register& rm);
+  inline void Smulh(const Register& rd,
+                    const Register& rn,
+                    const Register& rm);
+  inline void Stnp(const CPURegister& rt,
+                   const CPURegister& rt2,
+                   const MemOperand& dst);
+  inline void Sxtb(const Register& rd, const Register& rn);
+  inline void Sxth(const Register& rd, const Register& rn);
+  inline void Sxtw(const Register& rd, const Register& rn);
+  void Tbnz(const Register& rt, unsigned bit_pos, Label* label);
+  void Tbz(const Register& rt, unsigned bit_pos, Label* label);
+  inline void Ubfiz(const Register& rd,
+                    const Register& rn,
+                    unsigned lsb,
+                    unsigned width);
+  inline void Ubfx(const Register& rd,
+                   const Register& rn,
+                   unsigned lsb,
+                   unsigned width);
+  inline void Ucvtf(const FPRegister& fd,
+                    const Register& rn,
+                    unsigned fbits = 0);
+  inline void Udiv(const Register& rd, const Register& rn, const Register& rm);
+  inline void Umaddl(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra);
+  inline void Umsubl(const Register& rd,
+                     const Register& rn,
+                     const Register& rm,
+                     const Register& ra);
+  inline void Uxtb(const Register& rd, const Register& rn);
+  inline void Uxth(const Register& rd, const Register& rn);
+  inline void Uxtw(const Register& rd, const Register& rn);
+
+  // Pseudo-instructions ------------------------------------------------------
+
+  // Compute rd = abs(rm).
+  // This function clobbers the condition flags. On output the overflow flag is
+  // set iff the negation overflowed.
+  //
+  // If rm is the minimum representable value, the result is not representable.
+  // Handlers for each case can be specified using the relevant labels.
+  void Abs(const Register& rd, const Register& rm,
+           Label * is_not_representable = NULL,
+           Label * is_representable = NULL);
+
+  // Push or pop up to 4 registers of the same width to or from the stack,
+  // using the current stack pointer as set by SetStackPointer.
+  //
+  // If an argument register is 'NoReg', all further arguments are also assumed
+  // to be 'NoReg', and are thus not pushed or popped.
+  //
+  // Arguments are ordered such that "Push(a, b);" is functionally equivalent
+  // to "Push(a); Push(b);".
+  //
+  // It is valid to push the same register more than once, and there is no
+  // restriction on the order in which registers are specified.
+  //
+  // It is not valid to pop into the same register more than once in one
+  // operation, not even into the zero register.
+  //
+  // If the current stack pointer (as set by SetStackPointer) is csp, then it
+  // must be aligned to 16 bytes on entry and the total size of the specified
+  // registers must also be a multiple of 16 bytes.
+  //
+  // Even if the current stack pointer is not the system stack pointer (csp),
+  // Push (and derived methods) will still modify the system stack pointer in
+  // order to comply with ABI rules about accessing memory below the system
+  // stack pointer.
+  //
+  // Other than the registers passed into Pop, the stack pointer and (possibly)
+  // the system stack pointer, these methods do not modify any other registers.
+  void Push(const CPURegister& src0, const CPURegister& src1 = NoReg,
+            const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg);
+  void Push(const CPURegister& src0, const CPURegister& src1,
+            const CPURegister& src2, const CPURegister& src3,
+            const CPURegister& src4, const CPURegister& src5 = NoReg,
+            const CPURegister& src6 = NoReg, const CPURegister& src7 = NoReg);
+  void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg,
+           const CPURegister& dst2 = NoReg, const CPURegister& dst3 = NoReg);
+  void Push(const Register& src0, const FPRegister& src1);
+
+  // Alternative forms of Push and Pop, taking a RegList or CPURegList that
+  // specifies the registers that are to be pushed or popped. Higher-numbered
+  // registers are associated with higher memory addresses (as in the A32 push
+  // and pop instructions).
+  //
+  // (Push|Pop)SizeRegList allow you to specify the register size as a
+  // parameter. Only kXRegSizeInBits, kWRegSizeInBits, kDRegSizeInBits and
+  // kSRegSizeInBits are supported.
+  //
+  // Otherwise, (Push|Pop)(CPU|X|W|D|S)RegList is preferred.
+  void PushCPURegList(CPURegList registers);
+  void PopCPURegList(CPURegList registers);
+
+  inline void PushSizeRegList(RegList registers, unsigned reg_size,
+      CPURegister::RegisterType type = CPURegister::kRegister) {
+    PushCPURegList(CPURegList(type, reg_size, registers));
+  }
+  inline void PopSizeRegList(RegList registers, unsigned reg_size,
+      CPURegister::RegisterType type = CPURegister::kRegister) {
+    PopCPURegList(CPURegList(type, reg_size, registers));
+  }
+  inline void PushXRegList(RegList regs) {
+    PushSizeRegList(regs, kXRegSizeInBits);
+  }
+  inline void PopXRegList(RegList regs) {
+    PopSizeRegList(regs, kXRegSizeInBits);
+  }
+  inline void PushWRegList(RegList regs) {
+    PushSizeRegList(regs, kWRegSizeInBits);
+  }
+  inline void PopWRegList(RegList regs) {
+    PopSizeRegList(regs, kWRegSizeInBits);
+  }
+  inline void PushDRegList(RegList regs) {
+    PushSizeRegList(regs, kDRegSizeInBits, CPURegister::kFPRegister);
+  }
+  inline void PopDRegList(RegList regs) {
+    PopSizeRegList(regs, kDRegSizeInBits, CPURegister::kFPRegister);
+  }
+  inline void PushSRegList(RegList regs) {
+    PushSizeRegList(regs, kSRegSizeInBits, CPURegister::kFPRegister);
+  }
+  inline void PopSRegList(RegList regs) {
+    PopSizeRegList(regs, kSRegSizeInBits, CPURegister::kFPRegister);
+  }
+
+  // Push the specified register 'count' times.
+  void PushMultipleTimes(CPURegister src, Register count);
+  void PushMultipleTimes(CPURegister src, int count);
+
+  // This is a convenience method for pushing a single Handle<Object>.
+  inline void Push(Handle<Object> handle);
+  void Push(Smi* smi) { Push(Handle<Smi>(smi, isolate())); }
+
+  // Aliases of Push and Pop, required for V8 compatibility.
+  inline void push(Register src) {
+    Push(src);
+  }
+  inline void pop(Register dst) {
+    Pop(dst);
+  }
+
+  // Sometimes callers need to push or pop multiple registers in a way that is
+  // difficult to structure efficiently for fixed Push or Pop calls. This scope
+  // allows push requests to be queued up, then flushed at once. The
+  // MacroAssembler will try to generate the most efficient sequence required.
+  //
+  // Unlike the other Push and Pop macros, PushPopQueue can handle mixed sets of
+  // register sizes and types.
+  class PushPopQueue {
+   public:
+    explicit PushPopQueue(MacroAssembler* masm) : masm_(masm), size_(0) { }
+
+    ~PushPopQueue() {
+      DCHECK(queued_.empty());
+    }
+
+    void Queue(const CPURegister& rt) {
+      size_ += rt.SizeInBytes();
+      queued_.push_back(rt);
+    }
+
+    enum PreambleDirective {
+      WITH_PREAMBLE,
+      SKIP_PREAMBLE
+    };
+    void PushQueued(PreambleDirective preamble_directive = WITH_PREAMBLE);
+    void PopQueued();
+
+   private:
+    MacroAssembler* masm_;
+    int size_;
+    std::vector<CPURegister> queued_;
+  };
+
+  // Poke 'src' onto the stack. The offset is in bytes.
+  //
+  // If the current stack pointer (according to StackPointer()) is csp, then
+  // csp must be aligned to 16 bytes.
+  void Poke(const CPURegister& src, const Operand& offset);
+
+  // Peek at a value on the stack, and put it in 'dst'. The offset is in bytes.
+  //
+  // If the current stack pointer (according to StackPointer()) is csp, then
+  // csp must be aligned to 16 bytes.
+  void Peek(const CPURegister& dst, const Operand& offset);
+
+  // Poke 'src1' and 'src2' onto the stack. The values written will be adjacent
+  // with 'src2' at a higher address than 'src1'. The offset is in bytes.
+  //
+  // If the current stack pointer (according to StackPointer()) is csp, then
+  // csp must be aligned to 16 bytes.
+  void PokePair(const CPURegister& src1, const CPURegister& src2, int offset);
+
+  // Peek at two values on the stack, and put them in 'dst1' and 'dst2'. The
+  // values peeked will be adjacent, with the value in 'dst2' being from a
+  // higher address than 'dst1'. The offset is in bytes.
+  //
+  // If the current stack pointer (according to StackPointer()) is csp, then
+  // csp must be aligned to 16 bytes.
+  void PeekPair(const CPURegister& dst1, const CPURegister& dst2, int offset);
+
+  // Claim or drop stack space without actually accessing memory.
+  //
+  // In debug mode, both of these will write invalid data into the claimed or
+  // dropped space.
+  //
+  // If the current stack pointer (according to StackPointer()) is csp, then it
+  // must be aligned to 16 bytes and the size claimed or dropped must be a
+  // multiple of 16 bytes.
+  //
+  // Note that unit_size must be specified in bytes. For variants which take a
+  // Register count, the unit size must be a power of two.
+  inline void Claim(uint64_t count, uint64_t unit_size = kXRegSize);
+  inline void Claim(const Register& count,
+                    uint64_t unit_size = kXRegSize);
+  inline void Drop(uint64_t count, uint64_t unit_size = kXRegSize);
+  inline void Drop(const Register& count,
+                   uint64_t unit_size = kXRegSize);
+
+  // Variants of Claim and Drop, where the 'count' parameter is a SMI held in a
+  // register.
+  inline void ClaimBySMI(const Register& count_smi,
+                         uint64_t unit_size = kXRegSize);
+  inline void DropBySMI(const Register& count_smi,
+                        uint64_t unit_size = kXRegSize);
+
+  // Compare a register with an operand, and branch to label depending on the
+  // condition. May corrupt the status flags.
+  inline void CompareAndBranch(const Register& lhs,
+                               const Operand& rhs,
+                               Condition cond,
+                               Label* label);
+
+  // Test the bits of register defined by bit_pattern, and branch if ANY of
+  // those bits are set. May corrupt the status flags.
+  inline void TestAndBranchIfAnySet(const Register& reg,
+                                    const uint64_t bit_pattern,
+                                    Label* label);
+
+  // Test the bits of register defined by bit_pattern, and branch if ALL of
+  // those bits are clear (ie. not set.) May corrupt the status flags.
+  inline void TestAndBranchIfAllClear(const Register& reg,
+                                      const uint64_t bit_pattern,
+                                      Label* label);
+
+  // Insert one or more instructions into the instruction stream that encode
+  // some caller-defined data. The instructions used will be executable with no
+  // side effects.
+  inline void InlineData(uint64_t data);
+
+  // Insert an instrumentation enable marker into the instruction stream.
+  inline void EnableInstrumentation();
+
+  // Insert an instrumentation disable marker into the instruction stream.
+  inline void DisableInstrumentation();
+
+  // Insert an instrumentation event marker into the instruction stream. These
+  // will be picked up by the instrumentation system to annotate an instruction
+  // profile. The argument marker_name must be a printable two character string;
+  // it will be encoded in the event marker.
+  inline void AnnotateInstrumentation(const char* marker_name);
+
+  // If emit_debug_code() is true, emit a run-time check to ensure that
+  // StackPointer() does not point below the system stack pointer.
+  //
+  // Whilst it is architecturally legal for StackPointer() to point below csp,
+  // it can be evidence of a potential bug because the ABI forbids accesses
+  // below csp.
+  //
+  // If StackPointer() is the system stack pointer (csp) or ALWAYS_ALIGN_CSP is
+  // enabled, then csp will be dereferenced to  cause the processor
+  // (or simulator) to abort if it is not properly aligned.
+  //
+  // If emit_debug_code() is false, this emits no code.
+  void AssertStackConsistency();
+
+  // Preserve the callee-saved registers (as defined by AAPCS64).
+  //
+  // Higher-numbered registers are pushed before lower-numbered registers, and
+  // thus get higher addresses.
+  // Floating-point registers are pushed before general-purpose registers, and
+  // thus get higher addresses.
+  //
+  // Note that registers are not checked for invalid values. Use this method
+  // only if you know that the GC won't try to examine the values on the stack.
+  //
+  // This method must not be called unless the current stack pointer (as set by
+  // SetStackPointer) is the system stack pointer (csp), and is aligned to
+  // ActivationFrameAlignment().
+  void PushCalleeSavedRegisters();
+
+  // Restore the callee-saved registers (as defined by AAPCS64).
+  //
+  // Higher-numbered registers are popped after lower-numbered registers, and
+  // thus come from higher addresses.
+  // Floating-point registers are popped after general-purpose registers, and
+  // thus come from higher addresses.
+  //
+  // This method must not be called unless the current stack pointer (as set by
+  // SetStackPointer) is the system stack pointer (csp), and is aligned to
+  // ActivationFrameAlignment().
+  void PopCalleeSavedRegisters();
+
+  // Set the current stack pointer, but don't generate any code.
+  inline void SetStackPointer(const Register& stack_pointer) {
+    DCHECK(!TmpList()->IncludesAliasOf(stack_pointer));
+    sp_ = stack_pointer;
+  }
+
+  // Return the current stack pointer, as set by SetStackPointer.
+  inline const Register& StackPointer() const {
+    return sp_;
+  }
+
+  // Align csp for a frame, as per ActivationFrameAlignment, and make it the
+  // current stack pointer.
+  inline void AlignAndSetCSPForFrame() {
+    int sp_alignment = ActivationFrameAlignment();
+    // AAPCS64 mandates at least 16-byte alignment.
+    DCHECK(sp_alignment >= 16);
+    DCHECK(base::bits::IsPowerOfTwo32(sp_alignment));
+    Bic(csp, StackPointer(), sp_alignment - 1);
+    SetStackPointer(csp);
+  }
+
+  // Push the system stack pointer (csp) down to allow the same to be done to
+  // the current stack pointer (according to StackPointer()). This must be
+  // called _before_ accessing the memory.
+  //
+  // This is necessary when pushing or otherwise adding things to the stack, to
+  // satisfy the AAPCS64 constraint that the memory below the system stack
+  // pointer is not accessed.  The amount pushed will be increased as necessary
+  // to ensure csp remains aligned to 16 bytes.
+  //
+  // This method asserts that StackPointer() is not csp, since the call does
+  // not make sense in that context.
+  inline void BumpSystemStackPointer(const Operand& space);
+
+  // Re-synchronizes the system stack pointer (csp) with the current stack
+  // pointer (according to StackPointer()).  This function will ensure the
+  // new value of the system stack pointer is remains aligned to 16 bytes, and
+  // is lower than or equal to the value of the current stack pointer.
+  //
+  // This method asserts that StackPointer() is not csp, since the call does
+  // not make sense in that context.
+  inline void SyncSystemStackPointer();
+
+  // Helpers ------------------------------------------------------------------
+  // Root register.
+  inline void InitializeRootRegister();
+
+  void AssertFPCRState(Register fpcr = NoReg);
+  void ConfigureFPCR();
+  void CanonicalizeNaN(const FPRegister& dst, const FPRegister& src);
+  void CanonicalizeNaN(const FPRegister& reg) {
+    CanonicalizeNaN(reg, reg);
+  }
+
+  // Load an object from the root table.
+  void LoadRoot(CPURegister destination,
+                Heap::RootListIndex index);
+  // Store an object to the root table.
+  void StoreRoot(Register source,
+                 Heap::RootListIndex index);
+
+  // Load both TrueValue and FalseValue roots.
+  void LoadTrueFalseRoots(Register true_root, Register false_root);
+
+  void LoadHeapObject(Register dst, Handle<HeapObject> object);
+
+  void LoadObject(Register result, Handle<Object> object) {
+    AllowDeferredHandleDereference heap_object_check;
+    if (object->IsHeapObject()) {
+      LoadHeapObject(result, Handle<HeapObject>::cast(object));
+    } else {
+      DCHECK(object->IsSmi());
+      Mov(result, Operand(object));
+    }
+  }
+
+  static int SafepointRegisterStackIndex(int reg_code);
+
+  // This is required for compatibility with architecture independant code.
+  // Remove if not needed.
+  inline void Move(Register dst, Register src) { Mov(dst, src); }
+
+  void LoadInstanceDescriptors(Register map,
+                               Register descriptors);
+  void EnumLengthUntagged(Register dst, Register map);
+  void EnumLengthSmi(Register dst, Register map);
+  void NumberOfOwnDescriptors(Register dst, Register map);
+
+  template<typename Field>
+  void DecodeField(Register dst, Register src) {
+    static const uint64_t shift = Field::kShift;
+    static const uint64_t setbits = CountSetBits(Field::kMask, 32);
+    Ubfx(dst, src, shift, setbits);
+  }
+
+  template<typename Field>
+  void DecodeField(Register reg) {
+    DecodeField<Field>(reg, reg);
+  }
+
+  // ---- SMI and Number Utilities ----
+
+  inline void SmiTag(Register dst, Register src);
+  inline void SmiTag(Register smi);
+  inline void SmiUntag(Register dst, Register src);
+  inline void SmiUntag(Register smi);
+  inline void SmiUntagToDouble(FPRegister dst,
+                               Register src,
+                               UntagMode mode = kNotSpeculativeUntag);
+  inline void SmiUntagToFloat(FPRegister dst,
+                              Register src,
+                              UntagMode mode = kNotSpeculativeUntag);
+
+  // Tag and push in one step.
+  inline void SmiTagAndPush(Register src);
+  inline void SmiTagAndPush(Register src1, Register src2);
+
+  inline void JumpIfSmi(Register value,
+                        Label* smi_label,
+                        Label* not_smi_label = NULL);
+  inline void JumpIfNotSmi(Register value, Label* not_smi_label);
+  inline void JumpIfBothSmi(Register value1,
+                            Register value2,
+                            Label* both_smi_label,
+                            Label* not_smi_label = NULL);
+  inline void JumpIfEitherSmi(Register value1,
+                              Register value2,
+                              Label* either_smi_label,
+                              Label* not_smi_label = NULL);
+  inline void JumpIfEitherNotSmi(Register value1,
+                                 Register value2,
+                                 Label* not_smi_label);
+  inline void JumpIfBothNotSmi(Register value1,
+                               Register value2,
+                               Label* not_smi_label);
+
+  // Abort execution if argument is a smi, enabled via --debug-code.
+  void AssertNotSmi(Register object, BailoutReason reason = kOperandIsASmi);
+  void AssertSmi(Register object, BailoutReason reason = kOperandIsNotASmi);
+
+  inline void ObjectTag(Register tagged_obj, Register obj);
+  inline void ObjectUntag(Register untagged_obj, Register obj);
+
+  // Abort execution if argument is not a name, enabled via --debug-code.
+  void AssertName(Register object);
+
+  // Abort execution if argument is not undefined or an AllocationSite, enabled
+  // via --debug-code.
+  void AssertUndefinedOrAllocationSite(Register object, Register scratch);
+
+  // Abort execution if argument is not a string, enabled via --debug-code.
+  void AssertString(Register object);
+
+  void JumpIfHeapNumber(Register object, Label* on_heap_number,
+                        SmiCheckType smi_check_type = DONT_DO_SMI_CHECK);
+  void JumpIfNotHeapNumber(Register object, Label* on_not_heap_number,
+                           SmiCheckType smi_check_type = DONT_DO_SMI_CHECK);
+
+  // Sets the vs flag if the input is -0.0.
+  void TestForMinusZero(DoubleRegister input);
+
+  // Jump to label if the input double register contains -0.0.
+  void JumpIfMinusZero(DoubleRegister input, Label* on_negative_zero);
+
+  // Jump to label if the input integer register contains the double precision
+  // floating point representation of -0.0.
+  void JumpIfMinusZero(Register input, Label* on_negative_zero);
+
+  // Generate code to do a lookup in the number string cache. If the number in
+  // the register object is found in the cache the generated code falls through
+  // with the result in the result register. The object and the result register
+  // can be the same. If the number is not found in the cache the code jumps to
+  // the label not_found with only the content of register object unchanged.
+  void LookupNumberStringCache(Register object,
+                               Register result,
+                               Register scratch1,
+                               Register scratch2,
+                               Register scratch3,
+                               Label* not_found);
+
+  // Saturate a signed 32-bit integer in input to an unsigned 8-bit integer in
+  // output.
+  void ClampInt32ToUint8(Register in_out);
+  void ClampInt32ToUint8(Register output, Register input);
+
+  // Saturate a double in input to an unsigned 8-bit integer in output.
+  void ClampDoubleToUint8(Register output,
+                          DoubleRegister input,
+                          DoubleRegister dbl_scratch);
+
+  // Try to represent a double as a signed 32-bit int.
+  // This succeeds if the result compares equal to the input, so inputs of -0.0
+  // are represented as 0 and handled as a success.
+  //
+  // On output the Z flag is set if the operation was successful.
+  void TryRepresentDoubleAsInt32(Register as_int,
+                                 FPRegister value,
+                                 FPRegister scratch_d,
+                                 Label* on_successful_conversion = NULL,
+                                 Label* on_failed_conversion = NULL) {
+    DCHECK(as_int.Is32Bits());
+    TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion,
+                            on_failed_conversion);
+  }
+
+  // Try to represent a double as a signed 64-bit int.
+  // This succeeds if the result compares equal to the input, so inputs of -0.0
+  // are represented as 0 and handled as a success.
+  //
+  // On output the Z flag is set if the operation was successful.
+  void TryRepresentDoubleAsInt64(Register as_int,
+                                 FPRegister value,
+                                 FPRegister scratch_d,
+                                 Label* on_successful_conversion = NULL,
+                                 Label* on_failed_conversion = NULL) {
+    DCHECK(as_int.Is64Bits());
+    TryRepresentDoubleAsInt(as_int, value, scratch_d, on_successful_conversion,
+                            on_failed_conversion);
+  }
+
+  // ---- Object Utilities ----
+
+  // Copy fields from 'src' to 'dst', where both are tagged objects.
+  // The 'temps' list is a list of X registers which can be used for scratch
+  // values. The temps list must include at least one register.
+  //
+  // Currently, CopyFields cannot make use of more than three registers from
+  // the 'temps' list.
+  //
+  // CopyFields expects to be able to take at least two registers from
+  // MacroAssembler::TmpList().
+  void CopyFields(Register dst, Register src, CPURegList temps, unsigned count);
+
+  // Starting at address in dst, initialize field_count 64-bit fields with
+  // 64-bit value in register filler. Register dst is corrupted.
+  void FillFields(Register dst,
+                  Register field_count,
+                  Register filler);
+
+  // Copies a number of bytes from src to dst. All passed registers are
+  // clobbered. On exit src and dst will point to the place just after where the
+  // last byte was read or written and length will be zero. Hint may be used to
+  // determine which is the most efficient algorithm to use for copying.
+  void CopyBytes(Register dst,
+                 Register src,
+                 Register length,
+                 Register scratch,
+                 CopyHint hint = kCopyUnknown);
+
+  // ---- String Utilities ----
+
+
+  // Jump to label if either object is not a sequential one-byte string.
+  // Optionally perform a smi check on the objects first.
+  void JumpIfEitherIsNotSequentialOneByteStrings(
+      Register first, Register second, Register scratch1, Register scratch2,
+      Label* failure, SmiCheckType smi_check = DO_SMI_CHECK);
+
+  // Check if instance type is sequential one-byte string and jump to label if
+  // it is not.
+  void JumpIfInstanceTypeIsNotSequentialOneByte(Register type, Register scratch,
+                                                Label* failure);
+
+  // Checks if both instance types are sequential one-byte strings and jumps to
+  // label if either is not.
+  void JumpIfEitherInstanceTypeIsNotSequentialOneByte(
+      Register first_object_instance_type, Register second_object_instance_type,
+      Register scratch1, Register scratch2, Label* failure);
+
+  // Checks if both instance types are sequential one-byte strings and jumps to
+  // label if either is not.
+  void JumpIfBothInstanceTypesAreNotSequentialOneByte(
+      Register first_object_instance_type, Register second_object_instance_type,
+      Register scratch1, Register scratch2, Label* failure);
+
+  void JumpIfNotUniqueNameInstanceType(Register type, Label* not_unique_name);
+
+  // ---- Calling / Jumping helpers ----
+
+  // This is required for compatibility in architecture indepenedant code.
+  inline void jmp(Label* L) { B(L); }
+
+  // Passes thrown value to the handler of top of the try handler chain.
+  // Register value must be x0.
+  void Throw(Register value,
+             Register scratch1,
+             Register scratch2,
+             Register scratch3,
+             Register scratch4);
+
+  // Propagates an uncatchable exception to the top of the current JS stack's
+  // handler chain. Register value must be x0.
+  void ThrowUncatchable(Register value,
+                        Register scratch1,
+                        Register scratch2,
+                        Register scratch3,
+                        Register scratch4);
+
+  void CallStub(CodeStub* stub, TypeFeedbackId ast_id = TypeFeedbackId::None());
+  void TailCallStub(CodeStub* stub);
+
+  void CallRuntime(const Runtime::Function* f,
+                   int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
+
+  void CallRuntime(Runtime::FunctionId id,
+                   int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
+    CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
+  }
+
+  void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
+    const Runtime::Function* function = Runtime::FunctionForId(id);
+    CallRuntime(function, function->nargs, kSaveFPRegs);
+  }
+
+  void TailCallRuntime(Runtime::FunctionId fid,
+                       int num_arguments,
+                       int result_size);
+
+  int ActivationFrameAlignment();
+
+  // Calls a C function.
+  // The called function is not allowed to trigger a
+  // garbage collection, since that might move the code and invalidate the
+  // return address (unless this is somehow accounted for by the called
+  // function).
+  void CallCFunction(ExternalReference function,
+                     int num_reg_arguments);
+  void CallCFunction(ExternalReference function,
+                     int num_reg_arguments,
+                     int num_double_arguments);
+  void CallCFunction(Register function,
+                     int num_reg_arguments,
+                     int num_double_arguments);
+
+  // Calls an API function. Allocates HandleScope, extracts returned value
+  // from handle and propagates exceptions.
+  // 'stack_space' is the space to be unwound on exit (includes the call JS
+  // arguments space and the additional space allocated for the fast call).
+  // 'spill_offset' is the offset from the stack pointer where
+  // CallApiFunctionAndReturn can spill registers.
+  void CallApiFunctionAndReturn(Register function_address,
+                                ExternalReference thunk_ref,
+                                int stack_space,
+                                int spill_offset,
+                                MemOperand return_value_operand,
+                                MemOperand* context_restore_operand);
+
+  // The number of register that CallApiFunctionAndReturn will need to save on
+  // the stack. The space for these registers need to be allocated in the
+  // ExitFrame before calling CallApiFunctionAndReturn.
+  static const int kCallApiFunctionSpillSpace = 4;
+
+  // Jump to a runtime routine.
+  void JumpToExternalReference(const ExternalReference& builtin);
+  // Tail call of a runtime routine (jump).
+  // Like JumpToExternalReference, but also takes care of passing the number
+  // of parameters.
+  void TailCallExternalReference(const ExternalReference& ext,
+                                 int num_arguments,
+                                 int result_size);
+  void CallExternalReference(const ExternalReference& ext,
+                             int num_arguments);
+
+
+  // Invoke specified builtin JavaScript function. Adds an entry to
+  // the unresolved list if the name does not resolve.
+  void InvokeBuiltin(Builtins::JavaScript id,
+                     InvokeFlag flag,
+                     const CallWrapper& call_wrapper = NullCallWrapper());
+
+  // Store the code object for the given builtin in the target register and
+  // setup the function in the function register.
+  void GetBuiltinEntry(Register target,
+                       Register function,
+                       Builtins::JavaScript id);
+
+  // Store the function for the given builtin in the target register.
+  void GetBuiltinFunction(Register target, Builtins::JavaScript id);
+
+  void Jump(Register target);
+  void Jump(Address target, RelocInfo::Mode rmode);
+  void Jump(Handle<Code> code, RelocInfo::Mode rmode);
+  void Jump(intptr_t target, RelocInfo::Mode rmode);
+
+  void Call(Register target);
+  void Call(Label* target);
+  void Call(Address target, RelocInfo::Mode rmode);
+  void Call(Handle<Code> code,
+            RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
+            TypeFeedbackId ast_id = TypeFeedbackId::None());
+
+  // For every Call variant, there is a matching CallSize function that returns
+  // the size (in bytes) of the call sequence.
+  static int CallSize(Register target);
+  static int CallSize(Label* target);
+  static int CallSize(Address target, RelocInfo::Mode rmode);
+  static int CallSize(Handle<Code> code,
+                      RelocInfo::Mode rmode = RelocInfo::CODE_TARGET,
+                      TypeFeedbackId ast_id = TypeFeedbackId::None());
+
+  // Registers used through the invocation chain are hard-coded.
+  // We force passing the parameters to ensure the contracts are correctly
+  // honoured by the caller.
+  // 'function' must be x1.
+  // 'actual' must use an immediate or x0.
+  // 'expected' must use an immediate or x2.
+  // 'call_kind' must be x5.
+  void InvokePrologue(const ParameterCount& expected,
+                      const ParameterCount& actual,
+                      Handle<Code> code_constant,
+                      Register code_reg,
+                      Label* done,
+                      InvokeFlag flag,
+                      bool* definitely_mismatches,
+                      const CallWrapper& call_wrapper);
+  void InvokeCode(Register code,
+                  const ParameterCount& expected,
+                  const ParameterCount& actual,
+                  InvokeFlag flag,
+                  const CallWrapper& call_wrapper);
+  // Invoke the JavaScript function in the given register.
+  // Changes the current context to the context in the function before invoking.
+  void InvokeFunction(Register function,
+                      const ParameterCount& actual,
+                      InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+  void InvokeFunction(Register function,
+                      const ParameterCount& expected,
+                      const ParameterCount& actual,
+                      InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+  void InvokeFunction(Handle<JSFunction> function,
+                      const ParameterCount& expected,
+                      const ParameterCount& actual,
+                      InvokeFlag flag,
+                      const CallWrapper& call_wrapper);
+
+
+  // ---- Floating point helpers ----
+
+  // Perform a conversion from a double to a signed int64. If the input fits in
+  // range of the 64-bit result, execution branches to done. Otherwise,
+  // execution falls through, and the sign of the result can be used to
+  // determine if overflow was towards positive or negative infinity.
+  //
+  // On successful conversion, the least significant 32 bits of the result are
+  // equivalent to the ECMA-262 operation "ToInt32".
+  //
+  // Only public for the test code in test-code-stubs-arm64.cc.
+  void TryConvertDoubleToInt64(Register result,
+                               DoubleRegister input,
+                               Label* done);
+
+  // Performs a truncating conversion of a floating point number as used by
+  // the JS bitwise operations. See ECMA-262 9.5: ToInt32.
+  // Exits with 'result' holding the answer.
+  void TruncateDoubleToI(Register result, DoubleRegister double_input);
+
+  // Performs a truncating conversion of a heap number as used by
+  // the JS bitwise operations. See ECMA-262 9.5: ToInt32. 'result' and 'input'
+  // must be different registers.  Exits with 'result' holding the answer.
+  void TruncateHeapNumberToI(Register result, Register object);
+
+  // Converts the smi or heap number in object to an int32 using the rules
+  // for ToInt32 as described in ECMAScript 9.5.: the value is truncated
+  // and brought into the range -2^31 .. +2^31 - 1. 'result' and 'input' must be
+  // different registers.
+  void TruncateNumberToI(Register object,
+                         Register result,
+                         Register heap_number_map,
+                         Label* not_int32);
+
+  // ---- Code generation helpers ----
+
+  void set_generating_stub(bool value) { generating_stub_ = value; }
+  bool generating_stub() const { return generating_stub_; }
+#if DEBUG
+  void set_allow_macro_instructions(bool value) {
+    allow_macro_instructions_ = value;
+  }
+  bool allow_macro_instructions() const { return allow_macro_instructions_; }
+#endif
+  bool use_real_aborts() const { return use_real_aborts_; }
+  void set_has_frame(bool value) { has_frame_ = value; }
+  bool has_frame() const { return has_frame_; }
+  bool AllowThisStubCall(CodeStub* stub);
+
+  class NoUseRealAbortsScope {
+   public:
+    explicit NoUseRealAbortsScope(MacroAssembler* masm) :
+        saved_(masm->use_real_aborts_), masm_(masm) {
+      masm_->use_real_aborts_ = false;
+    }
+    ~NoUseRealAbortsScope() {
+      masm_->use_real_aborts_ = saved_;
+    }
+   private:
+    bool saved_;
+    MacroAssembler* masm_;
+  };
+
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void DebugBreak();
+
+  // ---------------------------------------------------------------------------
+  // Exception handling
+
+  // Push a new try handler and link into try handler chain.
+  void PushTryHandler(StackHandler::Kind kind, int handler_index);
+
+  // Unlink the stack handler on top of the stack from the try handler chain.
+  // Must preserve the result register.
+  void PopTryHandler();
+
+
+  // ---------------------------------------------------------------------------
+  // Allocation support
+
+  // Allocate an object in new space or old pointer space. The object_size is
+  // specified either in bytes or in words if the allocation flag SIZE_IN_WORDS
+  // is passed. The allocated object is returned in result.
+  //
+  // If the new space is exhausted control continues at the gc_required label.
+  // In this case, the result and scratch registers may still be clobbered.
+  // If flags includes TAG_OBJECT, the result is tagged as as a heap object.
+  void Allocate(Register object_size,
+                Register result,
+                Register scratch1,
+                Register scratch2,
+                Label* gc_required,
+                AllocationFlags flags);
+
+  void Allocate(int object_size,
+                Register result,
+                Register scratch1,
+                Register scratch2,
+                Label* gc_required,
+                AllocationFlags flags);
+
+  // Undo allocation in new space. The object passed and objects allocated after
+  // it will no longer be allocated. The caller must make sure that no pointers
+  // are left to the object(s) no longer allocated as they would be invalid when
+  // allocation is undone.
+  void UndoAllocationInNewSpace(Register object, Register scratch);
+
+  void AllocateTwoByteString(Register result,
+                             Register length,
+                             Register scratch1,
+                             Register scratch2,
+                             Register scratch3,
+                             Label* gc_required);
+  void AllocateOneByteString(Register result, Register length,
+                             Register scratch1, Register scratch2,
+                             Register scratch3, Label* gc_required);
+  void AllocateTwoByteConsString(Register result,
+                                 Register length,
+                                 Register scratch1,
+                                 Register scratch2,
+                                 Label* gc_required);
+  void AllocateOneByteConsString(Register result, Register length,
+                                 Register scratch1, Register scratch2,
+                                 Label* gc_required);
+  void AllocateTwoByteSlicedString(Register result,
+                                   Register length,
+                                   Register scratch1,
+                                   Register scratch2,
+                                   Label* gc_required);
+  void AllocateOneByteSlicedString(Register result, Register length,
+                                   Register scratch1, Register scratch2,
+                                   Label* gc_required);
+
+  // Allocates a heap number or jumps to the gc_required label if the young
+  // space is full and a scavenge is needed.
+  // All registers are clobbered.
+  // If no heap_number_map register is provided, the function will take care of
+  // loading it.
+  void AllocateHeapNumber(Register result,
+                          Label* gc_required,
+                          Register scratch1,
+                          Register scratch2,
+                          CPURegister value = NoFPReg,
+                          CPURegister heap_number_map = NoReg,
+                          MutableMode mode = IMMUTABLE);
+
+  // ---------------------------------------------------------------------------
+  // Support functions.
+
+  // Try to get function prototype of a function and puts the value in the
+  // result register. Checks that the function really is a function and jumps
+  // to the miss label if the fast checks fail. The function register will be
+  // untouched; the other registers may be clobbered.
+  enum BoundFunctionAction {
+    kMissOnBoundFunction,
+    kDontMissOnBoundFunction
+  };
+
+  void TryGetFunctionPrototype(Register function,
+                               Register result,
+                               Register scratch,
+                               Label* miss,
+                               BoundFunctionAction action =
+                                 kDontMissOnBoundFunction);
+
+  // Compare object type for heap object.  heap_object contains a non-Smi
+  // whose object type should be compared with the given type.  This both
+  // sets the flags and leaves the object type in the type_reg register.
+  // It leaves the map in the map register (unless the type_reg and map register
+  // are the same register).  It leaves the heap object in the heap_object
+  // register unless the heap_object register is the same register as one of the
+  // other registers.
+  void CompareObjectType(Register heap_object,
+                         Register map,
+                         Register type_reg,
+                         InstanceType type);
+
+
+  // Compare object type for heap object, and branch if equal (or not.)
+  // heap_object contains a non-Smi whose object type should be compared with
+  // the given type.  This both sets the flags and leaves the object type in
+  // the type_reg register. It leaves the map in the map register (unless the
+  // type_reg and map register are the same register).  It leaves the heap
+  // object in the heap_object register unless the heap_object register is the
+  // same register as one of the other registers.
+  void JumpIfObjectType(Register object,
+                        Register map,
+                        Register type_reg,
+                        InstanceType type,
+                        Label* if_cond_pass,
+                        Condition cond = eq);
+
+  void JumpIfNotObjectType(Register object,
+                           Register map,
+                           Register type_reg,
+                           InstanceType type,
+                           Label* if_not_object);
+
+  // Compare instance type in a map.  map contains a valid map object whose
+  // object type should be compared with the given type.  This both
+  // sets the flags and leaves the object type in the type_reg register.
+  void CompareInstanceType(Register map,
+                           Register type_reg,
+                           InstanceType type);
+
+  // Compare an object's map with the specified map. Condition flags are set
+  // with result of map compare.
+  void CompareObjectMap(Register obj, Heap::RootListIndex index);
+
+  // Compare an object's map with the specified map. Condition flags are set
+  // with result of map compare.
+  void CompareObjectMap(Register obj, Register scratch, Handle<Map> map);
+
+  // As above, but the map of the object is already loaded into the register
+  // which is preserved by the code generated.
+  void CompareMap(Register obj_map,
+                  Handle<Map> map);
+
+  // Check if the map of an object is equal to a specified map and branch to
+  // label if not. Skip the smi check if not required (object is known to be a
+  // heap object). If mode is ALLOW_ELEMENT_TRANSITION_MAPS, then also match
+  // against maps that are ElementsKind transition maps of the specified map.
+  void CheckMap(Register obj,
+                Register scratch,
+                Handle<Map> map,
+                Label* fail,
+                SmiCheckType smi_check_type);
+
+
+  void CheckMap(Register obj,
+                Register scratch,
+                Heap::RootListIndex index,
+                Label* fail,
+                SmiCheckType smi_check_type);
+
+  // As above, but the map of the object is already loaded into obj_map, and is
+  // preserved.
+  void CheckMap(Register obj_map,
+                Handle<Map> map,
+                Label* fail,
+                SmiCheckType smi_check_type);
+
+  // Check if the map of an object is equal to a specified map and branch to a
+  // specified target if equal. Skip the smi check if not required (object is
+  // known to be a heap object)
+  void DispatchMap(Register obj,
+                   Register scratch,
+                   Handle<Map> map,
+                   Handle<Code> success,
+                   SmiCheckType smi_check_type);
+
+  // Test the bitfield of the heap object map with mask and set the condition
+  // flags. The object register is preserved.
+  void TestMapBitfield(Register object, uint64_t mask);
+
+  // Load the elements kind field from a map, and return it in the result
+  // register.
+  void LoadElementsKindFromMap(Register result, Register map);
+
+  // Compare the object in a register to a value from the root list.
+  void CompareRoot(const Register& obj, Heap::RootListIndex index);
+
+  // Compare the object in a register to a value and jump if they are equal.
+  void JumpIfRoot(const Register& obj,
+                  Heap::RootListIndex index,
+                  Label* if_equal);
+
+  // Compare the object in a register to a value and jump if they are not equal.
+  void JumpIfNotRoot(const Register& obj,
+                     Heap::RootListIndex index,
+                     Label* if_not_equal);
+
+  // Load and check the instance type of an object for being a unique name.
+  // Loads the type into the second argument register.
+  // The object and type arguments can be the same register; in that case it
+  // will be overwritten with the type.
+  // Fall-through if the object was a string and jump on fail otherwise.
+  inline void IsObjectNameType(Register object, Register type, Label* fail);
+
+  inline void IsObjectJSObjectType(Register heap_object,
+                                   Register map,
+                                   Register scratch,
+                                   Label* fail);
+
+  // Check the instance type in the given map to see if it corresponds to a
+  // JS object type. Jump to the fail label if this is not the case and fall
+  // through otherwise. However if fail label is NULL, no branch will be
+  // performed and the flag will be updated. You can test the flag for "le"
+  // condition to test if it is a valid JS object type.
+  inline void IsInstanceJSObjectType(Register map,
+                                     Register scratch,
+                                     Label* fail);
+
+  // Load and check the instance type of an object for being a string.
+  // Loads the type into the second argument register.
+  // The object and type arguments can be the same register; in that case it
+  // will be overwritten with the type.
+  // Jumps to not_string or string appropriate. If the appropriate label is
+  // NULL, fall through.
+  inline void IsObjectJSStringType(Register object, Register type,
+                                   Label* not_string, Label* string = NULL);
+
+  // Compare the contents of a register with an operand, and branch to true,
+  // false or fall through, depending on condition.
+  void CompareAndSplit(const Register& lhs,
+                       const Operand& rhs,
+                       Condition cond,
+                       Label* if_true,
+                       Label* if_false,
+                       Label* fall_through);
+
+  // Test the bits of register defined by bit_pattern, and branch to
+  // if_any_set, if_all_clear or fall_through accordingly.
+  void TestAndSplit(const Register& reg,
+                    uint64_t bit_pattern,
+                    Label* if_all_clear,
+                    Label* if_any_set,
+                    Label* fall_through);
+
+  // Check if a map for a JSObject indicates that the object has fast elements.
+  // Jump to the specified label if it does not.
+  void CheckFastElements(Register map, Register scratch, Label* fail);
+
+  // Check if a map for a JSObject indicates that the object can have both smi
+  // and HeapObject elements.  Jump to the specified label if it does not.
+  void CheckFastObjectElements(Register map, Register scratch, Label* fail);
+
+  // Check to see if number can be stored as a double in FastDoubleElements.
+  // If it can, store it at the index specified by key_reg in the array,
+  // otherwise jump to fail.
+  void StoreNumberToDoubleElements(Register value_reg,
+                                   Register key_reg,
+                                   Register elements_reg,
+                                   Register scratch1,
+                                   FPRegister fpscratch1,
+                                   Label* fail,
+                                   int elements_offset = 0);
+
+  // Picks out an array index from the hash field.
+  // Register use:
+  //   hash - holds the index's hash. Clobbered.
+  //   index - holds the overwritten index on exit.
+  void IndexFromHash(Register hash, Register index);
+
+  // ---------------------------------------------------------------------------
+  // Inline caching support.
+
+  void EmitSeqStringSetCharCheck(Register string,
+                                 Register index,
+                                 SeqStringSetCharCheckIndexType index_type,
+                                 Register scratch,
+                                 uint32_t encoding_mask);
+
+  // Generate code for checking access rights - used for security checks
+  // on access to global objects across environments. The holder register
+  // is left untouched, whereas both scratch registers are clobbered.
+  void CheckAccessGlobalProxy(Register holder_reg,
+                              Register scratch1,
+                              Register scratch2,
+                              Label* miss);
+
+  // Hash the interger value in 'key' register.
+  // It uses the same algorithm as ComputeIntegerHash in utils.h.
+  void GetNumberHash(Register key, Register scratch);
+
+  // Load value from the dictionary.
+  //
+  // elements - holds the slow-case elements of the receiver on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // key      - holds the smi key on entry.
+  //            Unchanged unless 'result' is the same register.
+  //
+  // result   - holds the result on exit if the load succeeded.
+  //            Allowed to be the same as 'key' or 'result'.
+  //            Unchanged on bailout so 'key' or 'result' can be used
+  //            in further computation.
+  void LoadFromNumberDictionary(Label* miss,
+                                Register elements,
+                                Register key,
+                                Register result,
+                                Register scratch0,
+                                Register scratch1,
+                                Register scratch2,
+                                Register scratch3);
+
+  // ---------------------------------------------------------------------------
+  // Frames.
+
+  // Activation support.
+  void EnterFrame(StackFrame::Type type);
+  void LeaveFrame(StackFrame::Type type);
+
+  // Returns map with validated enum cache in object register.
+  void CheckEnumCache(Register object,
+                      Register null_value,
+                      Register scratch0,
+                      Register scratch1,
+                      Register scratch2,
+                      Register scratch3,
+                      Label* call_runtime);
+
+  // AllocationMemento support. Arrays may have an associated
+  // AllocationMemento object that can be checked for in order to pretransition
+  // to another type.
+  // On entry, receiver should point to the array object.
+  // If allocation info is present, the Z flag is set (so that the eq
+  // condition will pass).
+  void TestJSArrayForAllocationMemento(Register receiver,
+                                       Register scratch1,
+                                       Register scratch2,
+                                       Label* no_memento_found);
+
+  void JumpIfJSArrayHasAllocationMemento(Register receiver,
+                                         Register scratch1,
+                                         Register scratch2,
+                                         Label* memento_found) {
+    Label no_memento_found;
+    TestJSArrayForAllocationMemento(receiver, scratch1, scratch2,
+                                    &no_memento_found);
+    B(eq, memento_found);
+    Bind(&no_memento_found);
+  }
+
+  // The stack pointer has to switch between csp and jssp when setting up and
+  // destroying the exit frame. Hence preserving/restoring the registers is
+  // slightly more complicated than simple push/pop operations.
+  void ExitFramePreserveFPRegs();
+  void ExitFrameRestoreFPRegs();
+
+  // Generates function and stub prologue code.
+  void StubPrologue();
+  void Prologue(bool code_pre_aging);
+
+  // Enter exit frame. Exit frames are used when calling C code from generated
+  // (JavaScript) code.
+  //
+  // The stack pointer must be jssp on entry, and will be set to csp by this
+  // function. The frame pointer is also configured, but the only other
+  // registers modified by this function are the provided scratch register, and
+  // jssp.
+  //
+  // The 'extra_space' argument can be used to allocate some space in the exit
+  // frame that will be ignored by the GC. This space will be reserved in the
+  // bottom of the frame immediately above the return address slot.
+  //
+  // Set up a stack frame and registers as follows:
+  //         fp[8]: CallerPC (lr)
+  //   fp -> fp[0]: CallerFP (old fp)
+  //         fp[-8]: SPOffset (new csp)
+  //         fp[-16]: CodeObject()
+  //         fp[-16 - fp-size]: Saved doubles, if saved_doubles is true.
+  //         csp[8]: Memory reserved for the caller if extra_space != 0.
+  //                 Alignment padding, if necessary.
+  //  csp -> csp[0]: Space reserved for the return address.
+  //
+  // This function also stores the new frame information in the top frame, so
+  // that the new frame becomes the current frame.
+  void EnterExitFrame(bool save_doubles,
+                      const Register& scratch,
+                      int extra_space = 0);
+
+  // Leave the current exit frame, after a C function has returned to generated
+  // (JavaScript) code.
+  //
+  // This effectively unwinds the operation of EnterExitFrame:
+  //  * Preserved doubles are restored (if restore_doubles is true).
+  //  * The frame information is removed from the top frame.
+  //  * The exit frame is dropped.
+  //  * The stack pointer is reset to jssp.
+  //
+  // The stack pointer must be csp on entry.
+  void LeaveExitFrame(bool save_doubles,
+                      const Register& scratch,
+                      bool restore_context);
+
+  void LoadContext(Register dst, int context_chain_length);
+
+  // Emit code for a truncating division by a constant. The dividend register is
+  // unchanged. Dividend and result must be different.
+  void TruncatingDiv(Register result, Register dividend, int32_t divisor);
+
+  // ---------------------------------------------------------------------------
+  // StatsCounter support
+
+  void SetCounter(StatsCounter* counter, int value, Register scratch1,
+                  Register scratch2);
+  void IncrementCounter(StatsCounter* counter, int value, Register scratch1,
+                        Register scratch2);
+  void DecrementCounter(StatsCounter* counter, int value, Register scratch1,
+                        Register scratch2);
+
+  // ---------------------------------------------------------------------------
+  // Garbage collector support (GC).
+
+  enum RememberedSetFinalAction {
+    kReturnAtEnd,
+    kFallThroughAtEnd
+  };
+
+  // Record in the remembered set the fact that we have a pointer to new space
+  // at the address pointed to by the addr register. Only works if addr is not
+  // in new space.
+  void RememberedSetHelper(Register object,  // Used for debug code.
+                           Register addr,
+                           Register scratch1,
+                           SaveFPRegsMode save_fp,
+                           RememberedSetFinalAction and_then);
+
+  // Push and pop the registers that can hold pointers, as defined by the
+  // RegList constant kSafepointSavedRegisters.
+  void PushSafepointRegisters();
+  void PopSafepointRegisters();
+
+  void PushSafepointRegistersAndDoubles();
+  void PopSafepointRegistersAndDoubles();
+
+  // Store value in register src in the safepoint stack slot for register dst.
+  void StoreToSafepointRegisterSlot(Register src, Register dst) {
+    Poke(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
+  }
+
+  // Load the value of the src register from its safepoint stack slot
+  // into register dst.
+  void LoadFromSafepointRegisterSlot(Register dst, Register src) {
+    Peek(src, SafepointRegisterStackIndex(dst.code()) * kPointerSize);
+  }
+
+  void CheckPageFlagSet(const Register& object,
+                        const Register& scratch,
+                        int mask,
+                        Label* if_any_set);
+
+  void CheckPageFlagClear(const Register& object,
+                          const Register& scratch,
+                          int mask,
+                          Label* if_all_clear);
+
+  void CheckMapDeprecated(Handle<Map> map,
+                          Register scratch,
+                          Label* if_deprecated);
+
+  // Check if object is in new space and jump accordingly.
+  // Register 'object' is preserved.
+  void JumpIfNotInNewSpace(Register object,
+                           Label* branch) {
+    InNewSpace(object, ne, branch);
+  }
+
+  void JumpIfInNewSpace(Register object,
+                        Label* branch) {
+    InNewSpace(object, eq, branch);
+  }
+
+  // Notify the garbage collector that we wrote a pointer into an object.
+  // |object| is the object being stored into, |value| is the object being
+  // stored.  value and scratch registers are clobbered by the operation.
+  // The offset is the offset from the start of the object, not the offset from
+  // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
+  void RecordWriteField(
+      Register object,
+      int offset,
+      Register value,
+      Register scratch,
+      LinkRegisterStatus lr_status,
+      SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting);
+
+  // As above, but the offset has the tag presubtracted. For use with
+  // MemOperand(reg, off).
+  inline void RecordWriteContextSlot(
+      Register context,
+      int offset,
+      Register value,
+      Register scratch,
+      LinkRegisterStatus lr_status,
+      SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting) {
+    RecordWriteField(context,
+                     offset + kHeapObjectTag,
+                     value,
+                     scratch,
+                     lr_status,
+                     save_fp,
+                     remembered_set_action,
+                     smi_check,
+                     pointers_to_here_check_for_value);
+  }
+
+  void RecordWriteForMap(
+      Register object,
+      Register map,
+      Register dst,
+      LinkRegisterStatus lr_status,
+      SaveFPRegsMode save_fp);
+
+  // For a given |object| notify the garbage collector that the slot |address|
+  // has been written.  |value| is the object being stored. The value and
+  // address registers are clobbered by the operation.
+  void RecordWrite(
+      Register object,
+      Register address,
+      Register value,
+      LinkRegisterStatus lr_status,
+      SaveFPRegsMode save_fp,
+      RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
+      SmiCheck smi_check = INLINE_SMI_CHECK,
+      PointersToHereCheck pointers_to_here_check_for_value =
+          kPointersToHereMaybeInteresting);
+
+  // Checks the color of an object. If the object is already grey or black
+  // then we just fall through, since it is already live. If it is white and
+  // we can determine that it doesn't need to be scanned, then we just mark it
+  // black and fall through. For the rest we jump to the label so the
+  // incremental marker can fix its assumptions.
+  void EnsureNotWhite(Register object,
+                      Register scratch1,
+                      Register scratch2,
+                      Register scratch3,
+                      Register scratch4,
+                      Label* object_is_white_and_not_data);
+
+  // Detects conservatively whether an object is data-only, i.e. it does need to
+  // be scanned by the garbage collector.
+  void JumpIfDataObject(Register value,
+                        Register scratch,
+                        Label* not_data_object);
+
+  // Helper for finding the mark bits for an address.
+  // Note that the behaviour slightly differs from other architectures.
+  // On exit:
+  //  - addr_reg is unchanged.
+  //  - The bitmap register points at the word with the mark bits.
+  //  - The shift register contains the index of the first color bit for this
+  //    object in the bitmap.
+  inline void GetMarkBits(Register addr_reg,
+                          Register bitmap_reg,
+                          Register shift_reg);
+
+  // Check if an object has a given incremental marking color.
+  void HasColor(Register object,
+                Register scratch0,
+                Register scratch1,
+                Label* has_color,
+                int first_bit,
+                int second_bit);
+
+  void JumpIfBlack(Register object,
+                   Register scratch0,
+                   Register scratch1,
+                   Label* on_black);
+
+
+  // Get the location of a relocated constant (its address in the constant pool)
+  // from its load site.
+  void GetRelocatedValueLocation(Register ldr_location,
+                                 Register result);
+
+
+  // ---------------------------------------------------------------------------
+  // Debugging.
+
+  // Calls Abort(msg) if the condition cond is not satisfied.
+  // Use --debug_code to enable.
+  void Assert(Condition cond, BailoutReason reason);
+  void AssertRegisterIsClear(Register reg, BailoutReason reason);
+  void AssertRegisterIsRoot(
+      Register reg,
+      Heap::RootListIndex index,
+      BailoutReason reason = kRegisterDidNotMatchExpectedRoot);
+  void AssertFastElements(Register elements);
+
+  // Abort if the specified register contains the invalid color bit pattern.
+  // The pattern must be in bits [1:0] of 'reg' register.
+  //
+  // If emit_debug_code() is false, this emits no code.
+  void AssertHasValidColor(const Register& reg);
+
+  // Abort if 'object' register doesn't point to a string object.
+  //
+  // If emit_debug_code() is false, this emits no code.
+  void AssertIsString(const Register& object);
+
+  // Like Assert(), but always enabled.
+  void Check(Condition cond, BailoutReason reason);
+  void CheckRegisterIsClear(Register reg, BailoutReason reason);
+
+  // Print a message to stderr and abort execution.
+  void Abort(BailoutReason reason);
+
+  // Conditionally load the cached Array transitioned map of type
+  // transitioned_kind from the native context if the map in register
+  // map_in_out is the cached Array map in the native context of
+  // expected_kind.
+  void LoadTransitionedArrayMapConditional(
+      ElementsKind expected_kind,
+      ElementsKind transitioned_kind,
+      Register map_in_out,
+      Register scratch1,
+      Register scratch2,
+      Label* no_map_match);
+
+  void LoadGlobalFunction(int index, Register function);
+
+  // Load the initial map from the global function. The registers function and
+  // map can be the same, function is then overwritten.
+  void LoadGlobalFunctionInitialMap(Register function,
+                                    Register map,
+                                    Register scratch);
+
+  CPURegList* TmpList() { return &tmp_list_; }
+  CPURegList* FPTmpList() { return &fptmp_list_; }
+
+  static CPURegList DefaultTmpList();
+  static CPURegList DefaultFPTmpList();
+
+  // Like printf, but print at run-time from generated code.
+  //
+  // The caller must ensure that arguments for floating-point placeholders
+  // (such as %e, %f or %g) are FPRegisters, and that arguments for integer
+  // placeholders are Registers.
+  //
+  // At the moment it is only possible to print the value of csp if it is the
+  // current stack pointer. Otherwise, the MacroAssembler will automatically
+  // update csp on every push (using BumpSystemStackPointer), so determining its
+  // value is difficult.
+  //
+  // Format placeholders that refer to more than one argument, or to a specific
+  // argument, are not supported. This includes formats like "%1$d" or "%.*d".
+  //
+  // This function automatically preserves caller-saved registers so that
+  // calling code can use Printf at any point without having to worry about
+  // corruption. The preservation mechanism generates a lot of code. If this is
+  // a problem, preserve the important registers manually and then call
+  // PrintfNoPreserve. Callee-saved registers are not used by Printf, and are
+  // implicitly preserved.
+  void Printf(const char * format,
+              CPURegister arg0 = NoCPUReg,
+              CPURegister arg1 = NoCPUReg,
+              CPURegister arg2 = NoCPUReg,
+              CPURegister arg3 = NoCPUReg);
+
+  // Like Printf, but don't preserve any caller-saved registers, not even 'lr'.
+  //
+  // The return code from the system printf call will be returned in x0.
+  void PrintfNoPreserve(const char * format,
+                        const CPURegister& arg0 = NoCPUReg,
+                        const CPURegister& arg1 = NoCPUReg,
+                        const CPURegister& arg2 = NoCPUReg,
+                        const CPURegister& arg3 = NoCPUReg);
+
+  // Code ageing support functions.
+
+  // Code ageing on ARM64 works similarly to on ARM. When V8 wants to mark a
+  // function as old, it replaces some of the function prologue (generated by
+  // FullCodeGenerator::Generate) with a call to a special stub (ultimately
+  // generated by GenerateMakeCodeYoungAgainCommon). The stub restores the
+  // function prologue to its initial young state (indicating that it has been
+  // recently run) and continues. A young function is therefore one which has a
+  // normal frame setup sequence, and an old function has a code age sequence
+  // which calls a code ageing stub.
+
+  // Set up a basic stack frame for young code (or code exempt from ageing) with
+  // type FUNCTION. It may be patched later for code ageing support. This is
+  // done by to Code::PatchPlatformCodeAge and EmitCodeAgeSequence.
+  //
+  // This function takes an Assembler so it can be called from either a
+  // MacroAssembler or a PatchingAssembler context.
+  static void EmitFrameSetupForCodeAgePatching(Assembler* assm);
+
+  // Call EmitFrameSetupForCodeAgePatching from a MacroAssembler context.
+  void EmitFrameSetupForCodeAgePatching();
+
+  // Emit a code age sequence that calls the relevant code age stub. The code
+  // generated by this sequence is expected to replace the code generated by
+  // EmitFrameSetupForCodeAgePatching, and represents an old function.
+  //
+  // If stub is NULL, this function generates the code age sequence but omits
+  // the stub address that is normally embedded in the instruction stream. This
+  // can be used by debug code to verify code age sequences.
+  static void EmitCodeAgeSequence(Assembler* assm, Code* stub);
+
+  // Call EmitCodeAgeSequence from a MacroAssembler context.
+  void EmitCodeAgeSequence(Code* stub);
+
+  // Return true if the sequence is a young sequence geneated by
+  // EmitFrameSetupForCodeAgePatching. Otherwise, this method asserts that the
+  // sequence is a code age sequence (emitted by EmitCodeAgeSequence).
+  static bool IsYoungSequence(Isolate* isolate, byte* sequence);
+
+  // Jumps to found label if a prototype map has dictionary elements.
+  void JumpIfDictionaryInPrototypeChain(Register object, Register scratch0,
+                                        Register scratch1, Label* found);
+
+  // Perform necessary maintenance operations before a push or after a pop.
+  //
+  // Note that size is specified in bytes.
+  void PushPreamble(Operand total_size);
+  void PopPostamble(Operand total_size);
+
+  void PushPreamble(int count, int size) { PushPreamble(count * size); }
+  void PopPostamble(int count, int size) { PopPostamble(count * size); }
+
+ private:
+  // Helpers for CopyFields.
+  // These each implement CopyFields in a different way.
+  void CopyFieldsLoopPairsHelper(Register dst, Register src, unsigned count,
+                                 Register scratch1, Register scratch2,
+                                 Register scratch3, Register scratch4,
+                                 Register scratch5);
+  void CopyFieldsUnrolledPairsHelper(Register dst, Register src, unsigned count,
+                                     Register scratch1, Register scratch2,
+                                     Register scratch3, Register scratch4);
+  void CopyFieldsUnrolledHelper(Register dst, Register src, unsigned count,
+                                Register scratch1, Register scratch2,
+                                Register scratch3);
+
+  // The actual Push and Pop implementations. These don't generate any code
+  // other than that required for the push or pop. This allows
+  // (Push|Pop)CPURegList to bundle together run-time assertions for a large
+  // block of registers.
+  //
+  // Note that size is per register, and is specified in bytes.
+  void PushHelper(int count, int size,
+                  const CPURegister& src0, const CPURegister& src1,
+                  const CPURegister& src2, const CPURegister& src3);
+  void PopHelper(int count, int size,
+                 const CPURegister& dst0, const CPURegister& dst1,
+                 const CPURegister& dst2, const CPURegister& dst3);
+
+  // Call Printf. On a native build, a simple call will be generated, but if the
+  // simulator is being used then a suitable pseudo-instruction is used. The
+  // arguments and stack (csp) must be prepared by the caller as for a normal
+  // AAPCS64 call to 'printf'.
+  //
+  // The 'args' argument should point to an array of variable arguments in their
+  // proper PCS registers (and in calling order). The argument registers can
+  // have mixed types. The format string (x0) should not be included.
+  void CallPrintf(int arg_count = 0, const CPURegister * args = NULL);
+
+  // Helper for throwing exceptions.  Compute a handler address and jump to
+  // it.  See the implementation for register usage.
+  void JumpToHandlerEntry(Register exception,
+                          Register object,
+                          Register state,
+                          Register scratch1,
+                          Register scratch2);
+
+  // Helper for implementing JumpIfNotInNewSpace and JumpIfInNewSpace.
+  void InNewSpace(Register object,
+                  Condition cond,  // eq for new space, ne otherwise.
+                  Label* branch);
+
+  // Try to represent a double as an int so that integer fast-paths may be
+  // used. Not every valid integer value is guaranteed to be caught.
+  // It supports both 32-bit and 64-bit integers depending whether 'as_int'
+  // is a W or X register.
+  //
+  // This does not distinguish between +0 and -0, so if this distinction is
+  // important it must be checked separately.
+  //
+  // On output the Z flag is set if the operation was successful.
+  void TryRepresentDoubleAsInt(Register as_int,
+                               FPRegister value,
+                               FPRegister scratch_d,
+                               Label* on_successful_conversion = NULL,
+                               Label* on_failed_conversion = NULL);
+
+  bool generating_stub_;
+#if DEBUG
+  // Tell whether any of the macro instruction can be used. When false the
+  // MacroAssembler will assert if a method which can emit a variable number
+  // of instructions is called.
+  bool allow_macro_instructions_;
+#endif
+  bool has_frame_;
+
+  // The Abort method should call a V8 runtime function, but the CallRuntime
+  // mechanism depends on CEntryStub. If use_real_aborts is false, Abort will
+  // use a simpler abort mechanism that doesn't depend on CEntryStub.
+  //
+  // The purpose of this is to allow Aborts to be compiled whilst CEntryStub is
+  // being generated.
+  bool use_real_aborts_;
+
+  // This handle will be patched with the code object on installation.
+  Handle<Object> code_object_;
+
+  // The register to use as a stack pointer for stack operations.
+  Register sp_;
+
+  // Scratch registers available for use by the MacroAssembler.
+  CPURegList tmp_list_;
+  CPURegList fptmp_list_;
+
+  void InitializeNewString(Register string,
+                           Register length,
+                           Heap::RootListIndex map_index,
+                           Register scratch1,
+                           Register scratch2);
+
+ public:
+  // Far branches resolving.
+  //
+  // The various classes of branch instructions with immediate offsets have
+  // different ranges. While the Assembler will fail to assemble a branch
+  // exceeding its range, the MacroAssembler offers a mechanism to resolve
+  // branches to too distant targets, either by tweaking the generated code to
+  // use branch instructions with wider ranges or generating veneers.
+  //
+  // Currently branches to distant targets are resolved using unconditional
+  // branch isntructions with a range of +-128MB. If that becomes too little
+  // (!), the mechanism can be extended to generate special veneers for really
+  // far targets.
+
+  // Helps resolve branching to labels potentially out of range.
+  // If the label is not bound, it registers the information necessary to later
+  // be able to emit a veneer for this branch if necessary.
+  // If the label is bound, it returns true if the label (or the previous link
+  // in the label chain) is out of range. In that case the caller is responsible
+  // for generating appropriate code.
+  // Otherwise it returns false.
+  // This function also checks wether veneers need to be emitted.
+  bool NeedExtraInstructionsOrRegisterBranch(Label *label,
+                                             ImmBranchType branch_type);
+};
+
+
+// Use this scope when you need a one-to-one mapping bewteen methods and
+// instructions. This scope prevents the MacroAssembler from being called and
+// literal pools from being emitted. It also asserts the number of instructions
+// emitted is what you specified when creating the scope.
+class InstructionAccurateScope BASE_EMBEDDED {
+ public:
+  explicit InstructionAccurateScope(MacroAssembler* masm, size_t count = 0)
+      : masm_(masm)
+#ifdef DEBUG
+        ,
+        size_(count * kInstructionSize)
+#endif
+  {
+    // Before blocking the const pool, see if it needs to be emitted.
+    masm_->CheckConstPool(false, true);
+    masm_->CheckVeneerPool(false, true);
+
+    masm_->StartBlockPools();
+#ifdef DEBUG
+    if (count != 0) {
+      masm_->bind(&start_);
+    }
+    previous_allow_macro_instructions_ = masm_->allow_macro_instructions();
+    masm_->set_allow_macro_instructions(false);
+#endif
+  }
+
+  ~InstructionAccurateScope() {
+    masm_->EndBlockPools();
+#ifdef DEBUG
+    if (start_.is_bound()) {
+      DCHECK(masm_->SizeOfCodeGeneratedSince(&start_) == size_);
+    }
+    masm_->set_allow_macro_instructions(previous_allow_macro_instructions_);
+#endif
+  }
+
+ private:
+  MacroAssembler* masm_;
+#ifdef DEBUG
+  size_t size_;
+  Label start_;
+  bool previous_allow_macro_instructions_;
+#endif
+};
+
+
+// This scope utility allows scratch registers to be managed safely. The
+// MacroAssembler's TmpList() (and FPTmpList()) is used as a pool of scratch
+// registers. These registers can be allocated on demand, and will be returned
+// at the end of the scope.
+//
+// When the scope ends, the MacroAssembler's lists will be restored to their
+// original state, even if the lists were modified by some other means.
+class UseScratchRegisterScope {
+ public:
+  explicit UseScratchRegisterScope(MacroAssembler* masm)
+      : available_(masm->TmpList()),
+        availablefp_(masm->FPTmpList()),
+        old_available_(available_->list()),
+        old_availablefp_(availablefp_->list()) {
+    DCHECK(available_->type() == CPURegister::kRegister);
+    DCHECK(availablefp_->type() == CPURegister::kFPRegister);
+  }
+
+  ~UseScratchRegisterScope();
+
+  // Take a register from the appropriate temps list. It will be returned
+  // automatically when the scope ends.
+  Register AcquireW() { return AcquireNextAvailable(available_).W(); }
+  Register AcquireX() { return AcquireNextAvailable(available_).X(); }
+  FPRegister AcquireS() { return AcquireNextAvailable(availablefp_).S(); }
+  FPRegister AcquireD() { return AcquireNextAvailable(availablefp_).D(); }
+
+  Register UnsafeAcquire(const Register& reg) {
+    return Register(UnsafeAcquire(available_, reg));
+  }
+
+  Register AcquireSameSizeAs(const Register& reg);
+  FPRegister AcquireSameSizeAs(const FPRegister& reg);
+
+ private:
+  static CPURegister AcquireNextAvailable(CPURegList* available);
+  static CPURegister UnsafeAcquire(CPURegList* available,
+                                   const CPURegister& reg);
+
+  // Available scratch registers.
+  CPURegList* available_;     // kRegister
+  CPURegList* availablefp_;   // kFPRegister
+
+  // The state of the available lists at the start of this scope.
+  RegList old_available_;     // kRegister
+  RegList old_availablefp_;   // kFPRegister
+};
+
+
+inline MemOperand ContextMemOperand(Register context, int index) {
+  return MemOperand(context, Context::SlotOffset(index));
+}
+
+inline MemOperand GlobalObjectMemOperand() {
+  return ContextMemOperand(cp, Context::GLOBAL_OBJECT_INDEX);
+}
+
+
+// Encode and decode information about patchable inline SMI checks.
+class InlineSmiCheckInfo {
+ public:
+  explicit InlineSmiCheckInfo(Address info);
+
+  bool HasSmiCheck() const {
+    return smi_check_ != NULL;
+  }
+
+  const Register& SmiRegister() const {
+    return reg_;
+  }
+
+  Instruction* SmiCheck() const {
+    return smi_check_;
+  }
+
+  // Use MacroAssembler::InlineData to emit information about patchable inline
+  // SMI checks. The caller may specify 'reg' as NoReg and an unbound 'site' to
+  // indicate that there is no inline SMI check. Note that 'reg' cannot be csp.
+  //
+  // The generated patch information can be read using the InlineSMICheckInfo
+  // class.
+  static void Emit(MacroAssembler* masm, const Register& reg,
+                   const Label* smi_check);
+
+  // Emit information to indicate that there is no inline SMI check.
+  static void EmitNotInlined(MacroAssembler* masm) {
+    Label unbound;
+    Emit(masm, NoReg, &unbound);
+  }
+
+ private:
+  Register reg_;
+  Instruction* smi_check_;
+
+  // Fields in the data encoded by InlineData.
+
+  // A width of 5 (Rd_width) for the SMI register preclues the use of csp,
+  // since kSPRegInternalCode is 63. However, csp should never hold a SMI or be
+  // used in a patchable check. The Emit() method checks this.
+  //
+  // Note that the total size of the fields is restricted by the underlying
+  // storage size handled by the BitField class, which is a uint32_t.
+  class RegisterBits : public BitField<unsigned, 0, 5> {};
+  class DeltaBits : public BitField<uint32_t, 5, 32-5> {};
+};
+
+} }  // namespace v8::internal
+
+#ifdef GENERATED_CODE_COVERAGE
+#error "Unsupported option"
+#define CODE_COVERAGE_STRINGIFY(x) #x
+#define CODE_COVERAGE_TOSTRING(x) CODE_COVERAGE_STRINGIFY(x)
+#define __FILE_LINE__ __FILE__ ":" CODE_COVERAGE_TOSTRING(__LINE__)
+#define ACCESS_MASM(masm) masm->stop(__FILE_LINE__); masm->
+#else
+#define ACCESS_MASM(masm) masm->
+#endif
+
+#endif  // V8_ARM64_MACRO_ASSEMBLER_ARM64_H_
diff --git a/src/arm64/regexp-macro-assembler-arm64.cc b/src/arm64/regexp-macro-assembler-arm64.cc
new file mode 100644
index 0000000..e9a485d
--- /dev/null
+++ b/src/arm64/regexp-macro-assembler-arm64.cc
@@ -0,0 +1,1702 @@
+// Copyright 2013 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/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/code-stubs.h"
+#include "src/cpu-profiler.h"
+#include "src/log.h"
+#include "src/macro-assembler.h"
+#include "src/regexp-macro-assembler.h"
+#include "src/regexp-stack.h"
+#include "src/unicode.h"
+
+#include "src/arm64/regexp-macro-assembler-arm64.h"
+
+namespace v8 {
+namespace internal {
+
+#ifndef V8_INTERPRETED_REGEXP
+/*
+ * This assembler uses the following register assignment convention:
+ * - w19     : Used to temporarely store a value before a call to C code.
+ *             See CheckNotBackReferenceIgnoreCase.
+ * - x20     : Pointer to the current code object (Code*),
+ *             it includes the heap object tag.
+ * - w21     : Current position in input, as negative offset from
+ *             the end of the string. Please notice that this is
+ *             the byte offset, not the character offset!
+ * - w22     : Currently loaded character. Must be loaded using
+ *             LoadCurrentCharacter before using any of the dispatch methods.
+ * - x23     : Points to tip of backtrack stack.
+ * - w24     : Position of the first character minus one: non_position_value.
+ *             Used to initialize capture registers.
+ * - x25     : Address at the end of the input string: input_end.
+ *             Points to byte after last character in input.
+ * - x26     : Address at the start of the input string: input_start.
+ * - w27     : Where to start in the input string.
+ * - x28     : Output array pointer.
+ * - x29/fp  : Frame pointer. Used to access arguments, local variables and
+ *             RegExp registers.
+ * - x16/x17 : IP registers, used by assembler. Very volatile.
+ * - csp     : Points to tip of C stack.
+ *
+ * - x0-x7   : Used as a cache to store 32 bit capture registers. These
+ *             registers need to be retained every time a call to C code
+ *             is done.
+ *
+ * The remaining registers are free for computations.
+ * Each call to a public method should retain this convention.
+ *
+ * The stack will have the following structure:
+ *
+ *  Location    Name               Description
+ *              (as referred to in
+ *              the code)
+ *
+ *  - fp[104]   isolate            Address of the current isolate.
+ *  - fp[96]    return_address     Secondary link/return address
+ *                                 used by an exit frame if this is a
+ *                                 native call.
+ *  ^^^ csp when called ^^^
+ *  - fp[88]    lr                 Return from the RegExp code.
+ *  - fp[80]    r29                Old frame pointer (CalleeSaved).
+ *  - fp[0..72] r19-r28            Backup of CalleeSaved registers.
+ *  - fp[-8]    direct_call        1 => Direct call from JavaScript code.
+ *                                 0 => Call through the runtime system.
+ *  - fp[-16]   stack_base         High end of the memory area to use as
+ *                                 the backtracking stack.
+ *  - fp[-24]   output_size        Output may fit multiple sets of matches.
+ *  - fp[-32]   input              Handle containing the input string.
+ *  - fp[-40]   success_counter
+ *  ^^^^^^^^^^^^^ From here and downwards we store 32 bit values ^^^^^^^^^^^^^
+ *  - fp[-44]   register N         Capture registers initialized with
+ *  - fp[-48]   register N + 1     non_position_value.
+ *              ...                The first kNumCachedRegisters (N) registers
+ *              ...                are cached in x0 to x7.
+ *              ...                Only positions must be stored in the first
+ *  -           ...                num_saved_registers_ registers.
+ *  -           ...
+ *  -           register N + num_registers - 1
+ *  ^^^^^^^^^ csp ^^^^^^^^^
+ *
+ * The first num_saved_registers_ registers are initialized to point to
+ * "character -1" in the string (i.e., char_size() bytes before the first
+ * character of the string). The remaining registers start out as garbage.
+ *
+ * The data up to the return address must be placed there by the calling
+ * code and the remaining arguments are passed in registers, e.g. by calling the
+ * code entry as cast to a function with the signature:
+ * int (*match)(String* input,
+ *              int start_offset,
+ *              Address input_start,
+ *              Address input_end,
+ *              int* output,
+ *              int output_size,
+ *              Address stack_base,
+ *              bool direct_call = false,
+ *              Address secondary_return_address,  // Only used by native call.
+ *              Isolate* isolate)
+ * The call is performed by NativeRegExpMacroAssembler::Execute()
+ * (in regexp-macro-assembler.cc) via the CALL_GENERATED_REGEXP_CODE macro
+ * in arm64/simulator-arm64.h.
+ * When calling as a non-direct call (i.e., from C++ code), the return address
+ * area is overwritten with the LR register by the RegExp code. When doing a
+ * direct call from generated code, the return address is placed there by
+ * the calling code, as in a normal exit frame.
+ */
+
+#define __ ACCESS_MASM(masm_)
+
+RegExpMacroAssemblerARM64::RegExpMacroAssemblerARM64(
+    Mode mode,
+    int registers_to_save,
+    Zone* zone)
+    : NativeRegExpMacroAssembler(zone),
+      masm_(new MacroAssembler(zone->isolate(), NULL, kRegExpCodeSize)),
+      mode_(mode),
+      num_registers_(registers_to_save),
+      num_saved_registers_(registers_to_save),
+      entry_label_(),
+      start_label_(),
+      success_label_(),
+      backtrack_label_(),
+      exit_label_() {
+  __ SetStackPointer(csp);
+  DCHECK_EQ(0, registers_to_save % 2);
+  // We can cache at most 16 W registers in x0-x7.
+  STATIC_ASSERT(kNumCachedRegisters <= 16);
+  STATIC_ASSERT((kNumCachedRegisters % 2) == 0);
+  __ B(&entry_label_);   // We'll write the entry code later.
+  __ Bind(&start_label_);  // And then continue from here.
+}
+
+
+RegExpMacroAssemblerARM64::~RegExpMacroAssemblerARM64() {
+  delete masm_;
+  // Unuse labels in case we throw away the assembler without calling GetCode.
+  entry_label_.Unuse();
+  start_label_.Unuse();
+  success_label_.Unuse();
+  backtrack_label_.Unuse();
+  exit_label_.Unuse();
+  check_preempt_label_.Unuse();
+  stack_overflow_label_.Unuse();
+}
+
+int RegExpMacroAssemblerARM64::stack_limit_slack()  {
+  return RegExpStack::kStackLimitSlack;
+}
+
+
+void RegExpMacroAssemblerARM64::AdvanceCurrentPosition(int by) {
+  if (by != 0) {
+    __ Add(current_input_offset(),
+           current_input_offset(), by * char_size());
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::AdvanceRegister(int reg, int by) {
+  DCHECK((reg >= 0) && (reg < num_registers_));
+  if (by != 0) {
+    Register to_advance;
+    RegisterState register_state = GetRegisterState(reg);
+    switch (register_state) {
+      case STACKED:
+        __ Ldr(w10, register_location(reg));
+        __ Add(w10, w10, by);
+        __ Str(w10, register_location(reg));
+        break;
+      case CACHED_LSW:
+        to_advance = GetCachedRegister(reg);
+        __ Add(to_advance, to_advance, by);
+        break;
+      case CACHED_MSW:
+        to_advance = GetCachedRegister(reg);
+        __ Add(to_advance, to_advance,
+               static_cast<int64_t>(by) << kWRegSizeInBits);
+        break;
+      default:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::Backtrack() {
+  CheckPreemption();
+  Pop(w10);
+  __ Add(x10, code_pointer(), Operand(w10, UXTW));
+  __ Br(x10);
+}
+
+
+void RegExpMacroAssemblerARM64::Bind(Label* label) {
+  __ Bind(label);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacter(uint32_t c, Label* on_equal) {
+  CompareAndBranchOrBacktrack(current_character(), c, eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacterGT(uc16 limit,
+                                                 Label* on_greater) {
+  CompareAndBranchOrBacktrack(current_character(), limit, hi, on_greater);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckAtStart(Label* on_at_start) {
+  Label not_at_start;
+  // Did we start the match at the start of the input string?
+  CompareAndBranchOrBacktrack(start_offset(), 0, ne, &not_at_start);
+  // If we did, are we still at the start of the input string?
+  __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
+  __ Cmp(x10, input_start());
+  BranchOrBacktrack(eq, on_at_start);
+  __ Bind(&not_at_start);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckNotAtStart(Label* on_not_at_start) {
+  // Did we start the match at the start of the input string?
+  CompareAndBranchOrBacktrack(start_offset(), 0, ne, on_not_at_start);
+  // If we did, are we still at the start of the input string?
+  __ Add(x10, input_end(), Operand(current_input_offset(), SXTW));
+  __ Cmp(x10, input_start());
+  BranchOrBacktrack(ne, on_not_at_start);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacterLT(uc16 limit, Label* on_less) {
+  CompareAndBranchOrBacktrack(current_character(), limit, lo, on_less);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacters(Vector<const uc16> str,
+                                              int cp_offset,
+                                              Label* on_failure,
+                                              bool check_end_of_string) {
+  // This method is only ever called from the cctests.
+
+  if (check_end_of_string) {
+    // Is last character of required match inside string.
+    CheckPosition(cp_offset + str.length() - 1, on_failure);
+  }
+
+  Register characters_address = x11;
+
+  __ Add(characters_address,
+         input_end(),
+         Operand(current_input_offset(), SXTW));
+  if (cp_offset != 0) {
+    __ Add(characters_address, characters_address, cp_offset * char_size());
+  }
+
+  for (int i = 0; i < str.length(); i++) {
+    if (mode_ == LATIN1) {
+      __ Ldrb(w10, MemOperand(characters_address, 1, PostIndex));
+      DCHECK(str[i] <= String::kMaxOneByteCharCode);
+    } else {
+      __ Ldrh(w10, MemOperand(characters_address, 2, PostIndex));
+    }
+    CompareAndBranchOrBacktrack(w10, str[i], ne, on_failure);
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::CheckGreedyLoop(Label* on_equal) {
+  __ Ldr(w10, MemOperand(backtrack_stackpointer()));
+  __ Cmp(current_input_offset(), w10);
+  __ Cset(x11, eq);
+  __ Add(backtrack_stackpointer(),
+         backtrack_stackpointer(), Operand(x11, LSL, kWRegSizeLog2));
+  BranchOrBacktrack(eq, on_equal);
+}
+
+void RegExpMacroAssemblerARM64::CheckNotBackReferenceIgnoreCase(
+    int start_reg,
+    Label* on_no_match) {
+  Label fallthrough;
+
+  Register capture_start_offset = w10;
+  // Save the capture length in a callee-saved register so it will
+  // be preserved if we call a C helper.
+  Register capture_length = w19;
+  DCHECK(kCalleeSaved.IncludesAliasOf(capture_length));
+
+  // Find length of back-referenced capture.
+  DCHECK((start_reg % 2) == 0);
+  if (start_reg < kNumCachedRegisters) {
+    __ Mov(capture_start_offset.X(), GetCachedRegister(start_reg));
+    __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
+  } else {
+    __ Ldp(w11, capture_start_offset, capture_location(start_reg, x10));
+  }
+  __ Sub(capture_length, w11, capture_start_offset);  // Length to check.
+  // Succeed on empty capture (including no capture).
+  __ Cbz(capture_length, &fallthrough);
+
+  // Check that there are enough characters left in the input.
+  __ Cmn(capture_length, current_input_offset());
+  BranchOrBacktrack(gt, on_no_match);
+
+  if (mode_ == LATIN1) {
+    Label success;
+    Label fail;
+    Label loop_check;
+
+    Register capture_start_address = x12;
+    Register capture_end_addresss = x13;
+    Register current_position_address = x14;
+
+    __ Add(capture_start_address,
+           input_end(),
+           Operand(capture_start_offset, SXTW));
+    __ Add(capture_end_addresss,
+           capture_start_address,
+           Operand(capture_length, SXTW));
+    __ Add(current_position_address,
+           input_end(),
+           Operand(current_input_offset(), SXTW));
+
+    Label loop;
+    __ Bind(&loop);
+    __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
+    __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
+    __ Cmp(w10, w11);
+    __ B(eq, &loop_check);
+
+    // Mismatch, try case-insensitive match (converting letters to lower-case).
+    __ Orr(w10, w10, 0x20);  // Convert capture character to lower-case.
+    __ Orr(w11, w11, 0x20);  // Also convert input character.
+    __ Cmp(w11, w10);
+    __ B(ne, &fail);
+    __ Sub(w10, w10, 'a');
+    __ Cmp(w10, 'z' - 'a');  // Is w10 a lowercase letter?
+    __ B(ls, &loop_check);  // In range 'a'-'z'.
+    // Latin-1: Check for values in range [224,254] but not 247.
+    __ Sub(w10, w10, 224 - 'a');
+    __ Cmp(w10, 254 - 224);
+    __ Ccmp(w10, 247 - 224, ZFlag, ls);  // Check for 247.
+    __ B(eq, &fail);  // Weren't Latin-1 letters.
+
+    __ Bind(&loop_check);
+    __ Cmp(capture_start_address, capture_end_addresss);
+    __ B(lt, &loop);
+    __ B(&success);
+
+    __ Bind(&fail);
+    BranchOrBacktrack(al, on_no_match);
+
+    __ Bind(&success);
+    // Compute new value of character position after the matched part.
+    __ Sub(current_input_offset().X(), current_position_address, input_end());
+    if (masm_->emit_debug_code()) {
+      __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
+      __ Ccmp(current_input_offset(), 0, NoFlag, eq);
+      // The current input offset should be <= 0, and fit in a W register.
+      __ Check(le, kOffsetOutOfRange);
+    }
+  } else {
+    DCHECK(mode_ == UC16);
+    int argument_count = 4;
+
+    // The cached registers need to be retained.
+    CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
+    DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters);
+    __ PushCPURegList(cached_registers);
+
+    // Put arguments into arguments registers.
+    // Parameters are
+    //   x0: Address byte_offset1 - Address captured substring's start.
+    //   x1: Address byte_offset2 - Address of current character position.
+    //   w2: size_t byte_length - length of capture in bytes(!)
+    //   x3: Isolate* isolate
+
+    // Address of start of capture.
+    __ Add(x0, input_end(), Operand(capture_start_offset, SXTW));
+    // Length of capture.
+    __ Mov(w2, capture_length);
+    // Address of current input position.
+    __ Add(x1, input_end(), Operand(current_input_offset(), SXTW));
+    // Isolate.
+    __ Mov(x3, ExternalReference::isolate_address(isolate()));
+
+    {
+      AllowExternalCallThatCantCauseGC scope(masm_);
+      ExternalReference function =
+          ExternalReference::re_case_insensitive_compare_uc16(isolate());
+      __ CallCFunction(function, argument_count);
+    }
+
+    // Check if function returned non-zero for success or zero for failure.
+    // x0 is one of the registers used as a cache so it must be tested before
+    // the cache is restored.
+    __ Cmp(x0, 0);
+    __ PopCPURegList(cached_registers);
+    BranchOrBacktrack(eq, on_no_match);
+
+    // On success, increment position by length of capture.
+    __ Add(current_input_offset(), current_input_offset(), capture_length);
+  }
+
+  __ Bind(&fallthrough);
+}
+
+void RegExpMacroAssemblerARM64::CheckNotBackReference(
+    int start_reg,
+    Label* on_no_match) {
+  Label fallthrough;
+
+  Register capture_start_address = x12;
+  Register capture_end_address = x13;
+  Register current_position_address = x14;
+  Register capture_length = w15;
+
+  // Find length of back-referenced capture.
+  DCHECK((start_reg % 2) == 0);
+  if (start_reg < kNumCachedRegisters) {
+    __ Mov(x10, GetCachedRegister(start_reg));
+    __ Lsr(x11, GetCachedRegister(start_reg), kWRegSizeInBits);
+  } else {
+    __ Ldp(w11, w10, capture_location(start_reg, x10));
+  }
+  __ Sub(capture_length, w11, w10);  // Length to check.
+  // Succeed on empty capture (including no capture).
+  __ Cbz(capture_length, &fallthrough);
+
+  // Check that there are enough characters left in the input.
+  __ Cmn(capture_length, current_input_offset());
+  BranchOrBacktrack(gt, on_no_match);
+
+  // Compute pointers to match string and capture string
+  __ Add(capture_start_address, input_end(), Operand(w10, SXTW));
+  __ Add(capture_end_address,
+         capture_start_address,
+         Operand(capture_length, SXTW));
+  __ Add(current_position_address,
+         input_end(),
+         Operand(current_input_offset(), SXTW));
+
+  Label loop;
+  __ Bind(&loop);
+  if (mode_ == LATIN1) {
+    __ Ldrb(w10, MemOperand(capture_start_address, 1, PostIndex));
+    __ Ldrb(w11, MemOperand(current_position_address, 1, PostIndex));
+  } else {
+    DCHECK(mode_ == UC16);
+    __ Ldrh(w10, MemOperand(capture_start_address, 2, PostIndex));
+    __ Ldrh(w11, MemOperand(current_position_address, 2, PostIndex));
+  }
+  __ Cmp(w10, w11);
+  BranchOrBacktrack(ne, on_no_match);
+  __ Cmp(capture_start_address, capture_end_address);
+  __ B(lt, &loop);
+
+  // Move current character position to position after match.
+  __ Sub(current_input_offset().X(), current_position_address, input_end());
+  if (masm_->emit_debug_code()) {
+    __ Cmp(current_input_offset().X(), Operand(current_input_offset(), SXTW));
+    __ Ccmp(current_input_offset(), 0, NoFlag, eq);
+    // The current input offset should be <= 0, and fit in a W register.
+    __ Check(le, kOffsetOutOfRange);
+  }
+  __ Bind(&fallthrough);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckNotCharacter(unsigned c,
+                                                  Label* on_not_equal) {
+  CompareAndBranchOrBacktrack(current_character(), c, ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacterAfterAnd(uint32_t c,
+                                                       uint32_t mask,
+                                                       Label* on_equal) {
+  __ And(w10, current_character(), mask);
+  CompareAndBranchOrBacktrack(w10, c, eq, on_equal);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckNotCharacterAfterAnd(unsigned c,
+                                                          unsigned mask,
+                                                          Label* on_not_equal) {
+  __ And(w10, current_character(), mask);
+  CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckNotCharacterAfterMinusAnd(
+    uc16 c,
+    uc16 minus,
+    uc16 mask,
+    Label* on_not_equal) {
+  DCHECK(minus < String::kMaxUtf16CodeUnit);
+  __ Sub(w10, current_character(), minus);
+  __ And(w10, w10, mask);
+  CompareAndBranchOrBacktrack(w10, c, ne, on_not_equal);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacterInRange(
+    uc16 from,
+    uc16 to,
+    Label* on_in_range) {
+  __ Sub(w10, current_character(), from);
+  // Unsigned lower-or-same condition.
+  CompareAndBranchOrBacktrack(w10, to - from, ls, on_in_range);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckCharacterNotInRange(
+    uc16 from,
+    uc16 to,
+    Label* on_not_in_range) {
+  __ Sub(w10, current_character(), from);
+  // Unsigned higher condition.
+  CompareAndBranchOrBacktrack(w10, to - from, hi, on_not_in_range);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckBitInTable(
+    Handle<ByteArray> table,
+    Label* on_bit_set) {
+  __ Mov(x11, Operand(table));
+  if ((mode_ != LATIN1) || (kTableMask != String::kMaxOneByteCharCode)) {
+    __ And(w10, current_character(), kTableMask);
+    __ Add(w10, w10, ByteArray::kHeaderSize - kHeapObjectTag);
+  } else {
+    __ Add(w10, current_character(), ByteArray::kHeaderSize - kHeapObjectTag);
+  }
+  __ Ldrb(w11, MemOperand(x11, w10, UXTW));
+  CompareAndBranchOrBacktrack(w11, 0, ne, on_bit_set);
+}
+
+
+bool RegExpMacroAssemblerARM64::CheckSpecialCharacterClass(uc16 type,
+                                                           Label* on_no_match) {
+  // Range checks (c in min..max) are generally implemented by an unsigned
+  // (c - min) <= (max - min) check
+  switch (type) {
+  case 's':
+    // Match space-characters
+    if (mode_ == LATIN1) {
+      // One byte space characters are '\t'..'\r', ' ' and \u00a0.
+      Label success;
+      // Check for ' ' or 0x00a0.
+      __ Cmp(current_character(), ' ');
+      __ Ccmp(current_character(), 0x00a0, ZFlag, ne);
+      __ B(eq, &success);
+      // Check range 0x09..0x0d.
+      __ Sub(w10, current_character(), '\t');
+      CompareAndBranchOrBacktrack(w10, '\r' - '\t', hi, on_no_match);
+      __ Bind(&success);
+      return true;
+    }
+    return false;
+  case 'S':
+    // The emitted code for generic character classes is good enough.
+    return false;
+  case 'd':
+    // Match ASCII digits ('0'..'9').
+    __ Sub(w10, current_character(), '0');
+    CompareAndBranchOrBacktrack(w10, '9' - '0', hi, on_no_match);
+    return true;
+  case 'D':
+    // Match ASCII non-digits.
+    __ Sub(w10, current_character(), '0');
+    CompareAndBranchOrBacktrack(w10, '9' - '0', ls, on_no_match);
+    return true;
+  case '.': {
+    // Match non-newlines (not 0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+    // Here we emit the conditional branch only once at the end to make branch
+    // prediction more efficient, even though we could branch out of here
+    // as soon as a character matches.
+    __ Cmp(current_character(), 0x0a);
+    __ Ccmp(current_character(), 0x0d, ZFlag, ne);
+    if (mode_ == UC16) {
+      __ Sub(w10, current_character(), 0x2028);
+      // If the Z flag was set we clear the flags to force a branch.
+      __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
+      // ls -> !((C==1) && (Z==0))
+      BranchOrBacktrack(ls, on_no_match);
+    } else {
+      BranchOrBacktrack(eq, on_no_match);
+    }
+    return true;
+  }
+  case 'n': {
+    // Match newlines (0x0a('\n'), 0x0d('\r'), 0x2028 and 0x2029)
+    // We have to check all 4 newline characters before emitting
+    // the conditional branch.
+    __ Cmp(current_character(), 0x0a);
+    __ Ccmp(current_character(), 0x0d, ZFlag, ne);
+    if (mode_ == UC16) {
+      __ Sub(w10, current_character(), 0x2028);
+      // If the Z flag was set we clear the flags to force a fall-through.
+      __ Ccmp(w10, 0x2029 - 0x2028, NoFlag, ne);
+      // hi -> (C==1) && (Z==0)
+      BranchOrBacktrack(hi, on_no_match);
+    } else {
+      BranchOrBacktrack(ne, on_no_match);
+    }
+    return true;
+  }
+  case 'w': {
+    if (mode_ != LATIN1) {
+      // Table is 256 entries, so all Latin1 characters can be tested.
+      CompareAndBranchOrBacktrack(current_character(), 'z', hi, on_no_match);
+    }
+    ExternalReference map = ExternalReference::re_word_character_map();
+    __ Mov(x10, map);
+    __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
+    CompareAndBranchOrBacktrack(w10, 0, eq, on_no_match);
+    return true;
+  }
+  case 'W': {
+    Label done;
+    if (mode_ != LATIN1) {
+      // Table is 256 entries, so all Latin1 characters can be tested.
+      __ Cmp(current_character(), 'z');
+      __ B(hi, &done);
+    }
+    ExternalReference map = ExternalReference::re_word_character_map();
+    __ Mov(x10, map);
+    __ Ldrb(w10, MemOperand(x10, current_character(), UXTW));
+    CompareAndBranchOrBacktrack(w10, 0, ne, on_no_match);
+    __ Bind(&done);
+    return true;
+  }
+  case '*':
+    // Match any character.
+    return true;
+  // No custom implementation (yet): s(UC16), S(UC16).
+  default:
+    return false;
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::Fail() {
+  __ Mov(w0, FAILURE);
+  __ B(&exit_label_);
+}
+
+
+Handle<HeapObject> RegExpMacroAssemblerARM64::GetCode(Handle<String> source) {
+  Label return_w0;
+  // Finalize code - write the entry point code now we know how many
+  // registers we need.
+
+  // Entry code:
+  __ Bind(&entry_label_);
+
+  // Arguments on entry:
+  // x0:  String*  input
+  // x1:  int      start_offset
+  // x2:  byte*    input_start
+  // x3:  byte*    input_end
+  // x4:  int*     output array
+  // x5:  int      output array size
+  // x6:  Address  stack_base
+  // x7:  int      direct_call
+
+  // The stack pointer should be csp on entry.
+  //  csp[8]:  address of the current isolate
+  //  csp[0]:  secondary link/return address used by native call
+
+  // Tell the system that we have a stack frame.  Because the type is MANUAL, no
+  // code is generated.
+  FrameScope scope(masm_, StackFrame::MANUAL);
+
+  // Push registers on the stack, only push the argument registers that we need.
+  CPURegList argument_registers(x0, x5, x6, x7);
+
+  CPURegList registers_to_retain = kCalleeSaved;
+  DCHECK(kCalleeSaved.Count() == 11);
+  registers_to_retain.Combine(lr);
+
+  DCHECK(csp.Is(__ StackPointer()));
+  __ PushCPURegList(registers_to_retain);
+  __ PushCPURegList(argument_registers);
+
+  // Set frame pointer in place.
+  __ Add(frame_pointer(), csp, argument_registers.Count() * kPointerSize);
+
+  // Initialize callee-saved registers.
+  __ Mov(start_offset(), w1);
+  __ Mov(input_start(), x2);
+  __ Mov(input_end(), x3);
+  __ Mov(output_array(), x4);
+
+  // Set the number of registers we will need to allocate, that is:
+  //   - success_counter (X register)
+  //   - (num_registers_ - kNumCachedRegisters) (W registers)
+  int num_wreg_to_allocate = num_registers_ - kNumCachedRegisters;
+  // Do not allocate registers on the stack if they can all be cached.
+  if (num_wreg_to_allocate < 0) { num_wreg_to_allocate = 0; }
+  // Make room for the success_counter.
+  num_wreg_to_allocate += 2;
+
+  // Make sure the stack alignment will be respected.
+  int alignment = masm_->ActivationFrameAlignment();
+  DCHECK_EQ(alignment % 16, 0);
+  int align_mask = (alignment / kWRegSize) - 1;
+  num_wreg_to_allocate = (num_wreg_to_allocate + align_mask) & ~align_mask;
+
+  // Check if we have space on the stack.
+  Label stack_limit_hit;
+  Label stack_ok;
+
+  ExternalReference stack_limit =
+      ExternalReference::address_of_stack_limit(isolate());
+  __ Mov(x10, stack_limit);
+  __ Ldr(x10, MemOperand(x10));
+  __ Subs(x10, csp, x10);
+
+  // Handle it if the stack pointer is already below the stack limit.
+  __ B(ls, &stack_limit_hit);
+
+  // Check if there is room for the variable number of registers above
+  // the stack limit.
+  __ Cmp(x10, num_wreg_to_allocate * kWRegSize);
+  __ B(hs, &stack_ok);
+
+  // Exit with OutOfMemory exception. There is not enough space on the stack
+  // for our working registers.
+  __ Mov(w0, EXCEPTION);
+  __ B(&return_w0);
+
+  __ Bind(&stack_limit_hit);
+  CallCheckStackGuardState(x10);
+  // If returned value is non-zero, we exit with the returned value as result.
+  __ Cbnz(w0, &return_w0);
+
+  __ Bind(&stack_ok);
+
+  // Allocate space on stack.
+  __ Claim(num_wreg_to_allocate, kWRegSize);
+
+  // Initialize success_counter with 0.
+  __ Str(wzr, MemOperand(frame_pointer(), kSuccessCounter));
+
+  // Find negative length (offset of start relative to end).
+  __ Sub(x10, input_start(), input_end());
+  if (masm_->emit_debug_code()) {
+    // Check that the input string length is < 2^30.
+    __ Neg(x11, x10);
+    __ Cmp(x11, (1<<30) - 1);
+    __ Check(ls, kInputStringTooLong);
+  }
+  __ Mov(current_input_offset(), w10);
+
+  // The non-position value is used as a clearing value for the
+  // capture registers, it corresponds to the position of the first character
+  // minus one.
+  __ Sub(non_position_value(), current_input_offset(), char_size());
+  __ Sub(non_position_value(), non_position_value(),
+         Operand(start_offset(), LSL, (mode_ == UC16) ? 1 : 0));
+  // We can store this value twice in an X register for initializing
+  // on-stack registers later.
+  __ Orr(twice_non_position_value(),
+         non_position_value().X(),
+         Operand(non_position_value().X(), LSL, kWRegSizeInBits));
+
+  // Initialize code pointer register.
+  __ Mov(code_pointer(), Operand(masm_->CodeObject()));
+
+  Label load_char_start_regexp, start_regexp;
+  // Load newline if index is at start, previous character otherwise.
+  __ Cbnz(start_offset(), &load_char_start_regexp);
+  __ Mov(current_character(), '\n');
+  __ B(&start_regexp);
+
+  // Global regexp restarts matching here.
+  __ Bind(&load_char_start_regexp);
+  // Load previous char as initial value of current character register.
+  LoadCurrentCharacterUnchecked(-1, 1);
+  __ Bind(&start_regexp);
+  // Initialize on-stack registers.
+  if (num_saved_registers_ > 0) {
+    ClearRegisters(0, num_saved_registers_ - 1);
+  }
+
+  // Initialize backtrack stack pointer.
+  __ Ldr(backtrack_stackpointer(), MemOperand(frame_pointer(), kStackBase));
+
+  // Execute
+  __ B(&start_label_);
+
+  if (backtrack_label_.is_linked()) {
+    __ Bind(&backtrack_label_);
+    Backtrack();
+  }
+
+  if (success_label_.is_linked()) {
+    Register first_capture_start = w15;
+
+    // Save captures when successful.
+    __ Bind(&success_label_);
+
+    if (num_saved_registers_ > 0) {
+      // V8 expects the output to be an int32_t array.
+      Register capture_start = w12;
+      Register capture_end = w13;
+      Register input_length = w14;
+
+      // Copy captures to output.
+
+      // Get string length.
+      __ Sub(x10, input_end(), input_start());
+      if (masm_->emit_debug_code()) {
+        // Check that the input string length is < 2^30.
+        __ Cmp(x10, (1<<30) - 1);
+        __ Check(ls, kInputStringTooLong);
+      }
+      // input_start has a start_offset offset on entry. We need to include
+      // it when computing the length of the whole string.
+      if (mode_ == UC16) {
+        __ Add(input_length, start_offset(), Operand(w10, LSR, 1));
+      } else {
+        __ Add(input_length, start_offset(), w10);
+      }
+
+      // Copy the results to the output array from the cached registers first.
+      for (int i = 0;
+           (i < num_saved_registers_) && (i < kNumCachedRegisters);
+           i += 2) {
+        __ Mov(capture_start.X(), GetCachedRegister(i));
+        __ Lsr(capture_end.X(), capture_start.X(), kWRegSizeInBits);
+        if ((i == 0) && global_with_zero_length_check()) {
+          // Keep capture start for the zero-length check later.
+          __ Mov(first_capture_start, capture_start);
+        }
+        // Offsets need to be relative to the start of the string.
+        if (mode_ == UC16) {
+          __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
+          __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
+        } else {
+          __ Add(capture_start, input_length, capture_start);
+          __ Add(capture_end, input_length, capture_end);
+        }
+        // The output pointer advances for a possible global match.
+        __ Stp(capture_start,
+               capture_end,
+               MemOperand(output_array(), kPointerSize, PostIndex));
+      }
+
+      // Only carry on if there are more than kNumCachedRegisters capture
+      // registers.
+      int num_registers_left_on_stack =
+          num_saved_registers_ - kNumCachedRegisters;
+      if (num_registers_left_on_stack > 0) {
+        Register base = x10;
+        // There are always an even number of capture registers. A couple of
+        // registers determine one match with two offsets.
+        DCHECK_EQ(0, num_registers_left_on_stack % 2);
+        __ Add(base, frame_pointer(), kFirstCaptureOnStack);
+
+        // We can unroll the loop here, we should not unroll for less than 2
+        // registers.
+        STATIC_ASSERT(kNumRegistersToUnroll > 2);
+        if (num_registers_left_on_stack <= kNumRegistersToUnroll) {
+          for (int i = 0; i < num_registers_left_on_stack / 2; i++) {
+            __ Ldp(capture_end,
+                   capture_start,
+                   MemOperand(base, -kPointerSize, PostIndex));
+            if ((i == 0) && global_with_zero_length_check()) {
+              // Keep capture start for the zero-length check later.
+              __ Mov(first_capture_start, capture_start);
+            }
+            // Offsets need to be relative to the start of the string.
+            if (mode_ == UC16) {
+              __ Add(capture_start,
+                     input_length,
+                     Operand(capture_start, ASR, 1));
+              __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
+            } else {
+              __ Add(capture_start, input_length, capture_start);
+              __ Add(capture_end, input_length, capture_end);
+            }
+            // The output pointer advances for a possible global match.
+            __ Stp(capture_start,
+                   capture_end,
+                   MemOperand(output_array(), kPointerSize, PostIndex));
+          }
+        } else {
+          Label loop, start;
+          __ Mov(x11, num_registers_left_on_stack);
+
+          __ Ldp(capture_end,
+                 capture_start,
+                 MemOperand(base, -kPointerSize, PostIndex));
+          if (global_with_zero_length_check()) {
+            __ Mov(first_capture_start, capture_start);
+          }
+          __ B(&start);
+
+          __ Bind(&loop);
+          __ Ldp(capture_end,
+                 capture_start,
+                 MemOperand(base, -kPointerSize, PostIndex));
+          __ Bind(&start);
+          if (mode_ == UC16) {
+            __ Add(capture_start, input_length, Operand(capture_start, ASR, 1));
+            __ Add(capture_end, input_length, Operand(capture_end, ASR, 1));
+          } else {
+            __ Add(capture_start, input_length, capture_start);
+            __ Add(capture_end, input_length, capture_end);
+          }
+          // The output pointer advances for a possible global match.
+          __ Stp(capture_start,
+                 capture_end,
+                 MemOperand(output_array(), kPointerSize, PostIndex));
+          __ Sub(x11, x11, 2);
+          __ Cbnz(x11, &loop);
+        }
+      }
+    }
+
+    if (global()) {
+      Register success_counter = w0;
+      Register output_size = x10;
+      // Restart matching if the regular expression is flagged as global.
+
+      // Increment success counter.
+      __ Ldr(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
+      __ Add(success_counter, success_counter, 1);
+      __ Str(success_counter, MemOperand(frame_pointer(), kSuccessCounter));
+
+      // Capture results have been stored, so the number of remaining global
+      // output registers is reduced by the number of stored captures.
+      __ Ldr(output_size, MemOperand(frame_pointer(), kOutputSize));
+      __ Sub(output_size, output_size, num_saved_registers_);
+      // Check whether we have enough room for another set of capture results.
+      __ Cmp(output_size, num_saved_registers_);
+      __ B(lt, &return_w0);
+
+      // The output pointer is already set to the next field in the output
+      // array.
+      // Update output size on the frame before we restart matching.
+      __ Str(output_size, MemOperand(frame_pointer(), kOutputSize));
+
+      if (global_with_zero_length_check()) {
+        // Special case for zero-length matches.
+        __ Cmp(current_input_offset(), first_capture_start);
+        // Not a zero-length match, restart.
+        __ B(ne, &load_char_start_regexp);
+        // Offset from the end is zero if we already reached the end.
+        __ Cbz(current_input_offset(), &return_w0);
+        // Advance current position after a zero-length match.
+        __ Add(current_input_offset(),
+               current_input_offset(),
+               Operand((mode_ == UC16) ? 2 : 1));
+      }
+
+      __ B(&load_char_start_regexp);
+    } else {
+      __ Mov(w0, SUCCESS);
+    }
+  }
+
+  if (exit_label_.is_linked()) {
+    // Exit and return w0
+    __ Bind(&exit_label_);
+    if (global()) {
+      __ Ldr(w0, MemOperand(frame_pointer(), kSuccessCounter));
+    }
+  }
+
+  __ Bind(&return_w0);
+
+  // Set stack pointer back to first register to retain
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Mov(csp, fp);
+  __ AssertStackConsistency();
+
+  // Restore registers.
+  __ PopCPURegList(registers_to_retain);
+
+  __ Ret();
+
+  Label exit_with_exception;
+  // Registers x0 to x7 are used to store the first captures, they need to be
+  // retained over calls to C++ code.
+  CPURegList cached_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 7);
+  DCHECK((cached_registers.Count() * 2) == kNumCachedRegisters);
+
+  if (check_preempt_label_.is_linked()) {
+    __ Bind(&check_preempt_label_);
+    SaveLinkRegister();
+    // The cached registers need to be retained.
+    __ PushCPURegList(cached_registers);
+    CallCheckStackGuardState(x10);
+    // Returning from the regexp code restores the stack (csp <- fp)
+    // so we don't need to drop the link register from it before exiting.
+    __ Cbnz(w0, &return_w0);
+    // Reset the cached registers.
+    __ PopCPURegList(cached_registers);
+    RestoreLinkRegister();
+    __ Ret();
+  }
+
+  if (stack_overflow_label_.is_linked()) {
+    __ Bind(&stack_overflow_label_);
+    SaveLinkRegister();
+    // The cached registers need to be retained.
+    __ PushCPURegList(cached_registers);
+    // Call GrowStack(backtrack_stackpointer(), &stack_base)
+    __ Mov(x2, ExternalReference::isolate_address(isolate()));
+    __ Add(x1, frame_pointer(), kStackBase);
+    __ Mov(x0, backtrack_stackpointer());
+    ExternalReference grow_stack =
+        ExternalReference::re_grow_stack(isolate());
+    __ CallCFunction(grow_stack, 3);
+    // If return NULL, we have failed to grow the stack, and
+    // must exit with a stack-overflow exception.
+    // Returning from the regexp code restores the stack (csp <- fp)
+    // so we don't need to drop the link register from it before exiting.
+    __ Cbz(w0, &exit_with_exception);
+    // Otherwise use return value as new stack pointer.
+    __ Mov(backtrack_stackpointer(), x0);
+    // Reset the cached registers.
+    __ PopCPURegList(cached_registers);
+    RestoreLinkRegister();
+    __ Ret();
+  }
+
+  if (exit_with_exception.is_linked()) {
+    __ Bind(&exit_with_exception);
+    __ Mov(w0, EXCEPTION);
+    __ B(&return_w0);
+  }
+
+  CodeDesc code_desc;
+  masm_->GetCode(&code_desc);
+  Handle<Code> code = isolate()->factory()->NewCode(
+      code_desc, Code::ComputeFlags(Code::REGEXP), masm_->CodeObject());
+  PROFILE(masm_->isolate(), RegExpCodeCreateEvent(*code, *source));
+  return Handle<HeapObject>::cast(code);
+}
+
+
+void RegExpMacroAssemblerARM64::GoTo(Label* to) {
+  BranchOrBacktrack(al, to);
+}
+
+void RegExpMacroAssemblerARM64::IfRegisterGE(int reg, int comparand,
+                                             Label* if_ge) {
+  Register to_compare = GetRegister(reg, w10);
+  CompareAndBranchOrBacktrack(to_compare, comparand, ge, if_ge);
+}
+
+
+void RegExpMacroAssemblerARM64::IfRegisterLT(int reg, int comparand,
+                                             Label* if_lt) {
+  Register to_compare = GetRegister(reg, w10);
+  CompareAndBranchOrBacktrack(to_compare, comparand, lt, if_lt);
+}
+
+
+void RegExpMacroAssemblerARM64::IfRegisterEqPos(int reg, Label* if_eq) {
+  Register to_compare = GetRegister(reg, w10);
+  __ Cmp(to_compare, current_input_offset());
+  BranchOrBacktrack(eq, if_eq);
+}
+
+RegExpMacroAssembler::IrregexpImplementation
+    RegExpMacroAssemblerARM64::Implementation() {
+  return kARM64Implementation;
+}
+
+
+void RegExpMacroAssemblerARM64::LoadCurrentCharacter(int cp_offset,
+                                                     Label* on_end_of_input,
+                                                     bool check_bounds,
+                                                     int characters) {
+  // TODO(pielan): Make sure long strings are caught before this, and not
+  // just asserted in debug mode.
+  DCHECK(cp_offset >= -1);      // ^ and \b can look behind one character.
+  // Be sane! (And ensure that an int32_t can be used to index the string)
+  DCHECK(cp_offset < (1<<30));
+  if (check_bounds) {
+    CheckPosition(cp_offset + characters - 1, on_end_of_input);
+  }
+  LoadCurrentCharacterUnchecked(cp_offset, characters);
+}
+
+
+void RegExpMacroAssemblerARM64::PopCurrentPosition() {
+  Pop(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM64::PopRegister(int register_index) {
+  Pop(w10);
+  StoreRegister(register_index, w10);
+}
+
+
+void RegExpMacroAssemblerARM64::PushBacktrack(Label* label) {
+  if (label->is_bound()) {
+    int target = label->pos();
+    __ Mov(w10, target + Code::kHeaderSize - kHeapObjectTag);
+  } else {
+    __ Adr(x10, label, MacroAssembler::kAdrFar);
+    __ Sub(x10, x10, code_pointer());
+    if (masm_->emit_debug_code()) {
+      __ Cmp(x10, kWRegMask);
+      // The code offset has to fit in a W register.
+      __ Check(ls, kOffsetOutOfRange);
+    }
+  }
+  Push(w10);
+  CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM64::PushCurrentPosition() {
+  Push(current_input_offset());
+}
+
+
+void RegExpMacroAssemblerARM64::PushRegister(int register_index,
+                                             StackCheckFlag check_stack_limit) {
+  Register to_push = GetRegister(register_index, w10);
+  Push(to_push);
+  if (check_stack_limit) CheckStackLimit();
+}
+
+
+void RegExpMacroAssemblerARM64::ReadCurrentPositionFromRegister(int reg) {
+  Register cached_register;
+  RegisterState register_state = GetRegisterState(reg);
+  switch (register_state) {
+    case STACKED:
+      __ Ldr(current_input_offset(), register_location(reg));
+      break;
+    case CACHED_LSW:
+      cached_register = GetCachedRegister(reg);
+      __ Mov(current_input_offset(), cached_register.W());
+      break;
+    case CACHED_MSW:
+      cached_register = GetCachedRegister(reg);
+      __ Lsr(current_input_offset().X(), cached_register, kWRegSizeInBits);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::ReadStackPointerFromRegister(int reg) {
+  Register read_from = GetRegister(reg, w10);
+  __ Ldr(x11, MemOperand(frame_pointer(), kStackBase));
+  __ Add(backtrack_stackpointer(), x11, Operand(read_from, SXTW));
+}
+
+
+void RegExpMacroAssemblerARM64::SetCurrentPositionFromEnd(int by) {
+  Label after_position;
+  __ Cmp(current_input_offset(), -by * char_size());
+  __ B(ge, &after_position);
+  __ Mov(current_input_offset(), -by * char_size());
+  // On RegExp code entry (where this operation is used), the character before
+  // the current position is expected to be already loaded.
+  // We have advanced the position, so it's safe to read backwards.
+  LoadCurrentCharacterUnchecked(-1, 1);
+  __ Bind(&after_position);
+}
+
+
+void RegExpMacroAssemblerARM64::SetRegister(int register_index, int to) {
+  DCHECK(register_index >= num_saved_registers_);  // Reserved for positions!
+  Register set_to = wzr;
+  if (to != 0) {
+    set_to = w10;
+    __ Mov(set_to, to);
+  }
+  StoreRegister(register_index, set_to);
+}
+
+
+bool RegExpMacroAssemblerARM64::Succeed() {
+  __ B(&success_label_);
+  return global();
+}
+
+
+void RegExpMacroAssemblerARM64::WriteCurrentPositionToRegister(int reg,
+                                                               int cp_offset) {
+  Register position = current_input_offset();
+  if (cp_offset != 0) {
+    position = w10;
+    __ Add(position, current_input_offset(), cp_offset * char_size());
+  }
+  StoreRegister(reg, position);
+}
+
+
+void RegExpMacroAssemblerARM64::ClearRegisters(int reg_from, int reg_to) {
+  DCHECK(reg_from <= reg_to);
+  int num_registers = reg_to - reg_from + 1;
+
+  // If the first capture register is cached in a hardware register but not
+  // aligned on a 64-bit one, we need to clear the first one specifically.
+  if ((reg_from < kNumCachedRegisters) && ((reg_from % 2) != 0)) {
+    StoreRegister(reg_from, non_position_value());
+    num_registers--;
+    reg_from++;
+  }
+
+  // Clear cached registers in pairs as far as possible.
+  while ((num_registers >= 2) && (reg_from < kNumCachedRegisters)) {
+    DCHECK(GetRegisterState(reg_from) == CACHED_LSW);
+    __ Mov(GetCachedRegister(reg_from), twice_non_position_value());
+    reg_from += 2;
+    num_registers -= 2;
+  }
+
+  if ((num_registers % 2) == 1) {
+    StoreRegister(reg_from, non_position_value());
+    num_registers--;
+    reg_from++;
+  }
+
+  if (num_registers > 0) {
+    // If there are some remaining registers, they are stored on the stack.
+    DCHECK(reg_from >= kNumCachedRegisters);
+
+    // Move down the indexes of the registers on stack to get the correct offset
+    // in memory.
+    reg_from -= kNumCachedRegisters;
+    reg_to -= kNumCachedRegisters;
+    // We should not unroll the loop for less than 2 registers.
+    STATIC_ASSERT(kNumRegistersToUnroll > 2);
+    // We position the base pointer to (reg_from + 1).
+    int base_offset = kFirstRegisterOnStack -
+        kWRegSize - (kWRegSize * reg_from);
+    if (num_registers > kNumRegistersToUnroll) {
+      Register base = x10;
+      __ Add(base, frame_pointer(), base_offset);
+
+      Label loop;
+      __ Mov(x11, num_registers);
+      __ Bind(&loop);
+      __ Str(twice_non_position_value(),
+             MemOperand(base, -kPointerSize, PostIndex));
+      __ Sub(x11, x11, 2);
+      __ Cbnz(x11, &loop);
+    } else {
+      for (int i = reg_from; i <= reg_to; i += 2) {
+        __ Str(twice_non_position_value(),
+               MemOperand(frame_pointer(), base_offset));
+        base_offset -= kWRegSize * 2;
+      }
+    }
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::WriteStackPointerToRegister(int reg) {
+  __ Ldr(x10, MemOperand(frame_pointer(), kStackBase));
+  __ Sub(x10, backtrack_stackpointer(), x10);
+  if (masm_->emit_debug_code()) {
+    __ Cmp(x10, Operand(w10, SXTW));
+    // The stack offset needs to fit in a W register.
+    __ Check(eq, kOffsetOutOfRange);
+  }
+  StoreRegister(reg, w10);
+}
+
+
+// Helper function for reading a value out of a stack frame.
+template <typename T>
+static T& frame_entry(Address re_frame, int frame_offset) {
+  return *reinterpret_cast<T*>(re_frame + frame_offset);
+}
+
+
+int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
+                                                  Code* re_code,
+                                                  Address re_frame,
+                                                  int start_offset,
+                                                  const byte** input_start,
+                                                  const byte** input_end) {
+  Isolate* isolate = frame_entry<Isolate*>(re_frame, kIsolate);
+  StackLimitCheck check(isolate);
+  if (check.JsHasOverflowed()) {
+    isolate->StackOverflow();
+    return EXCEPTION;
+  }
+
+  // If not real stack overflow the stack guard was used to interrupt
+  // execution for another purpose.
+
+  // If this is a direct call from JavaScript retry the RegExp forcing the call
+  // through the runtime system. Currently the direct call cannot handle a GC.
+  if (frame_entry<int>(re_frame, kDirectCall) == 1) {
+    return RETRY;
+  }
+
+  // Prepare for possible GC.
+  HandleScope handles(isolate);
+  Handle<Code> code_handle(re_code);
+
+  Handle<String> subject(frame_entry<String*>(re_frame, kInput));
+
+  // Current string.
+  bool is_one_byte = subject->IsOneByteRepresentationUnderneath();
+
+  DCHECK(re_code->instruction_start() <= *return_address);
+  DCHECK(*return_address <=
+      re_code->instruction_start() + re_code->instruction_size());
+
+  Object* result = isolate->stack_guard()->HandleInterrupts();
+
+  if (*code_handle != re_code) {  // Return address no longer valid
+    int delta = code_handle->address() - re_code->address();
+    // Overwrite the return address on the stack.
+    *return_address += delta;
+  }
+
+  if (result->IsException()) {
+    return EXCEPTION;
+  }
+
+  Handle<String> subject_tmp = subject;
+  int slice_offset = 0;
+
+  // Extract the underlying string and the slice offset.
+  if (StringShape(*subject_tmp).IsCons()) {
+    subject_tmp = Handle<String>(ConsString::cast(*subject_tmp)->first());
+  } else if (StringShape(*subject_tmp).IsSliced()) {
+    SlicedString* slice = SlicedString::cast(*subject_tmp);
+    subject_tmp = Handle<String>(slice->parent());
+    slice_offset = slice->offset();
+  }
+
+  // String might have changed.
+  if (subject_tmp->IsOneByteRepresentation() != is_one_byte) {
+    // If we changed between an Latin1 and an UC16 string, the specialized
+    // code cannot be used, and we need to restart regexp matching from
+    // scratch (including, potentially, compiling a new version of the code).
+    return RETRY;
+  }
+
+  // Otherwise, the content of the string might have moved. It must still
+  // be a sequential or external string with the same content.
+  // Update the start and end pointers in the stack frame to the current
+  // location (whether it has actually moved or not).
+  DCHECK(StringShape(*subject_tmp).IsSequential() ||
+         StringShape(*subject_tmp).IsExternal());
+
+  // The original start address of the characters to match.
+  const byte* start_address = *input_start;
+
+  // Find the current start address of the same character at the current string
+  // position.
+  const byte* new_address = StringCharacterPosition(*subject_tmp,
+      start_offset + slice_offset);
+
+  if (start_address != new_address) {
+    // If there is a difference, update the object pointer and start and end
+    // addresses in the RegExp stack frame to match the new value.
+    const byte* end_address = *input_end;
+    int byte_length = static_cast<int>(end_address - start_address);
+    frame_entry<const String*>(re_frame, kInput) = *subject;
+    *input_start = new_address;
+    *input_end = new_address + byte_length;
+  } else if (frame_entry<const String*>(re_frame, kInput) != *subject) {
+    // Subject string might have been a ConsString that underwent
+    // short-circuiting during GC. That will not change start_address but
+    // will change pointer inside the subject handle.
+    frame_entry<const String*>(re_frame, kInput) = *subject;
+  }
+
+  return 0;
+}
+
+
+void RegExpMacroAssemblerARM64::CheckPosition(int cp_offset,
+                                              Label* on_outside_input) {
+  CompareAndBranchOrBacktrack(current_input_offset(),
+                              -cp_offset * char_size(),
+                              ge,
+                              on_outside_input);
+}
+
+
+bool RegExpMacroAssemblerARM64::CanReadUnaligned() {
+  // TODO(pielan): See whether or not we should disable unaligned accesses.
+  return !slow_safe();
+}
+
+
+// Private methods:
+
+void RegExpMacroAssemblerARM64::CallCheckStackGuardState(Register scratch) {
+  // Allocate space on the stack to store the return address. The
+  // CheckStackGuardState C++ function will override it if the code
+  // moved. Allocate extra space for 2 arguments passed by pointers.
+  // AAPCS64 requires the stack to be 16 byte aligned.
+  int alignment = masm_->ActivationFrameAlignment();
+  DCHECK_EQ(alignment % 16, 0);
+  int align_mask = (alignment / kXRegSize) - 1;
+  int xreg_to_claim = (3 + align_mask) & ~align_mask;
+
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Claim(xreg_to_claim);
+
+  // CheckStackGuardState needs the end and start addresses of the input string.
+  __ Poke(input_end(), 2 * kPointerSize);
+  __ Add(x5, csp, 2 * kPointerSize);
+  __ Poke(input_start(), kPointerSize);
+  __ Add(x4, csp, kPointerSize);
+
+  __ Mov(w3, start_offset());
+  // RegExp code frame pointer.
+  __ Mov(x2, frame_pointer());
+  // Code* of self.
+  __ Mov(x1, Operand(masm_->CodeObject()));
+
+  // We need to pass a pointer to the return address as first argument.
+  // The DirectCEntry stub will place the return address on the stack before
+  // calling so the stack pointer will point to it.
+  __ Mov(x0, csp);
+
+  ExternalReference check_stack_guard_state =
+      ExternalReference::re_check_stack_guard_state(isolate());
+  __ Mov(scratch, check_stack_guard_state);
+  DirectCEntryStub stub(isolate());
+  stub.GenerateCall(masm_, scratch);
+
+  // The input string may have been moved in memory, we need to reload it.
+  __ Peek(input_start(), kPointerSize);
+  __ Peek(input_end(), 2 * kPointerSize);
+
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Drop(xreg_to_claim);
+
+  // Reload the Code pointer.
+  __ Mov(code_pointer(), Operand(masm_->CodeObject()));
+}
+
+void RegExpMacroAssemblerARM64::BranchOrBacktrack(Condition condition,
+                                                  Label* to) {
+  if (condition == al) {  // Unconditional.
+    if (to == NULL) {
+      Backtrack();
+      return;
+    }
+    __ B(to);
+    return;
+  }
+  if (to == NULL) {
+    to = &backtrack_label_;
+  }
+  __ B(condition, to);
+}
+
+void RegExpMacroAssemblerARM64::CompareAndBranchOrBacktrack(Register reg,
+                                                            int immediate,
+                                                            Condition condition,
+                                                            Label* to) {
+  if ((immediate == 0) && ((condition == eq) || (condition == ne))) {
+    if (to == NULL) {
+      to = &backtrack_label_;
+    }
+    if (condition == eq) {
+      __ Cbz(reg, to);
+    } else {
+      __ Cbnz(reg, to);
+    }
+  } else {
+    __ Cmp(reg, immediate);
+    BranchOrBacktrack(condition, to);
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::CheckPreemption() {
+  // Check for preemption.
+  ExternalReference stack_limit =
+      ExternalReference::address_of_stack_limit(isolate());
+  __ Mov(x10, stack_limit);
+  __ Ldr(x10, MemOperand(x10));
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Cmp(csp, x10);
+  CallIf(&check_preempt_label_, ls);
+}
+
+
+void RegExpMacroAssemblerARM64::CheckStackLimit() {
+  ExternalReference stack_limit =
+      ExternalReference::address_of_regexp_stack_limit(isolate());
+  __ Mov(x10, stack_limit);
+  __ Ldr(x10, MemOperand(x10));
+  __ Cmp(backtrack_stackpointer(), x10);
+  CallIf(&stack_overflow_label_, ls);
+}
+
+
+void RegExpMacroAssemblerARM64::Push(Register source) {
+  DCHECK(source.Is32Bits());
+  DCHECK(!source.is(backtrack_stackpointer()));
+  __ Str(source,
+         MemOperand(backtrack_stackpointer(),
+                    -static_cast<int>(kWRegSize),
+                    PreIndex));
+}
+
+
+void RegExpMacroAssemblerARM64::Pop(Register target) {
+  DCHECK(target.Is32Bits());
+  DCHECK(!target.is(backtrack_stackpointer()));
+  __ Ldr(target,
+         MemOperand(backtrack_stackpointer(), kWRegSize, PostIndex));
+}
+
+
+Register RegExpMacroAssemblerARM64::GetCachedRegister(int register_index) {
+  DCHECK(register_index < kNumCachedRegisters);
+  return Register::Create(register_index / 2, kXRegSizeInBits);
+}
+
+
+Register RegExpMacroAssemblerARM64::GetRegister(int register_index,
+                                                Register maybe_result) {
+  DCHECK(maybe_result.Is32Bits());
+  DCHECK(register_index >= 0);
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
+  Register result;
+  RegisterState register_state = GetRegisterState(register_index);
+  switch (register_state) {
+    case STACKED:
+      __ Ldr(maybe_result, register_location(register_index));
+      result = maybe_result;
+      break;
+    case CACHED_LSW:
+      result = GetCachedRegister(register_index).W();
+      break;
+    case CACHED_MSW:
+      __ Lsr(maybe_result.X(), GetCachedRegister(register_index),
+             kWRegSizeInBits);
+      result = maybe_result;
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+  DCHECK(result.Is32Bits());
+  return result;
+}
+
+
+void RegExpMacroAssemblerARM64::StoreRegister(int register_index,
+                                              Register source) {
+  DCHECK(source.Is32Bits());
+  DCHECK(register_index >= 0);
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
+
+  Register cached_register;
+  RegisterState register_state = GetRegisterState(register_index);
+  switch (register_state) {
+    case STACKED:
+      __ Str(source, register_location(register_index));
+      break;
+    case CACHED_LSW:
+      cached_register = GetCachedRegister(register_index);
+      if (!source.Is(cached_register.W())) {
+        __ Bfi(cached_register, source.X(), 0, kWRegSizeInBits);
+      }
+      break;
+    case CACHED_MSW:
+      cached_register = GetCachedRegister(register_index);
+      __ Bfi(cached_register, source.X(), kWRegSizeInBits, kWRegSizeInBits);
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void RegExpMacroAssemblerARM64::CallIf(Label* to, Condition condition) {
+  Label skip_call;
+  if (condition != al) __ B(&skip_call, NegateCondition(condition));
+  __ Bl(to);
+  __ Bind(&skip_call);
+}
+
+
+void RegExpMacroAssemblerARM64::RestoreLinkRegister() {
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Pop(lr, xzr);
+  __ Add(lr, lr, Operand(masm_->CodeObject()));
+}
+
+
+void RegExpMacroAssemblerARM64::SaveLinkRegister() {
+  DCHECK(csp.Is(__ StackPointer()));
+  __ Sub(lr, lr, Operand(masm_->CodeObject()));
+  __ Push(xzr, lr);
+}
+
+
+MemOperand RegExpMacroAssemblerARM64::register_location(int register_index) {
+  DCHECK(register_index < (1<<30));
+  DCHECK(register_index >= kNumCachedRegisters);
+  if (num_registers_ <= register_index) {
+    num_registers_ = register_index + 1;
+  }
+  register_index -= kNumCachedRegisters;
+  int offset = kFirstRegisterOnStack - register_index * kWRegSize;
+  return MemOperand(frame_pointer(), offset);
+}
+
+MemOperand RegExpMacroAssemblerARM64::capture_location(int register_index,
+                                                     Register scratch) {
+  DCHECK(register_index < (1<<30));
+  DCHECK(register_index < num_saved_registers_);
+  DCHECK(register_index >= kNumCachedRegisters);
+  DCHECK_EQ(register_index % 2, 0);
+  register_index -= kNumCachedRegisters;
+  int offset = kFirstCaptureOnStack - register_index * kWRegSize;
+  // capture_location is used with Stp instructions to load/store 2 registers.
+  // The immediate field in the encoding is limited to 7 bits (signed).
+  if (is_int7(offset)) {
+    return MemOperand(frame_pointer(), offset);
+  } else {
+    __ Add(scratch, frame_pointer(), offset);
+    return MemOperand(scratch);
+  }
+}
+
+void RegExpMacroAssemblerARM64::LoadCurrentCharacterUnchecked(int cp_offset,
+                                                              int characters) {
+  Register offset = current_input_offset();
+
+  // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
+  // and the operating system running on the target allow it.
+  // If unaligned load/stores are not supported then this function must only
+  // be used to load a single character at a time.
+
+  // ARMv8 supports unaligned accesses but V8 or the kernel can decide to
+  // disable it.
+  // TODO(pielan): See whether or not we should disable unaligned accesses.
+  if (!CanReadUnaligned()) {
+    DCHECK(characters == 1);
+  }
+
+  if (cp_offset != 0) {
+    if (masm_->emit_debug_code()) {
+      __ Mov(x10, cp_offset * char_size());
+      __ Add(x10, x10, Operand(current_input_offset(), SXTW));
+      __ Cmp(x10, Operand(w10, SXTW));
+      // The offset needs to fit in a W register.
+      __ Check(eq, kOffsetOutOfRange);
+    } else {
+      __ Add(w10, current_input_offset(), cp_offset * char_size());
+    }
+    offset = w10;
+  }
+
+  if (mode_ == LATIN1) {
+    if (characters == 4) {
+      __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
+    } else if (characters == 2) {
+      __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
+    } else {
+      DCHECK(characters == 1);
+      __ Ldrb(current_character(), MemOperand(input_end(), offset, SXTW));
+    }
+  } else {
+    DCHECK(mode_ == UC16);
+    if (characters == 2) {
+      __ Ldr(current_character(), MemOperand(input_end(), offset, SXTW));
+    } else {
+      DCHECK(characters == 1);
+      __ Ldrh(current_character(), MemOperand(input_end(), offset, SXTW));
+    }
+  }
+}
+
+#endif  // V8_INTERPRETED_REGEXP
+
+}}  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/regexp-macro-assembler-arm64.h b/src/arm64/regexp-macro-assembler-arm64.h
new file mode 100644
index 0000000..632c513
--- /dev/null
+++ b/src/arm64/regexp-macro-assembler-arm64.h
@@ -0,0 +1,293 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_
+#define V8_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_
+
+#include "src/macro-assembler.h"
+
+#include "src/arm64/assembler-arm64.h"
+#include "src/arm64/assembler-arm64-inl.h"
+
+namespace v8 {
+namespace internal {
+
+
+#ifndef V8_INTERPRETED_REGEXP
+class RegExpMacroAssemblerARM64: public NativeRegExpMacroAssembler {
+ public:
+  RegExpMacroAssemblerARM64(Mode mode, int registers_to_save, Zone* zone);
+  virtual ~RegExpMacroAssemblerARM64();
+  virtual int stack_limit_slack();
+  virtual void AdvanceCurrentPosition(int by);
+  virtual void AdvanceRegister(int reg, int by);
+  virtual void Backtrack();
+  virtual void Bind(Label* label);
+  virtual void CheckAtStart(Label* on_at_start);
+  virtual void CheckCharacter(unsigned c, Label* on_equal);
+  virtual void CheckCharacterAfterAnd(unsigned c,
+                                      unsigned mask,
+                                      Label* on_equal);
+  virtual void CheckCharacterGT(uc16 limit, Label* on_greater);
+  virtual void CheckCharacterLT(uc16 limit, Label* on_less);
+  virtual void CheckCharacters(Vector<const uc16> str,
+                               int cp_offset,
+                               Label* on_failure,
+                               bool check_end_of_string);
+  // A "greedy loop" is a loop that is both greedy and with a simple
+  // body. It has a particularly simple implementation.
+  virtual void CheckGreedyLoop(Label* on_tos_equals_current_position);
+  virtual void CheckNotAtStart(Label* on_not_at_start);
+  virtual void CheckNotBackReference(int start_reg, Label* on_no_match);
+  virtual void CheckNotBackReferenceIgnoreCase(int start_reg,
+                                               Label* on_no_match);
+  virtual void CheckNotCharacter(unsigned c, Label* on_not_equal);
+  virtual void CheckNotCharacterAfterAnd(unsigned c,
+                                         unsigned mask,
+                                         Label* on_not_equal);
+  virtual void CheckNotCharacterAfterMinusAnd(uc16 c,
+                                              uc16 minus,
+                                              uc16 mask,
+                                              Label* on_not_equal);
+  virtual void CheckCharacterInRange(uc16 from,
+                                     uc16 to,
+                                     Label* on_in_range);
+  virtual void CheckCharacterNotInRange(uc16 from,
+                                        uc16 to,
+                                        Label* on_not_in_range);
+  virtual void CheckBitInTable(Handle<ByteArray> table, Label* on_bit_set);
+
+  // Checks whether the given offset from the current position is before
+  // the end of the string.
+  virtual void CheckPosition(int cp_offset, Label* on_outside_input);
+  virtual bool CheckSpecialCharacterClass(uc16 type,
+                                          Label* on_no_match);
+  virtual void Fail();
+  virtual Handle<HeapObject> GetCode(Handle<String> source);
+  virtual void GoTo(Label* label);
+  virtual void IfRegisterGE(int reg, int comparand, Label* if_ge);
+  virtual void IfRegisterLT(int reg, int comparand, Label* if_lt);
+  virtual void IfRegisterEqPos(int reg, Label* if_eq);
+  virtual IrregexpImplementation Implementation();
+  virtual void LoadCurrentCharacter(int cp_offset,
+                                    Label* on_end_of_input,
+                                    bool check_bounds = true,
+                                    int characters = 1);
+  virtual void PopCurrentPosition();
+  virtual void PopRegister(int register_index);
+  virtual void PushBacktrack(Label* label);
+  virtual void PushCurrentPosition();
+  virtual void PushRegister(int register_index,
+                            StackCheckFlag check_stack_limit);
+  virtual void ReadCurrentPositionFromRegister(int reg);
+  virtual void ReadStackPointerFromRegister(int reg);
+  virtual void SetCurrentPositionFromEnd(int by);
+  virtual void SetRegister(int register_index, int to);
+  virtual bool Succeed();
+  virtual void WriteCurrentPositionToRegister(int reg, int cp_offset);
+  virtual void ClearRegisters(int reg_from, int reg_to);
+  virtual void WriteStackPointerToRegister(int reg);
+  virtual bool CanReadUnaligned();
+
+  // Called from RegExp if the stack-guard is triggered.
+  // If the code object is relocated, the return address is fixed before
+  // returning.
+  static int CheckStackGuardState(Address* return_address,
+                                  Code* re_code,
+                                  Address re_frame,
+                                  int start_offset,
+                                  const byte** input_start,
+                                  const byte** input_end);
+
+ private:
+  // Above the frame pointer - Stored registers and stack passed parameters.
+  // Callee-saved registers x19-x29, where x29 is the old frame pointer.
+  static const int kCalleeSavedRegisters = 0;
+  // Return address.
+  // It is placed above the 11 callee-saved registers.
+  static const int kReturnAddress = kCalleeSavedRegisters + 11 * kPointerSize;
+  static const int kSecondaryReturnAddress = kReturnAddress + kPointerSize;
+  // Stack parameter placed by caller.
+  static const int kIsolate = kSecondaryReturnAddress + kPointerSize;
+
+  // Below the frame pointer.
+  // Register parameters stored by setup code.
+  static const int kDirectCall = kCalleeSavedRegisters - kPointerSize;
+  static const int kStackBase = kDirectCall - kPointerSize;
+  static const int kOutputSize = kStackBase - kPointerSize;
+  static const int kInput = kOutputSize - kPointerSize;
+  // When adding local variables remember to push space for them in
+  // the frame in GetCode.
+  static const int kSuccessCounter = kInput - kPointerSize;
+  // First position register address on the stack. Following positions are
+  // below it. A position is a 32 bit value.
+  static const int kFirstRegisterOnStack = kSuccessCounter - kWRegSize;
+  // A capture is a 64 bit value holding two position.
+  static const int kFirstCaptureOnStack = kSuccessCounter - kXRegSize;
+
+  // Initial size of code buffer.
+  static const size_t kRegExpCodeSize = 1024;
+
+  // When initializing registers to a non-position value we can unroll
+  // the loop. Set the limit of registers to unroll.
+  static const int kNumRegistersToUnroll = 16;
+
+  // We are using x0 to x7 as a register cache. Each hardware register must
+  // contain one capture, that is two 32 bit registers. We can cache at most
+  // 16 registers.
+  static const int kNumCachedRegisters = 16;
+
+  // Load a number of characters at the given offset from the
+  // current position, into the current-character register.
+  void LoadCurrentCharacterUnchecked(int cp_offset, int character_count);
+
+  // Check whether preemption has been requested.
+  void CheckPreemption();
+
+  // Check whether we are exceeding the stack limit on the backtrack stack.
+  void CheckStackLimit();
+
+  // Generate a call to CheckStackGuardState.
+  void CallCheckStackGuardState(Register scratch);
+
+  // Location of a 32 bit position register.
+  MemOperand register_location(int register_index);
+
+  // Location of a 64 bit capture, combining two position registers.
+  MemOperand capture_location(int register_index, Register scratch);
+
+  // Register holding the current input position as negative offset from
+  // the end of the string.
+  Register current_input_offset() { return w21; }
+
+  // The register containing the current character after LoadCurrentCharacter.
+  Register current_character() { return w22; }
+
+  // Register holding address of the end of the input string.
+  Register input_end() { return x25; }
+
+  // Register holding address of the start of the input string.
+  Register input_start() { return x26; }
+
+  // Register holding the offset from the start of the string where we should
+  // start matching.
+  Register start_offset() { return w27; }
+
+  // Pointer to the output array's first element.
+  Register output_array() { return x28; }
+
+  // Register holding the frame address. Local variables, parameters and
+  // regexp registers are addressed relative to this.
+  Register frame_pointer() { return fp; }
+
+  // The register containing the backtrack stack top. Provides a meaningful
+  // name to the register.
+  Register backtrack_stackpointer() { return x23; }
+
+  // Register holding pointer to the current code object.
+  Register code_pointer() { return x20; }
+
+  // Register holding the value used for clearing capture registers.
+  Register non_position_value() { return w24; }
+  // The top 32 bit of this register is used to store this value
+  // twice. This is used for clearing more than one register at a time.
+  Register twice_non_position_value() { return x24; }
+
+  // Byte size of chars in the string to match (decided by the Mode argument)
+  int char_size() { return static_cast<int>(mode_); }
+
+  // Equivalent to a conditional branch to the label, unless the label
+  // is NULL, in which case it is a conditional Backtrack.
+  void BranchOrBacktrack(Condition condition, Label* to);
+
+  // Compares reg against immmediate before calling BranchOrBacktrack.
+  // It makes use of the Cbz and Cbnz instructions.
+  void CompareAndBranchOrBacktrack(Register reg,
+                                   int immediate,
+                                   Condition condition,
+                                   Label* to);
+
+  inline void CallIf(Label* to, Condition condition);
+
+  // Save and restore the link register on the stack in a way that
+  // is GC-safe.
+  inline void SaveLinkRegister();
+  inline void RestoreLinkRegister();
+
+  // Pushes the value of a register on the backtrack stack. Decrements the
+  // stack pointer by a word size and stores the register's value there.
+  inline void Push(Register source);
+
+  // Pops a value from the backtrack stack. Reads the word at the stack pointer
+  // and increments it by a word size.
+  inline void Pop(Register target);
+
+  // This state indicates where the register actually is.
+  enum RegisterState {
+    STACKED,     // Resides in memory.
+    CACHED_LSW,  // Least Significant Word of a 64 bit hardware register.
+    CACHED_MSW   // Most Significant Word of a 64 bit hardware register.
+  };
+
+  RegisterState GetRegisterState(int register_index) {
+    DCHECK(register_index >= 0);
+    if (register_index >= kNumCachedRegisters) {
+      return STACKED;
+    } else {
+      if ((register_index % 2) == 0) {
+        return CACHED_LSW;
+      } else {
+        return CACHED_MSW;
+      }
+    }
+  }
+
+  // Store helper that takes the state of the register into account.
+  inline void StoreRegister(int register_index, Register source);
+
+  // Returns a hardware W register that holds the value of the capture
+  // register.
+  //
+  // This function will try to use an existing cache register (w0-w7) for the
+  // result. Otherwise, it will load the value into maybe_result.
+  //
+  // If the returned register is anything other than maybe_result, calling code
+  // must not write to it.
+  inline Register GetRegister(int register_index, Register maybe_result);
+
+  // Returns the harware register (x0-x7) holding the value of the capture
+  // register.
+  // This assumes that the state of the register is not STACKED.
+  inline Register GetCachedRegister(int register_index);
+
+  Isolate* isolate() const { return masm_->isolate(); }
+
+  MacroAssembler* masm_;
+
+  // Which mode to generate code for (LATIN1 or UC16).
+  Mode mode_;
+
+  // One greater than maximal register index actually used.
+  int num_registers_;
+
+  // Number of registers to output at the end (the saved registers
+  // are always 0..num_saved_registers_-1)
+  int num_saved_registers_;
+
+  // Labels used internally.
+  Label entry_label_;
+  Label start_label_;
+  Label success_label_;
+  Label backtrack_label_;
+  Label exit_label_;
+  Label check_preempt_label_;
+  Label stack_overflow_label_;
+};
+
+#endif  // V8_INTERPRETED_REGEXP
+
+
+}}  // namespace v8::internal
+
+#endif  // V8_ARM64_REGEXP_MACRO_ASSEMBLER_ARM64_H_
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
new file mode 100644
index 0000000..129252b
--- /dev/null
+++ b/src/arm64/simulator-arm64.cc
@@ -0,0 +1,3829 @@
+// Copyright 2013 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 <stdlib.h>
+#include <cmath>
+#include <cstdarg>
+#include "src/v8.h"
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/decoder-arm64-inl.h"
+#include "src/arm64/simulator-arm64.h"
+#include "src/assembler.h"
+#include "src/disasm.h"
+#include "src/macro-assembler.h"
+#include "src/ostreams.h"
+
+namespace v8 {
+namespace internal {
+
+#if defined(USE_SIMULATOR)
+
+
+// This macro provides a platform independent use of sscanf. The reason for
+// SScanF not being implemented in a platform independent way through
+// ::v8::internal::OS in the same way as SNPrintF is that the
+// Windows C Run-Time Library does not provide vsscanf.
+#define SScanF sscanf  // NOLINT
+
+
+// Helpers for colors.
+#define COLOUR(colour_code)       "\033[0;" colour_code "m"
+#define COLOUR_BOLD(colour_code)  "\033[1;" colour_code "m"
+#define NORMAL  ""
+#define GREY    "30"
+#define RED     "31"
+#define GREEN   "32"
+#define YELLOW  "33"
+#define BLUE    "34"
+#define MAGENTA "35"
+#define CYAN    "36"
+#define WHITE   "37"
+typedef char const * const TEXT_COLOUR;
+TEXT_COLOUR clr_normal         = FLAG_log_colour ? COLOUR(NORMAL)       : "";
+TEXT_COLOUR clr_flag_name      = FLAG_log_colour ? COLOUR_BOLD(WHITE)   : "";
+TEXT_COLOUR clr_flag_value     = FLAG_log_colour ? COLOUR(NORMAL)       : "";
+TEXT_COLOUR clr_reg_name       = FLAG_log_colour ? COLOUR_BOLD(CYAN)    : "";
+TEXT_COLOUR clr_reg_value      = FLAG_log_colour ? COLOUR(CYAN)         : "";
+TEXT_COLOUR clr_fpreg_name     = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : "";
+TEXT_COLOUR clr_fpreg_value    = FLAG_log_colour ? COLOUR(MAGENTA)      : "";
+TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE)    : "";
+TEXT_COLOUR clr_debug_number   = FLAG_log_colour ? COLOUR_BOLD(YELLOW)  : "";
+TEXT_COLOUR clr_debug_message  = FLAG_log_colour ? COLOUR(YELLOW)       : "";
+TEXT_COLOUR clr_printf         = FLAG_log_colour ? COLOUR(GREEN)        : "";
+
+
+// This is basically the same as PrintF, with a guard for FLAG_trace_sim.
+void Simulator::TraceSim(const char* format, ...) {
+  if (FLAG_trace_sim) {
+    va_list arguments;
+    va_start(arguments, format);
+    base::OS::VFPrint(stream_, format, arguments);
+    va_end(arguments);
+  }
+}
+
+
+const Instruction* Simulator::kEndOfSimAddress = NULL;
+
+
+void SimSystemRegister::SetBits(int msb, int lsb, uint32_t bits) {
+  int width = msb - lsb + 1;
+  DCHECK(is_uintn(bits, width) || is_intn(bits, width));
+
+  bits <<= lsb;
+  uint32_t mask = ((1 << width) - 1) << lsb;
+  DCHECK((mask & write_ignore_mask_) == 0);
+
+  value_ = (value_ & ~mask) | (bits & mask);
+}
+
+
+SimSystemRegister SimSystemRegister::DefaultValueFor(SystemRegister id) {
+  switch (id) {
+    case NZCV:
+      return SimSystemRegister(0x00000000, NZCVWriteIgnoreMask);
+    case FPCR:
+      return SimSystemRegister(0x00000000, FPCRWriteIgnoreMask);
+    default:
+      UNREACHABLE();
+      return SimSystemRegister();
+  }
+}
+
+
+void Simulator::Initialize(Isolate* isolate) {
+  if (isolate->simulator_initialized()) return;
+  isolate->set_simulator_initialized(true);
+  ExternalReference::set_redirector(isolate, &RedirectExternalReference);
+}
+
+
+// Get the active Simulator for the current thread.
+Simulator* Simulator::current(Isolate* isolate) {
+  Isolate::PerIsolateThreadData* isolate_data =
+      isolate->FindOrAllocatePerThreadDataForThisThread();
+  DCHECK(isolate_data != NULL);
+
+  Simulator* sim = isolate_data->simulator();
+  if (sim == NULL) {
+    if (FLAG_trace_sim || FLAG_log_instruction_stats || FLAG_debug_sim) {
+      sim = new Simulator(new Decoder<DispatchingDecoderVisitor>(), isolate);
+    } else {
+      sim = new Decoder<Simulator>();
+      sim->isolate_ = isolate;
+    }
+    isolate_data->set_simulator(sim);
+  }
+  return sim;
+}
+
+
+void Simulator::CallVoid(byte* entry, CallArgument* args) {
+  int index_x = 0;
+  int index_d = 0;
+
+  std::vector<int64_t> stack_args(0);
+  for (int i = 0; !args[i].IsEnd(); i++) {
+    CallArgument arg = args[i];
+    if (arg.IsX() && (index_x < 8)) {
+      set_xreg(index_x++, arg.bits());
+    } else if (arg.IsD() && (index_d < 8)) {
+      set_dreg_bits(index_d++, arg.bits());
+    } else {
+      DCHECK(arg.IsD() || arg.IsX());
+      stack_args.push_back(arg.bits());
+    }
+  }
+
+  // Process stack arguments, and make sure the stack is suitably aligned.
+  uintptr_t original_stack = sp();
+  uintptr_t entry_stack = original_stack -
+                          stack_args.size() * sizeof(stack_args[0]);
+  if (base::OS::ActivationFrameAlignment() != 0) {
+    entry_stack &= -base::OS::ActivationFrameAlignment();
+  }
+  char * stack = reinterpret_cast<char*>(entry_stack);
+  std::vector<int64_t>::const_iterator it;
+  for (it = stack_args.begin(); it != stack_args.end(); it++) {
+    memcpy(stack, &(*it), sizeof(*it));
+    stack += sizeof(*it);
+  }
+
+  DCHECK(reinterpret_cast<uintptr_t>(stack) <= original_stack);
+  set_sp(entry_stack);
+
+  // Call the generated code.
+  set_pc(entry);
+  set_lr(kEndOfSimAddress);
+  CheckPCSComplianceAndRun();
+
+  set_sp(original_stack);
+}
+
+
+int64_t Simulator::CallInt64(byte* entry, CallArgument* args) {
+  CallVoid(entry, args);
+  return xreg(0);
+}
+
+
+double Simulator::CallDouble(byte* entry, CallArgument* args) {
+  CallVoid(entry, args);
+  return dreg(0);
+}
+
+
+int64_t Simulator::CallJS(byte* entry,
+                          byte* function_entry,
+                          JSFunction* func,
+                          Object* revc,
+                          int64_t argc,
+                          Object*** argv) {
+  CallArgument args[] = {
+    CallArgument(function_entry),
+    CallArgument(func),
+    CallArgument(revc),
+    CallArgument(argc),
+    CallArgument(argv),
+    CallArgument::End()
+  };
+  return CallInt64(entry, args);
+}
+
+int64_t Simulator::CallRegExp(byte* entry,
+                              String* input,
+                              int64_t start_offset,
+                              const byte* input_start,
+                              const byte* input_end,
+                              int* output,
+                              int64_t output_size,
+                              Address stack_base,
+                              int64_t direct_call,
+                              void* return_address,
+                              Isolate* isolate) {
+  CallArgument args[] = {
+    CallArgument(input),
+    CallArgument(start_offset),
+    CallArgument(input_start),
+    CallArgument(input_end),
+    CallArgument(output),
+    CallArgument(output_size),
+    CallArgument(stack_base),
+    CallArgument(direct_call),
+    CallArgument(return_address),
+    CallArgument(isolate),
+    CallArgument::End()
+  };
+  return CallInt64(entry, args);
+}
+
+
+void Simulator::CheckPCSComplianceAndRun() {
+#ifdef DEBUG
+  CHECK_EQ(kNumberOfCalleeSavedRegisters, kCalleeSaved.Count());
+  CHECK_EQ(kNumberOfCalleeSavedFPRegisters, kCalleeSavedFP.Count());
+
+  int64_t saved_registers[kNumberOfCalleeSavedRegisters];
+  uint64_t saved_fpregisters[kNumberOfCalleeSavedFPRegisters];
+
+  CPURegList register_list = kCalleeSaved;
+  CPURegList fpregister_list = kCalleeSavedFP;
+
+  for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
+    // x31 is not a caller saved register, so no need to specify if we want
+    // the stack or zero.
+    saved_registers[i] = xreg(register_list.PopLowestIndex().code());
+  }
+  for (int i = 0; i < kNumberOfCalleeSavedFPRegisters; i++) {
+    saved_fpregisters[i] =
+        dreg_bits(fpregister_list.PopLowestIndex().code());
+  }
+  int64_t original_stack = sp();
+#endif
+  // Start the simulation!
+  Run();
+#ifdef DEBUG
+  CHECK_EQ(original_stack, sp());
+  // Check that callee-saved registers have been preserved.
+  register_list = kCalleeSaved;
+  fpregister_list = kCalleeSavedFP;
+  for (int i = 0; i < kNumberOfCalleeSavedRegisters; i++) {
+    CHECK_EQ(saved_registers[i], xreg(register_list.PopLowestIndex().code()));
+  }
+  for (int i = 0; i < kNumberOfCalleeSavedFPRegisters; i++) {
+    DCHECK(saved_fpregisters[i] ==
+           dreg_bits(fpregister_list.PopLowestIndex().code()));
+  }
+
+  // Corrupt caller saved register minus the return regiters.
+
+  // In theory x0 to x7 can be used for return values, but V8 only uses x0, x1
+  // for now .
+  register_list = kCallerSaved;
+  register_list.Remove(x0);
+  register_list.Remove(x1);
+
+  // In theory d0 to d7 can be used for return values, but V8 only uses d0
+  // for now .
+  fpregister_list = kCallerSavedFP;
+  fpregister_list.Remove(d0);
+
+  CorruptRegisters(&register_list, kCallerSavedRegisterCorruptionValue);
+  CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue);
+#endif
+}
+
+
+#ifdef DEBUG
+// The least significant byte of the curruption value holds the corresponding
+// register's code.
+void Simulator::CorruptRegisters(CPURegList* list, uint64_t value) {
+  if (list->type() == CPURegister::kRegister) {
+    while (!list->IsEmpty()) {
+      unsigned code = list->PopLowestIndex().code();
+      set_xreg(code, value | code);
+    }
+  } else {
+    DCHECK(list->type() == CPURegister::kFPRegister);
+    while (!list->IsEmpty()) {
+      unsigned code = list->PopLowestIndex().code();
+      set_dreg_bits(code, value | code);
+    }
+  }
+}
+
+
+void Simulator::CorruptAllCallerSavedCPURegisters() {
+  // Corrupt alters its parameter so copy them first.
+  CPURegList register_list = kCallerSaved;
+  CPURegList fpregister_list = kCallerSavedFP;
+
+  CorruptRegisters(&register_list, kCallerSavedRegisterCorruptionValue);
+  CorruptRegisters(&fpregister_list, kCallerSavedFPRegisterCorruptionValue);
+}
+#endif
+
+
+// Extending the stack by 2 * 64 bits is required for stack alignment purposes.
+uintptr_t Simulator::PushAddress(uintptr_t address) {
+  DCHECK(sizeof(uintptr_t) < 2 * kXRegSize);
+  intptr_t new_sp = sp() - 2 * kXRegSize;
+  uintptr_t* alignment_slot =
+    reinterpret_cast<uintptr_t*>(new_sp + kXRegSize);
+  memcpy(alignment_slot, &kSlotsZapValue, kPointerSize);
+  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
+  memcpy(stack_slot, &address, kPointerSize);
+  set_sp(new_sp);
+  return new_sp;
+}
+
+
+uintptr_t Simulator::PopAddress() {
+  intptr_t current_sp = sp();
+  uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(current_sp);
+  uintptr_t address = *stack_slot;
+  DCHECK(sizeof(uintptr_t) < 2 * kXRegSize);
+  set_sp(current_sp + 2 * kXRegSize);
+  return address;
+}
+
+
+// Returns the limit of the stack area to enable checking for stack overflows.
+uintptr_t Simulator::StackLimit() const {
+  // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
+  // pushing values.
+  return stack_limit_ + 1024;
+}
+
+
+Simulator::Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
+                     Isolate* isolate, FILE* stream)
+    : decoder_(decoder),
+      last_debugger_input_(NULL),
+      log_parameters_(NO_PARAM),
+      isolate_(isolate) {
+  // Setup the decoder.
+  decoder_->AppendVisitor(this);
+
+  Init(stream);
+
+  if (FLAG_trace_sim) {
+    decoder_->InsertVisitorBefore(print_disasm_, this);
+    log_parameters_ = LOG_ALL;
+  }
+
+  if (FLAG_log_instruction_stats) {
+    instrument_ = new Instrument(FLAG_log_instruction_file,
+                                 FLAG_log_instruction_period);
+    decoder_->AppendVisitor(instrument_);
+  }
+}
+
+
+Simulator::Simulator()
+    : decoder_(NULL),
+      last_debugger_input_(NULL),
+      log_parameters_(NO_PARAM),
+      isolate_(NULL) {
+  Init(stdout);
+  CHECK(!FLAG_trace_sim && !FLAG_log_instruction_stats);
+}
+
+
+void Simulator::Init(FILE* stream) {
+  ResetState();
+
+  // Allocate and setup the simulator stack.
+  stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_);
+  stack_ = reinterpret_cast<uintptr_t>(new byte[stack_size_]);
+  stack_limit_ = stack_ + stack_protection_size_;
+  uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
+  // The stack pointer must be 16-byte aligned.
+  set_sp(tos & ~0xfUL);
+
+  stream_ = stream;
+  print_disasm_ = new PrintDisassembler(stream_);
+
+  // The debugger needs to disassemble code without the simulator executing an
+  // instruction, so we create a dedicated decoder.
+  disassembler_decoder_ = new Decoder<DispatchingDecoderVisitor>();
+  disassembler_decoder_->AppendVisitor(print_disasm_);
+}
+
+
+void Simulator::ResetState() {
+  // Reset the system registers.
+  nzcv_ = SimSystemRegister::DefaultValueFor(NZCV);
+  fpcr_ = SimSystemRegister::DefaultValueFor(FPCR);
+
+  // Reset registers to 0.
+  pc_ = NULL;
+  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
+    set_xreg(i, 0xbadbeef);
+  }
+  for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
+    // Set FP registers to a value that is NaN in both 32-bit and 64-bit FP.
+    set_dreg_bits(i, 0x7ff000007f800001UL);
+  }
+  // Returning to address 0 exits the Simulator.
+  set_lr(kEndOfSimAddress);
+
+  // Reset debug helpers.
+  breakpoints_.empty();
+  break_on_next_= false;
+}
+
+
+Simulator::~Simulator() {
+  delete[] reinterpret_cast<byte*>(stack_);
+  if (FLAG_log_instruction_stats) {
+    delete instrument_;
+  }
+  delete disassembler_decoder_;
+  delete print_disasm_;
+  DeleteArray(last_debugger_input_);
+  delete decoder_;
+}
+
+
+void Simulator::Run() {
+  pc_modified_ = false;
+  while (pc_ != kEndOfSimAddress) {
+    ExecuteInstruction();
+  }
+}
+
+
+void Simulator::RunFrom(Instruction* start) {
+  set_pc(start);
+  Run();
+}
+
+
+// When the generated code calls an external reference we need to catch that in
+// the simulator.  The external reference will be a function compiled for the
+// host architecture.  We need to call that function instead of trying to
+// execute it with the simulator.  We do that by redirecting the external
+// reference to a svc (Supervisor Call) instruction that is handled by
+// the simulator.  We write the original destination of the jump just at a known
+// offset from the svc instruction so the simulator knows what to call.
+class Redirection {
+ public:
+  Redirection(void* external_function, ExternalReference::Type type)
+      : external_function_(external_function),
+        type_(type),
+        next_(NULL) {
+    redirect_call_.SetInstructionBits(
+        HLT | Assembler::ImmException(kImmExceptionIsRedirectedCall));
+    Isolate* isolate = Isolate::Current();
+    next_ = isolate->simulator_redirection();
+    // TODO(all): Simulator flush I cache
+    isolate->set_simulator_redirection(this);
+  }
+
+  void* address_of_redirect_call() {
+    return reinterpret_cast<void*>(&redirect_call_);
+  }
+
+  template <typename T>
+  T external_function() { return reinterpret_cast<T>(external_function_); }
+
+  ExternalReference::Type type() { return type_; }
+
+  static Redirection* Get(void* external_function,
+                          ExternalReference::Type type) {
+    Isolate* isolate = Isolate::Current();
+    Redirection* current = isolate->simulator_redirection();
+    for (; current != NULL; current = current->next_) {
+      if (current->external_function_ == external_function) {
+        DCHECK_EQ(current->type(), type);
+        return current;
+      }
+    }
+    return new Redirection(external_function, type);
+  }
+
+  static Redirection* FromHltInstruction(Instruction* redirect_call) {
+    char* addr_of_hlt = reinterpret_cast<char*>(redirect_call);
+    char* addr_of_redirection =
+        addr_of_hlt - OFFSET_OF(Redirection, redirect_call_);
+    return reinterpret_cast<Redirection*>(addr_of_redirection);
+  }
+
+  static void* ReverseRedirection(int64_t reg) {
+    Redirection* redirection =
+        FromHltInstruction(reinterpret_cast<Instruction*>(reg));
+    return redirection->external_function<void*>();
+  }
+
+ private:
+  void* external_function_;
+  Instruction redirect_call_;
+  ExternalReference::Type type_;
+  Redirection* next_;
+};
+
+
+// Calls into the V8 runtime are based on this very simple interface.
+// Note: To be able to return two values from some calls the code in runtime.cc
+// uses the ObjectPair structure.
+// The simulator assumes all runtime calls return two 64-bits values. If they
+// don't, register x1 is clobbered. This is fine because x1 is caller-saved.
+struct ObjectPair {
+  int64_t res0;
+  int64_t res1;
+};
+
+
+typedef ObjectPair (*SimulatorRuntimeCall)(int64_t arg0,
+                                           int64_t arg1,
+                                           int64_t arg2,
+                                           int64_t arg3,
+                                           int64_t arg4,
+                                           int64_t arg5,
+                                           int64_t arg6,
+                                           int64_t arg7);
+
+typedef int64_t (*SimulatorRuntimeCompareCall)(double arg1, double arg2);
+typedef double (*SimulatorRuntimeFPFPCall)(double arg1, double arg2);
+typedef double (*SimulatorRuntimeFPCall)(double arg1);
+typedef double (*SimulatorRuntimeFPIntCall)(double arg1, int32_t arg2);
+
+// This signature supports direct call in to API function native callback
+// (refer to InvocationCallback in v8.h).
+typedef void (*SimulatorRuntimeDirectApiCall)(int64_t arg0);
+typedef void (*SimulatorRuntimeProfilingApiCall)(int64_t arg0, void* arg1);
+
+// This signature supports direct call to accessor getter callback.
+typedef void (*SimulatorRuntimeDirectGetterCall)(int64_t arg0, int64_t arg1);
+typedef void (*SimulatorRuntimeProfilingGetterCall)(int64_t arg0, int64_t arg1,
+                                                    void* arg2);
+
+void Simulator::DoRuntimeCall(Instruction* instr) {
+  Redirection* redirection = Redirection::FromHltInstruction(instr);
+
+  // The called C code might itself call simulated code, so any
+  // caller-saved registers (including lr) could still be clobbered by a
+  // redirected call.
+  Instruction* return_address = lr();
+
+  int64_t external = redirection->external_function<int64_t>();
+
+  TraceSim("Call to host function at %p\n",
+           redirection->external_function<void*>());
+
+  // SP must be 16-byte-aligned at the call interface.
+  bool stack_alignment_exception = ((sp() & 0xf) != 0);
+  if (stack_alignment_exception) {
+    TraceSim("  with unaligned stack 0x%016" PRIx64 ".\n", sp());
+    FATAL("ALIGNMENT EXCEPTION");
+  }
+
+  switch (redirection->type()) {
+    default:
+      TraceSim("Type: Unknown.\n");
+      UNREACHABLE();
+      break;
+
+    case ExternalReference::BUILTIN_CALL: {
+      // Object* f(v8::internal::Arguments).
+      TraceSim("Type: BUILTIN_CALL\n");
+      SimulatorRuntimeCall target =
+        reinterpret_cast<SimulatorRuntimeCall>(external);
+
+      // We don't know how many arguments are being passed, but we can
+      // pass 8 without touching the stack. They will be ignored by the
+      // host function if they aren't used.
+      TraceSim("Arguments: "
+               "0x%016" PRIx64 ", 0x%016" PRIx64 ", "
+               "0x%016" PRIx64 ", 0x%016" PRIx64 ", "
+               "0x%016" PRIx64 ", 0x%016" PRIx64 ", "
+               "0x%016" PRIx64 ", 0x%016" PRIx64,
+               xreg(0), xreg(1), xreg(2), xreg(3),
+               xreg(4), xreg(5), xreg(6), xreg(7));
+      ObjectPair result = target(xreg(0), xreg(1), xreg(2), xreg(3),
+                                 xreg(4), xreg(5), xreg(6), xreg(7));
+      TraceSim("Returned: {0x%" PRIx64 ", 0x%" PRIx64 "}\n",
+               result.res0, result.res1);
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      set_xreg(0, result.res0);
+      set_xreg(1, result.res1);
+      break;
+    }
+
+    case ExternalReference::DIRECT_API_CALL: {
+      // void f(v8::FunctionCallbackInfo&)
+      TraceSim("Type: DIRECT_API_CALL\n");
+      SimulatorRuntimeDirectApiCall target =
+        reinterpret_cast<SimulatorRuntimeDirectApiCall>(external);
+      TraceSim("Arguments: 0x%016" PRIx64 "\n", xreg(0));
+      target(xreg(0));
+      TraceSim("No return value.");
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      break;
+    }
+
+    case ExternalReference::BUILTIN_COMPARE_CALL: {
+      // int f(double, double)
+      TraceSim("Type: BUILTIN_COMPARE_CALL\n");
+      SimulatorRuntimeCompareCall target =
+        reinterpret_cast<SimulatorRuntimeCompareCall>(external);
+      TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
+      int64_t result = target(dreg(0), dreg(1));
+      TraceSim("Returned: %" PRId64 "\n", result);
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      set_xreg(0, result);
+      break;
+    }
+
+    case ExternalReference::BUILTIN_FP_CALL: {
+      // double f(double)
+      TraceSim("Type: BUILTIN_FP_CALL\n");
+      SimulatorRuntimeFPCall target =
+        reinterpret_cast<SimulatorRuntimeFPCall>(external);
+      TraceSim("Argument: %f\n", dreg(0));
+      double result = target(dreg(0));
+      TraceSim("Returned: %f\n", result);
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      set_dreg(0, result);
+      break;
+    }
+
+    case ExternalReference::BUILTIN_FP_FP_CALL: {
+      // double f(double, double)
+      TraceSim("Type: BUILTIN_FP_FP_CALL\n");
+      SimulatorRuntimeFPFPCall target =
+        reinterpret_cast<SimulatorRuntimeFPFPCall>(external);
+      TraceSim("Arguments: %f, %f\n", dreg(0), dreg(1));
+      double result = target(dreg(0), dreg(1));
+      TraceSim("Returned: %f\n", result);
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      set_dreg(0, result);
+      break;
+    }
+
+    case ExternalReference::BUILTIN_FP_INT_CALL: {
+      // double f(double, int)
+      TraceSim("Type: BUILTIN_FP_INT_CALL\n");
+      SimulatorRuntimeFPIntCall target =
+        reinterpret_cast<SimulatorRuntimeFPIntCall>(external);
+      TraceSim("Arguments: %f, %d\n", dreg(0), wreg(0));
+      double result = target(dreg(0), wreg(0));
+      TraceSim("Returned: %f\n", result);
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      set_dreg(0, result);
+      break;
+    }
+
+    case ExternalReference::DIRECT_GETTER_CALL: {
+      // void f(Local<String> property, PropertyCallbackInfo& info)
+      TraceSim("Type: DIRECT_GETTER_CALL\n");
+      SimulatorRuntimeDirectGetterCall target =
+        reinterpret_cast<SimulatorRuntimeDirectGetterCall>(external);
+      TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 "\n",
+               xreg(0), xreg(1));
+      target(xreg(0), xreg(1));
+      TraceSim("No return value.");
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      break;
+    }
+
+    case ExternalReference::PROFILING_API_CALL: {
+      // void f(v8::FunctionCallbackInfo&, v8::FunctionCallback)
+      TraceSim("Type: PROFILING_API_CALL\n");
+      SimulatorRuntimeProfilingApiCall target =
+        reinterpret_cast<SimulatorRuntimeProfilingApiCall>(external);
+      void* arg1 = Redirection::ReverseRedirection(xreg(1));
+      TraceSim("Arguments: 0x%016" PRIx64 ", %p\n", xreg(0), arg1);
+      target(xreg(0), arg1);
+      TraceSim("No return value.");
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      break;
+    }
+
+    case ExternalReference::PROFILING_GETTER_CALL: {
+      // void f(Local<String> property, PropertyCallbackInfo& info,
+      //        AccessorNameGetterCallback callback)
+      TraceSim("Type: PROFILING_GETTER_CALL\n");
+      SimulatorRuntimeProfilingGetterCall target =
+        reinterpret_cast<SimulatorRuntimeProfilingGetterCall>(
+            external);
+      void* arg2 = Redirection::ReverseRedirection(xreg(2));
+      TraceSim("Arguments: 0x%016" PRIx64 ", 0x%016" PRIx64 ", %p\n",
+               xreg(0), xreg(1), arg2);
+      target(xreg(0), xreg(1), arg2);
+      TraceSim("No return value.");
+#ifdef DEBUG
+      CorruptAllCallerSavedCPURegisters();
+#endif
+      break;
+    }
+  }
+
+  set_lr(return_address);
+  set_pc(return_address);
+}
+
+
+void* Simulator::RedirectExternalReference(void* external_function,
+                                           ExternalReference::Type type) {
+  Redirection* redirection = Redirection::Get(external_function, type);
+  return redirection->address_of_redirect_call();
+}
+
+
+const char* Simulator::xreg_names[] = {
+"x0",  "x1",  "x2",  "x3",  "x4",   "x5",  "x6",  "x7",
+"x8",  "x9",  "x10", "x11", "x12",  "x13", "x14", "x15",
+"ip0", "ip1", "x18", "x19", "x20",  "x21", "x22", "x23",
+"x24", "x25", "x26", "cp",  "jssp", "fp",  "lr",  "xzr", "csp"};
+
+const char* Simulator::wreg_names[] = {
+"w0",  "w1",  "w2",  "w3",  "w4",    "w5",  "w6",  "w7",
+"w8",  "w9",  "w10", "w11", "w12",   "w13", "w14", "w15",
+"w16", "w17", "w18", "w19", "w20",   "w21", "w22", "w23",
+"w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"};
+
+const char* Simulator::sreg_names[] = {
+"s0",  "s1",  "s2",  "s3",  "s4",  "s5",  "s6",  "s7",
+"s8",  "s9",  "s10", "s11", "s12", "s13", "s14", "s15",
+"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"};
+
+const char* Simulator::dreg_names[] = {
+"d0",  "d1",  "d2",  "d3",  "d4",  "d5",  "d6",  "d7",
+"d8",  "d9",  "d10", "d11", "d12", "d13", "d14", "d15",
+"d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+"d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31"};
+
+const char* Simulator::vreg_names[] = {
+"v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
+"v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
+"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
+"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"};
+
+
+const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
+  STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1));
+  DCHECK(code < kNumberOfRegisters);
+  // The modulo operator has no effect here, but it silences a broken GCC
+  // warning about out-of-bounds array accesses.
+  code %= kNumberOfRegisters;
+
+  // If the code represents the stack pointer, index the name after zr.
+  if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
+    code = kZeroRegCode + 1;
+  }
+  return wreg_names[code];
+}
+
+
+const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
+  STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1));
+  DCHECK(code < kNumberOfRegisters);
+  code %= kNumberOfRegisters;
+
+  // If the code represents the stack pointer, index the name after zr.
+  if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
+    code = kZeroRegCode + 1;
+  }
+  return xreg_names[code];
+}
+
+
+const char* Simulator::SRegNameForCode(unsigned code) {
+  STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters);
+  DCHECK(code < kNumberOfFPRegisters);
+  return sreg_names[code % kNumberOfFPRegisters];
+}
+
+
+const char* Simulator::DRegNameForCode(unsigned code) {
+  STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters);
+  DCHECK(code < kNumberOfFPRegisters);
+  return dreg_names[code % kNumberOfFPRegisters];
+}
+
+
+const char* Simulator::VRegNameForCode(unsigned code) {
+  STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters);
+  DCHECK(code < kNumberOfFPRegisters);
+  return vreg_names[code % kNumberOfFPRegisters];
+}
+
+
+int Simulator::CodeFromName(const char* name) {
+  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
+    if ((strcmp(xreg_names[i], name) == 0) ||
+        (strcmp(wreg_names[i], name) == 0)) {
+      return i;
+    }
+  }
+  for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
+    if ((strcmp(vreg_names[i], name) == 0) ||
+        (strcmp(dreg_names[i], name) == 0) ||
+        (strcmp(sreg_names[i], name) == 0)) {
+      return i;
+    }
+  }
+  if ((strcmp("csp", name) == 0) || (strcmp("wcsp", name) == 0)) {
+    return kSPRegInternalCode;
+  }
+  return -1;
+}
+
+
+// Helpers ---------------------------------------------------------------------
+template <typename T>
+T Simulator::AddWithCarry(bool set_flags,
+                          T src1,
+                          T src2,
+                          T carry_in) {
+  typedef typename make_unsigned<T>::type unsignedT;
+  DCHECK((carry_in == 0) || (carry_in == 1));
+
+  T signed_sum = src1 + src2 + carry_in;
+  T result = signed_sum;
+
+  bool N, Z, C, V;
+
+  // Compute the C flag
+  unsignedT u1 = static_cast<unsignedT>(src1);
+  unsignedT u2 = static_cast<unsignedT>(src2);
+  unsignedT urest = std::numeric_limits<unsignedT>::max() - u1;
+  C = (u2 > urest) || (carry_in && (((u2 + 1) > urest) || (u2 > (urest - 1))));
+
+  // Overflow iff the sign bit is the same for the two inputs and different
+  // for the result.
+  V = ((src1 ^ src2) >= 0) && ((src1 ^ result) < 0);
+
+  N = CalcNFlag(result);
+  Z = CalcZFlag(result);
+
+  if (set_flags) {
+    nzcv().SetN(N);
+    nzcv().SetZ(Z);
+    nzcv().SetC(C);
+    nzcv().SetV(V);
+    LogSystemRegister(NZCV);
+  }
+  return result;
+}
+
+
+template<typename T>
+void Simulator::AddSubWithCarry(Instruction* instr) {
+  T op2 = reg<T>(instr->Rm());
+  T new_val;
+
+  if ((instr->Mask(AddSubOpMask) == SUB) || instr->Mask(AddSubOpMask) == SUBS) {
+    op2 = ~op2;
+  }
+
+  new_val = AddWithCarry<T>(instr->FlagsUpdate(),
+                            reg<T>(instr->Rn()),
+                            op2,
+                            nzcv().C());
+
+  set_reg<T>(instr->Rd(), new_val);
+}
+
+template <typename T>
+T Simulator::ShiftOperand(T value, Shift shift_type, unsigned amount) {
+  typedef typename make_unsigned<T>::type unsignedT;
+
+  if (amount == 0) {
+    return value;
+  }
+
+  switch (shift_type) {
+    case LSL:
+      return value << amount;
+    case LSR:
+      return static_cast<unsignedT>(value) >> amount;
+    case ASR:
+      return value >> amount;
+    case ROR:
+      return (static_cast<unsignedT>(value) >> amount) |
+              ((value & ((1L << amount) - 1L)) <<
+                  (sizeof(unsignedT) * 8 - amount));
+    default:
+      UNIMPLEMENTED();
+      return 0;
+  }
+}
+
+
+template <typename T>
+T Simulator::ExtendValue(T value, Extend extend_type, unsigned left_shift) {
+  const unsigned kSignExtendBShift = (sizeof(T) - 1) * 8;
+  const unsigned kSignExtendHShift = (sizeof(T) - 2) * 8;
+  const unsigned kSignExtendWShift = (sizeof(T) - 4) * 8;
+
+  switch (extend_type) {
+    case UXTB:
+      value &= kByteMask;
+      break;
+    case UXTH:
+      value &= kHalfWordMask;
+      break;
+    case UXTW:
+      value &= kWordMask;
+      break;
+    case SXTB:
+      value = (value << kSignExtendBShift) >> kSignExtendBShift;
+      break;
+    case SXTH:
+      value = (value << kSignExtendHShift) >> kSignExtendHShift;
+      break;
+    case SXTW:
+      value = (value << kSignExtendWShift) >> kSignExtendWShift;
+      break;
+    case UXTX:
+    case SXTX:
+      break;
+    default:
+      UNREACHABLE();
+  }
+  return value << left_shift;
+}
+
+
+template <typename T>
+void Simulator::Extract(Instruction* instr) {
+  unsigned lsb = instr->ImmS();
+  T op2 = reg<T>(instr->Rm());
+  T result = op2;
+
+  if (lsb) {
+    T op1 = reg<T>(instr->Rn());
+    result = op2 >> lsb | (op1 << ((sizeof(T) * 8) - lsb));
+  }
+  set_reg<T>(instr->Rd(), result);
+}
+
+
+template<> double Simulator::FPDefaultNaN<double>() const {
+  return kFP64DefaultNaN;
+}
+
+
+template<> float Simulator::FPDefaultNaN<float>() const {
+  return kFP32DefaultNaN;
+}
+
+
+void Simulator::FPCompare(double val0, double val1) {
+  AssertSupportedFPCR();
+
+  // TODO(jbramley): This assumes that the C++ implementation handles
+  // comparisons in the way that we expect (as per AssertSupportedFPCR()).
+  if ((std::isnan(val0) != 0) || (std::isnan(val1) != 0)) {
+    nzcv().SetRawValue(FPUnorderedFlag);
+  } else if (val0 < val1) {
+    nzcv().SetRawValue(FPLessThanFlag);
+  } else if (val0 > val1) {
+    nzcv().SetRawValue(FPGreaterThanFlag);
+  } else if (val0 == val1) {
+    nzcv().SetRawValue(FPEqualFlag);
+  } else {
+    UNREACHABLE();
+  }
+  LogSystemRegister(NZCV);
+}
+
+
+void Simulator::SetBreakpoint(Instruction* location) {
+  for (unsigned i = 0; i < breakpoints_.size(); i++) {
+    if (breakpoints_.at(i).location == location) {
+      PrintF(stream_,
+             "Existing breakpoint at %p was %s\n",
+             reinterpret_cast<void*>(location),
+             breakpoints_.at(i).enabled ? "disabled" : "enabled");
+      breakpoints_.at(i).enabled = !breakpoints_.at(i).enabled;
+      return;
+    }
+  }
+  Breakpoint new_breakpoint = {location, true};
+  breakpoints_.push_back(new_breakpoint);
+  PrintF(stream_,
+         "Set a breakpoint at %p\n", reinterpret_cast<void*>(location));
+}
+
+
+void Simulator::ListBreakpoints() {
+  PrintF(stream_, "Breakpoints:\n");
+  for (unsigned i = 0; i < breakpoints_.size(); i++) {
+    PrintF(stream_, "%p  : %s\n",
+           reinterpret_cast<void*>(breakpoints_.at(i).location),
+           breakpoints_.at(i).enabled ? "enabled" : "disabled");
+  }
+}
+
+
+void Simulator::CheckBreakpoints() {
+  bool hit_a_breakpoint = false;
+  for (unsigned i = 0; i < breakpoints_.size(); i++) {
+    if ((breakpoints_.at(i).location == pc_) &&
+        breakpoints_.at(i).enabled) {
+      hit_a_breakpoint = true;
+      // Disable this breakpoint.
+      breakpoints_.at(i).enabled = false;
+    }
+  }
+  if (hit_a_breakpoint) {
+    PrintF(stream_, "Hit and disabled a breakpoint at %p.\n",
+           reinterpret_cast<void*>(pc_));
+    Debug();
+  }
+}
+
+
+void Simulator::CheckBreakNext() {
+  // If the current instruction is a BL, insert a breakpoint just after it.
+  if (break_on_next_ && pc_->IsBranchAndLinkToRegister()) {
+    SetBreakpoint(pc_->following());
+    break_on_next_ = false;
+  }
+}
+
+
+void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
+  Instruction* end = start->InstructionAtOffset(count * kInstructionSize);
+  for (Instruction* pc = start; pc < end; pc = pc->following()) {
+    disassembler_decoder_->Decode(pc);
+  }
+}
+
+
+void Simulator::PrintSystemRegisters() {
+  PrintSystemRegister(NZCV);
+  PrintSystemRegister(FPCR);
+}
+
+
+void Simulator::PrintRegisters() {
+  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
+    PrintRegister(i);
+  }
+}
+
+
+void Simulator::PrintFPRegisters() {
+  for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
+    PrintFPRegister(i);
+  }
+}
+
+
+void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
+  // Don't print writes into xzr.
+  if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
+    return;
+  }
+
+  // The template is "# x<code>:value".
+  fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s\n",
+          clr_reg_name, XRegNameForCode(code, r31mode),
+          clr_reg_value, reg<uint64_t>(code, r31mode), clr_normal);
+}
+
+
+void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) {
+  // The template is "# v<code>:bits (d<code>:value, ...)".
+
+  DCHECK(sizes != 0);
+  DCHECK((sizes & kPrintAllFPRegValues) == sizes);
+
+  // Print the raw bits.
+  fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (",
+          clr_fpreg_name, VRegNameForCode(code),
+          clr_fpreg_value, fpreg<uint64_t>(code), clr_normal);
+
+  // Print all requested value interpretations.
+  bool need_separator = false;
+  if (sizes & kPrintDRegValue) {
+    fprintf(stream_, "%s%s%s: %s%g%s",
+            need_separator ? ", " : "",
+            clr_fpreg_name, DRegNameForCode(code),
+            clr_fpreg_value, fpreg<double>(code), clr_normal);
+    need_separator = true;
+  }
+
+  if (sizes & kPrintSRegValue) {
+    fprintf(stream_, "%s%s%s: %s%g%s",
+            need_separator ? ", " : "",
+            clr_fpreg_name, SRegNameForCode(code),
+            clr_fpreg_value, fpreg<float>(code), clr_normal);
+    need_separator = true;
+  }
+
+  // End the value list.
+  fprintf(stream_, ")\n");
+}
+
+
+void Simulator::PrintSystemRegister(SystemRegister id) {
+  switch (id) {
+    case NZCV:
+      fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
+              clr_flag_name, clr_flag_value,
+              nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
+              clr_normal);
+      break;
+    case FPCR: {
+      static const char * rmode[] = {
+        "0b00 (Round to Nearest)",
+        "0b01 (Round towards Plus Infinity)",
+        "0b10 (Round towards Minus Infinity)",
+        "0b11 (Round towards Zero)"
+      };
+      DCHECK(fpcr().RMode() < arraysize(rmode));
+      fprintf(stream_,
+              "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
+              clr_flag_name, clr_flag_value,
+              fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
+              clr_normal);
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::PrintRead(uintptr_t address,
+                          size_t size,
+                          unsigned reg_code) {
+  USE(size);  // Size is unused here.
+
+  // The template is "# x<code>:value <- address".
+  fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s",
+          clr_reg_name, XRegNameForCode(reg_code),
+          clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
+
+  fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
+          clr_memory_address, address, clr_normal);
+}
+
+
+void Simulator::PrintReadFP(uintptr_t address,
+                            size_t size,
+                            unsigned reg_code) {
+  // The template is "# reg:bits (reg:value) <- address".
+  switch (size) {
+    case kSRegSize:
+      fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)",
+              clr_fpreg_name, VRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
+              clr_fpreg_name, SRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
+      break;
+    case kDRegSize:
+      fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)",
+              clr_fpreg_name, VRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
+              clr_fpreg_name, DRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
+          clr_memory_address, address, clr_normal);
+}
+
+
+void Simulator::PrintWrite(uintptr_t address,
+                           size_t size,
+                           unsigned reg_code) {
+  // The template is "# reg:value -> address". To keep the trace tidy and
+  // readable, the value is aligned with the values in the register trace.
+  switch (size) {
+    case kByteSizeInBytes:
+      fprintf(stream_, "# %s%5s<7:0>:          %s0x%02" PRIx8 "%s",
+              clr_reg_name, WRegNameForCode(reg_code),
+              clr_reg_value, reg<uint8_t>(reg_code), clr_normal);
+      break;
+    case kHalfWordSizeInBytes:
+      fprintf(stream_, "# %s%5s<15:0>:       %s0x%04" PRIx16 "%s",
+              clr_reg_name, WRegNameForCode(reg_code),
+              clr_reg_value, reg<uint16_t>(reg_code), clr_normal);
+      break;
+    case kWRegSize:
+      fprintf(stream_, "# %s%5s:         %s0x%08" PRIx32 "%s",
+              clr_reg_name, WRegNameForCode(reg_code),
+              clr_reg_value, reg<uint32_t>(reg_code), clr_normal);
+      break;
+    case kXRegSize:
+      fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s",
+              clr_reg_name, XRegNameForCode(reg_code),
+              clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
+          clr_memory_address, address, clr_normal);
+}
+
+
+void Simulator::PrintWriteFP(uintptr_t address,
+                             size_t size,
+                             unsigned reg_code) {
+  // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy
+  // and readable, the value is aligned with the values in the register trace.
+  switch (size) {
+    case kSRegSize:
+      fprintf(stream_, "# %s%5s<31:0>:   %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)",
+              clr_fpreg_name, VRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal,
+              clr_fpreg_name, SRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
+      break;
+    case kDRegSize:
+      fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)",
+              clr_fpreg_name, VRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
+              clr_fpreg_name, DRegNameForCode(reg_code),
+              clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
+      break;
+    default:
+      UNREACHABLE();
+  }
+
+  fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
+          clr_memory_address, address, clr_normal);
+}
+
+
+// Visitors---------------------------------------------------------------------
+
+void Simulator::VisitUnimplemented(Instruction* instr) {
+  fprintf(stream_, "Unimplemented instruction at %p: 0x%08" PRIx32 "\n",
+          reinterpret_cast<void*>(instr), instr->InstructionBits());
+  UNIMPLEMENTED();
+}
+
+
+void Simulator::VisitUnallocated(Instruction* instr) {
+  fprintf(stream_, "Unallocated instruction at %p: 0x%08" PRIx32 "\n",
+          reinterpret_cast<void*>(instr), instr->InstructionBits());
+  UNIMPLEMENTED();
+}
+
+
+void Simulator::VisitPCRelAddressing(Instruction* instr) {
+  switch (instr->Mask(PCRelAddressingMask)) {
+    case ADR:
+      set_reg(instr->Rd(), instr->ImmPCOffsetTarget());
+      break;
+    case ADRP:  // Not implemented in the assembler.
+      UNIMPLEMENTED();
+      break;
+    default:
+      UNREACHABLE();
+      break;
+  }
+}
+
+
+void Simulator::VisitUnconditionalBranch(Instruction* instr) {
+  switch (instr->Mask(UnconditionalBranchMask)) {
+    case BL:
+      set_lr(instr->following());
+      // Fall through.
+    case B:
+      set_pc(instr->ImmPCOffsetTarget());
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+
+void Simulator::VisitConditionalBranch(Instruction* instr) {
+  DCHECK(instr->Mask(ConditionalBranchMask) == B_cond);
+  if (ConditionPassed(static_cast<Condition>(instr->ConditionBranch()))) {
+    set_pc(instr->ImmPCOffsetTarget());
+  }
+}
+
+
+void Simulator::VisitUnconditionalBranchToRegister(Instruction* instr) {
+  Instruction* target = reg<Instruction*>(instr->Rn());
+  switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
+    case BLR: {
+      set_lr(instr->following());
+      if (instr->Rn() == 31) {
+        // BLR XZR is used as a guard for the constant pool. We should never hit
+        // this, but if we do trap to allow debugging.
+        Debug();
+      }
+      // Fall through.
+    }
+    case BR:
+    case RET: set_pc(target); break;
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::VisitTestBranch(Instruction* instr) {
+  unsigned bit_pos = (instr->ImmTestBranchBit5() << 5) |
+                     instr->ImmTestBranchBit40();
+  bool take_branch = ((xreg(instr->Rt()) & (1UL << bit_pos)) == 0);
+  switch (instr->Mask(TestBranchMask)) {
+    case TBZ: break;
+    case TBNZ: take_branch = !take_branch; break;
+    default: UNIMPLEMENTED();
+  }
+  if (take_branch) {
+    set_pc(instr->ImmPCOffsetTarget());
+  }
+}
+
+
+void Simulator::VisitCompareBranch(Instruction* instr) {
+  unsigned rt = instr->Rt();
+  bool take_branch = false;
+  switch (instr->Mask(CompareBranchMask)) {
+    case CBZ_w: take_branch = (wreg(rt) == 0); break;
+    case CBZ_x: take_branch = (xreg(rt) == 0); break;
+    case CBNZ_w: take_branch = (wreg(rt) != 0); break;
+    case CBNZ_x: take_branch = (xreg(rt) != 0); break;
+    default: UNIMPLEMENTED();
+  }
+  if (take_branch) {
+    set_pc(instr->ImmPCOffsetTarget());
+  }
+}
+
+
+template<typename T>
+void Simulator::AddSubHelper(Instruction* instr, T op2) {
+  bool set_flags = instr->FlagsUpdate();
+  T new_val = 0;
+  Instr operation = instr->Mask(AddSubOpMask);
+
+  switch (operation) {
+    case ADD:
+    case ADDS: {
+      new_val = AddWithCarry<T>(set_flags,
+                                reg<T>(instr->Rn(), instr->RnMode()),
+                                op2);
+      break;
+    }
+    case SUB:
+    case SUBS: {
+      new_val = AddWithCarry<T>(set_flags,
+                                reg<T>(instr->Rn(), instr->RnMode()),
+                                ~op2,
+                                1);
+      break;
+    }
+    default: UNREACHABLE();
+  }
+
+  set_reg<T>(instr->Rd(), new_val, instr->RdMode());
+}
+
+
+void Simulator::VisitAddSubShifted(Instruction* instr) {
+  Shift shift_type = static_cast<Shift>(instr->ShiftDP());
+  unsigned shift_amount = instr->ImmDPShift();
+
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
+    AddSubHelper(instr, op2);
+  } else {
+    int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
+    AddSubHelper(instr, op2);
+  }
+}
+
+
+void Simulator::VisitAddSubImmediate(Instruction* instr) {
+  int64_t op2 = instr->ImmAddSub() << ((instr->ShiftAddSub() == 1) ? 12 : 0);
+  if (instr->SixtyFourBits()) {
+    AddSubHelper<int64_t>(instr, op2);
+  } else {
+    AddSubHelper<int32_t>(instr, op2);
+  }
+}
+
+
+void Simulator::VisitAddSubExtended(Instruction* instr) {
+  Extend ext = static_cast<Extend>(instr->ExtendMode());
+  unsigned left_shift = instr->ImmExtendShift();
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ExtendValue(xreg(instr->Rm()), ext, left_shift);
+    AddSubHelper(instr, op2);
+  } else {
+    int32_t op2 = ExtendValue(wreg(instr->Rm()), ext, left_shift);
+    AddSubHelper(instr, op2);
+  }
+}
+
+
+void Simulator::VisitAddSubWithCarry(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    AddSubWithCarry<int64_t>(instr);
+  } else {
+    AddSubWithCarry<int32_t>(instr);
+  }
+}
+
+
+void Simulator::VisitLogicalShifted(Instruction* instr) {
+  Shift shift_type = static_cast<Shift>(instr->ShiftDP());
+  unsigned shift_amount = instr->ImmDPShift();
+
+  if (instr->SixtyFourBits()) {
+    int64_t op2 = ShiftOperand(xreg(instr->Rm()), shift_type, shift_amount);
+    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
+    LogicalHelper<int64_t>(instr, op2);
+  } else {
+    int32_t op2 = ShiftOperand(wreg(instr->Rm()), shift_type, shift_amount);
+    op2 = (instr->Mask(NOT) == NOT) ? ~op2 : op2;
+    LogicalHelper<int32_t>(instr, op2);
+  }
+}
+
+
+void Simulator::VisitLogicalImmediate(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    LogicalHelper<int64_t>(instr, instr->ImmLogical());
+  } else {
+    LogicalHelper<int32_t>(instr, instr->ImmLogical());
+  }
+}
+
+
+template<typename T>
+void Simulator::LogicalHelper(Instruction* instr, T op2) {
+  T op1 = reg<T>(instr->Rn());
+  T result = 0;
+  bool update_flags = false;
+
+  // Switch on the logical operation, stripping out the NOT bit, as it has a
+  // different meaning for logical immediate instructions.
+  switch (instr->Mask(LogicalOpMask & ~NOT)) {
+    case ANDS: update_flags = true;  // Fall through.
+    case AND: result = op1 & op2; break;
+    case ORR: result = op1 | op2; break;
+    case EOR: result = op1 ^ op2; break;
+    default:
+      UNIMPLEMENTED();
+  }
+
+  if (update_flags) {
+    nzcv().SetN(CalcNFlag(result));
+    nzcv().SetZ(CalcZFlag(result));
+    nzcv().SetC(0);
+    nzcv().SetV(0);
+    LogSystemRegister(NZCV);
+  }
+
+  set_reg<T>(instr->Rd(), result, instr->RdMode());
+}
+
+
+void Simulator::VisitConditionalCompareRegister(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    ConditionalCompareHelper(instr, xreg(instr->Rm()));
+  } else {
+    ConditionalCompareHelper(instr, wreg(instr->Rm()));
+  }
+}
+
+
+void Simulator::VisitConditionalCompareImmediate(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    ConditionalCompareHelper<int64_t>(instr, instr->ImmCondCmp());
+  } else {
+    ConditionalCompareHelper<int32_t>(instr, instr->ImmCondCmp());
+  }
+}
+
+
+template<typename T>
+void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
+  T op1 = reg<T>(instr->Rn());
+
+  if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
+    // If the condition passes, set the status flags to the result of comparing
+    // the operands.
+    if (instr->Mask(ConditionalCompareMask) == CCMP) {
+      AddWithCarry<T>(true, op1, ~op2, 1);
+    } else {
+      DCHECK(instr->Mask(ConditionalCompareMask) == CCMN);
+      AddWithCarry<T>(true, op1, op2, 0);
+    }
+  } else {
+    // If the condition fails, set the status flags to the nzcv immediate.
+    nzcv().SetFlags(instr->Nzcv());
+    LogSystemRegister(NZCV);
+  }
+}
+
+
+void Simulator::VisitLoadStoreUnsignedOffset(Instruction* instr) {
+  int offset = instr->ImmLSUnsigned() << instr->SizeLS();
+  LoadStoreHelper(instr, offset, Offset);
+}
+
+
+void Simulator::VisitLoadStoreUnscaledOffset(Instruction* instr) {
+  LoadStoreHelper(instr, instr->ImmLS(), Offset);
+}
+
+
+void Simulator::VisitLoadStorePreIndex(Instruction* instr) {
+  LoadStoreHelper(instr, instr->ImmLS(), PreIndex);
+}
+
+
+void Simulator::VisitLoadStorePostIndex(Instruction* instr) {
+  LoadStoreHelper(instr, instr->ImmLS(), PostIndex);
+}
+
+
+void Simulator::VisitLoadStoreRegisterOffset(Instruction* instr) {
+  Extend ext = static_cast<Extend>(instr->ExtendMode());
+  DCHECK((ext == UXTW) || (ext == UXTX) || (ext == SXTW) || (ext == SXTX));
+  unsigned shift_amount = instr->ImmShiftLS() * instr->SizeLS();
+
+  int64_t offset = ExtendValue(xreg(instr->Rm()), ext, shift_amount);
+  LoadStoreHelper(instr, offset, Offset);
+}
+
+
+void Simulator::LoadStoreHelper(Instruction* instr,
+                                int64_t offset,
+                                AddrMode addrmode) {
+  unsigned srcdst = instr->Rt();
+  unsigned addr_reg = instr->Rn();
+  uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
+  uintptr_t stack = 0;
+
+  // Handle the writeback for stores before the store. On a CPU the writeback
+  // and the store are atomic, but when running on the simulator it is possible
+  // to be interrupted in between. The simulator is not thread safe and V8 does
+  // not require it to be to run JavaScript therefore the profiler may sample
+  // the "simulated" CPU in the middle of load/store with writeback. The code
+  // below ensures that push operations are safe even when interrupted: the
+  // stack pointer will be decremented before adding an element to the stack.
+  if (instr->IsStore()) {
+    LoadStoreWriteBack(addr_reg, offset, addrmode);
+
+    // For store the address post writeback is used to check access below the
+    // stack.
+    stack = sp();
+  }
+
+  LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask));
+  switch (op) {
+    // Use _no_log variants to suppress the register trace (LOG_REGS,
+    // LOG_FP_REGS). We will print a more detailed log.
+    case LDRB_w:  set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break;
+    case LDRH_w:  set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break;
+    case LDR_w:   set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break;
+    case LDR_x:   set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break;
+    case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
+    case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
+    case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
+    case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
+    case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); break;
+    case LDR_s:   set_sreg_no_log(srcdst, MemoryRead<float>(address)); break;
+    case LDR_d:   set_dreg_no_log(srcdst, MemoryRead<double>(address)); break;
+
+    case STRB_w:  MemoryWrite<uint8_t>(address, wreg(srcdst)); break;
+    case STRH_w:  MemoryWrite<uint16_t>(address, wreg(srcdst)); break;
+    case STR_w:   MemoryWrite<uint32_t>(address, wreg(srcdst)); break;
+    case STR_x:   MemoryWrite<uint64_t>(address, xreg(srcdst)); break;
+    case STR_s:   MemoryWrite<float>(address, sreg(srcdst)); break;
+    case STR_d:   MemoryWrite<double>(address, dreg(srcdst)); break;
+
+    default: UNIMPLEMENTED();
+  }
+
+  // Print a detailed trace (including the memory address) instead of the basic
+  // register:value trace generated by set_*reg().
+  size_t access_size = 1 << instr->SizeLS();
+  if (instr->IsLoad()) {
+    if ((op == LDR_s) || (op == LDR_d)) {
+      LogReadFP(address, access_size, srcdst);
+    } else {
+      LogRead(address, access_size, srcdst);
+    }
+  } else {
+    if ((op == STR_s) || (op == STR_d)) {
+      LogWriteFP(address, access_size, srcdst);
+    } else {
+      LogWrite(address, access_size, srcdst);
+    }
+  }
+
+  // Handle the writeback for loads after the load to ensure safe pop
+  // operation even when interrupted in the middle of it. The stack pointer
+  // is only updated after the load so pop(fp) will never break the invariant
+  // sp <= fp expected while walking the stack in the sampler.
+  if (instr->IsLoad()) {
+    // For loads the address pre writeback is used to check access below the
+    // stack.
+    stack = sp();
+
+    LoadStoreWriteBack(addr_reg, offset, addrmode);
+  }
+
+  // Accesses below the stack pointer (but above the platform stack limit) are
+  // not allowed in the ABI.
+  CheckMemoryAccess(address, stack);
+}
+
+
+void Simulator::VisitLoadStorePairOffset(Instruction* instr) {
+  LoadStorePairHelper(instr, Offset);
+}
+
+
+void Simulator::VisitLoadStorePairPreIndex(Instruction* instr) {
+  LoadStorePairHelper(instr, PreIndex);
+}
+
+
+void Simulator::VisitLoadStorePairPostIndex(Instruction* instr) {
+  LoadStorePairHelper(instr, PostIndex);
+}
+
+
+void Simulator::VisitLoadStorePairNonTemporal(Instruction* instr) {
+  LoadStorePairHelper(instr, Offset);
+}
+
+
+void Simulator::LoadStorePairHelper(Instruction* instr,
+                                    AddrMode addrmode) {
+  unsigned rt = instr->Rt();
+  unsigned rt2 = instr->Rt2();
+  unsigned addr_reg = instr->Rn();
+  size_t access_size = 1 << instr->SizeLSPair();
+  int64_t offset = instr->ImmLSPair() * access_size;
+  uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
+  uintptr_t address2 = address + access_size;
+  uintptr_t stack = 0;
+
+  // Handle the writeback for stores before the store. On a CPU the writeback
+  // and the store are atomic, but when running on the simulator it is possible
+  // to be interrupted in between. The simulator is not thread safe and V8 does
+  // not require it to be to run JavaScript therefore the profiler may sample
+  // the "simulated" CPU in the middle of load/store with writeback. The code
+  // below ensures that push operations are safe even when interrupted: the
+  // stack pointer will be decremented before adding an element to the stack.
+  if (instr->IsStore()) {
+    LoadStoreWriteBack(addr_reg, offset, addrmode);
+
+    // For store the address post writeback is used to check access below the
+    // stack.
+    stack = sp();
+  }
+
+  LoadStorePairOp op =
+    static_cast<LoadStorePairOp>(instr->Mask(LoadStorePairMask));
+
+  // 'rt' and 'rt2' can only be aliased for stores.
+  DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2));
+
+  switch (op) {
+    // Use _no_log variants to suppress the register trace (LOG_REGS,
+    // LOG_FP_REGS). We will print a more detailed log.
+    case LDP_w: {
+      DCHECK(access_size == kWRegSize);
+      set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
+      set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2));
+      break;
+    }
+    case LDP_s: {
+      DCHECK(access_size == kSRegSize);
+      set_sreg_no_log(rt, MemoryRead<float>(address));
+      set_sreg_no_log(rt2, MemoryRead<float>(address2));
+      break;
+    }
+    case LDP_x: {
+      DCHECK(access_size == kXRegSize);
+      set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
+      set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2));
+      break;
+    }
+    case LDP_d: {
+      DCHECK(access_size == kDRegSize);
+      set_dreg_no_log(rt, MemoryRead<double>(address));
+      set_dreg_no_log(rt2, MemoryRead<double>(address2));
+      break;
+    }
+    case LDPSW_x: {
+      DCHECK(access_size == kWRegSize);
+      set_xreg_no_log(rt, MemoryRead<int32_t>(address));
+      set_xreg_no_log(rt2, MemoryRead<int32_t>(address2));
+      break;
+    }
+    case STP_w: {
+      DCHECK(access_size == kWRegSize);
+      MemoryWrite<uint32_t>(address, wreg(rt));
+      MemoryWrite<uint32_t>(address2, wreg(rt2));
+      break;
+    }
+    case STP_s: {
+      DCHECK(access_size == kSRegSize);
+      MemoryWrite<float>(address, sreg(rt));
+      MemoryWrite<float>(address2, sreg(rt2));
+      break;
+    }
+    case STP_x: {
+      DCHECK(access_size == kXRegSize);
+      MemoryWrite<uint64_t>(address, xreg(rt));
+      MemoryWrite<uint64_t>(address2, xreg(rt2));
+      break;
+    }
+    case STP_d: {
+      DCHECK(access_size == kDRegSize);
+      MemoryWrite<double>(address, dreg(rt));
+      MemoryWrite<double>(address2, dreg(rt2));
+      break;
+    }
+    default: UNREACHABLE();
+  }
+
+  // Print a detailed trace (including the memory address) instead of the basic
+  // register:value trace generated by set_*reg().
+  if (instr->IsLoad()) {
+    if ((op == LDP_s) || (op == LDP_d)) {
+      LogReadFP(address, access_size, rt);
+      LogReadFP(address2, access_size, rt2);
+    } else {
+      LogRead(address, access_size, rt);
+      LogRead(address2, access_size, rt2);
+    }
+  } else {
+    if ((op == STP_s) || (op == STP_d)) {
+      LogWriteFP(address, access_size, rt);
+      LogWriteFP(address2, access_size, rt2);
+    } else {
+      LogWrite(address, access_size, rt);
+      LogWrite(address2, access_size, rt2);
+    }
+  }
+
+  // Handle the writeback for loads after the load to ensure safe pop
+  // operation even when interrupted in the middle of it. The stack pointer
+  // is only updated after the load so pop(fp) will never break the invariant
+  // sp <= fp expected while walking the stack in the sampler.
+  if (instr->IsLoad()) {
+    // For loads the address pre writeback is used to check access below the
+    // stack.
+    stack = sp();
+
+    LoadStoreWriteBack(addr_reg, offset, addrmode);
+  }
+
+  // Accesses below the stack pointer (but above the platform stack limit) are
+  // not allowed in the ABI.
+  CheckMemoryAccess(address, stack);
+}
+
+
+void Simulator::VisitLoadLiteral(Instruction* instr) {
+  uintptr_t address = instr->LiteralAddress();
+  unsigned rt = instr->Rt();
+
+  switch (instr->Mask(LoadLiteralMask)) {
+    // Use _no_log variants to suppress the register trace (LOG_REGS,
+    // LOG_FP_REGS), then print a more detailed log.
+    case LDR_w_lit:
+      set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
+      LogRead(address, kWRegSize, rt);
+      break;
+    case LDR_x_lit:
+      set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
+      LogRead(address, kXRegSize, rt);
+      break;
+    case LDR_s_lit:
+      set_sreg_no_log(rt, MemoryRead<float>(address));
+      LogReadFP(address, kSRegSize, rt);
+      break;
+    case LDR_d_lit:
+      set_dreg_no_log(rt, MemoryRead<double>(address));
+      LogReadFP(address, kDRegSize, rt);
+      break;
+    default: UNREACHABLE();
+  }
+}
+
+
+uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset,
+                                      AddrMode addrmode) {
+  const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask;
+  uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
+  if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) {
+    // When the base register is SP the stack pointer is required to be
+    // quadword aligned prior to the address calculation and write-backs.
+    // Misalignment will cause a stack alignment fault.
+    FATAL("ALIGNMENT EXCEPTION");
+  }
+
+  if ((addrmode == Offset) || (addrmode == PreIndex)) {
+    address += offset;
+  }
+
+  return address;
+}
+
+
+void Simulator::LoadStoreWriteBack(unsigned addr_reg,
+                                   int64_t offset,
+                                   AddrMode addrmode) {
+  if ((addrmode == PreIndex) || (addrmode == PostIndex)) {
+    DCHECK(offset != 0);
+    uint64_t address = xreg(addr_reg, Reg31IsStackPointer);
+    set_reg(addr_reg, address + offset, Reg31IsStackPointer);
+  }
+}
+
+
+void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) {
+  if ((address >= stack_limit_) && (address < stack)) {
+    fprintf(stream_, "ACCESS BELOW STACK POINTER:\n");
+    fprintf(stream_, "  sp is here:          0x%016" PRIx64 "\n",
+            static_cast<uint64_t>(stack));
+    fprintf(stream_, "  access was here:     0x%016" PRIx64 "\n",
+            static_cast<uint64_t>(address));
+    fprintf(stream_, "  stack limit is here: 0x%016" PRIx64 "\n",
+            static_cast<uint64_t>(stack_limit_));
+    fprintf(stream_, "\n");
+    FATAL("ACCESS BELOW STACK POINTER");
+  }
+}
+
+
+void Simulator::VisitMoveWideImmediate(Instruction* instr) {
+  MoveWideImmediateOp mov_op =
+    static_cast<MoveWideImmediateOp>(instr->Mask(MoveWideImmediateMask));
+  int64_t new_xn_val = 0;
+
+  bool is_64_bits = instr->SixtyFourBits() == 1;
+  // Shift is limited for W operations.
+  DCHECK(is_64_bits || (instr->ShiftMoveWide() < 2));
+
+  // Get the shifted immediate.
+  int64_t shift = instr->ShiftMoveWide() * 16;
+  int64_t shifted_imm16 = instr->ImmMoveWide() << shift;
+
+  // Compute the new value.
+  switch (mov_op) {
+    case MOVN_w:
+    case MOVN_x: {
+        new_xn_val = ~shifted_imm16;
+        if (!is_64_bits) new_xn_val &= kWRegMask;
+      break;
+    }
+    case MOVK_w:
+    case MOVK_x: {
+        unsigned reg_code = instr->Rd();
+        int64_t prev_xn_val = is_64_bits ? xreg(reg_code)
+                                         : wreg(reg_code);
+        new_xn_val = (prev_xn_val & ~(0xffffL << shift)) | shifted_imm16;
+      break;
+    }
+    case MOVZ_w:
+    case MOVZ_x: {
+        new_xn_val = shifted_imm16;
+      break;
+    }
+    default:
+      UNREACHABLE();
+  }
+
+  // Update the destination register.
+  set_xreg(instr->Rd(), new_xn_val);
+}
+
+
+void Simulator::VisitConditionalSelect(Instruction* instr) {
+  if (ConditionFailed(static_cast<Condition>(instr->Condition()))) {
+    uint64_t new_val = xreg(instr->Rm());
+    switch (instr->Mask(ConditionalSelectMask)) {
+      case CSEL_w: set_wreg(instr->Rd(), new_val); break;
+      case CSEL_x: set_xreg(instr->Rd(), new_val); break;
+      case CSINC_w: set_wreg(instr->Rd(), new_val + 1); break;
+      case CSINC_x: set_xreg(instr->Rd(), new_val + 1); break;
+      case CSINV_w: set_wreg(instr->Rd(), ~new_val); break;
+      case CSINV_x: set_xreg(instr->Rd(), ~new_val); break;
+      case CSNEG_w: set_wreg(instr->Rd(), -new_val); break;
+      case CSNEG_x: set_xreg(instr->Rd(), -new_val); break;
+      default: UNIMPLEMENTED();
+    }
+  } else {
+    if (instr->SixtyFourBits()) {
+      set_xreg(instr->Rd(), xreg(instr->Rn()));
+    } else {
+      set_wreg(instr->Rd(), wreg(instr->Rn()));
+    }
+  }
+}
+
+
+void Simulator::VisitDataProcessing1Source(Instruction* instr) {
+  unsigned dst = instr->Rd();
+  unsigned src = instr->Rn();
+
+  switch (instr->Mask(DataProcessing1SourceMask)) {
+    case RBIT_w: set_wreg(dst, ReverseBits(wreg(src), kWRegSizeInBits)); break;
+    case RBIT_x: set_xreg(dst, ReverseBits(xreg(src), kXRegSizeInBits)); break;
+    case REV16_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse16)); break;
+    case REV16_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse16)); break;
+    case REV_w: set_wreg(dst, ReverseBytes(wreg(src), Reverse32)); break;
+    case REV32_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse32)); break;
+    case REV_x: set_xreg(dst, ReverseBytes(xreg(src), Reverse64)); break;
+    case CLZ_w: set_wreg(dst, CountLeadingZeros(wreg(src), kWRegSizeInBits));
+                break;
+    case CLZ_x: set_xreg(dst, CountLeadingZeros(xreg(src), kXRegSizeInBits));
+                break;
+    case CLS_w: {
+      set_wreg(dst, CountLeadingSignBits(wreg(src), kWRegSizeInBits));
+      break;
+    }
+    case CLS_x: {
+      set_xreg(dst, CountLeadingSignBits(xreg(src), kXRegSizeInBits));
+      break;
+    }
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+uint64_t Simulator::ReverseBits(uint64_t value, unsigned num_bits) {
+  DCHECK((num_bits == kWRegSizeInBits) || (num_bits == kXRegSizeInBits));
+  uint64_t result = 0;
+  for (unsigned i = 0; i < num_bits; i++) {
+    result = (result << 1) | (value & 1);
+    value >>= 1;
+  }
+  return result;
+}
+
+
+uint64_t Simulator::ReverseBytes(uint64_t value, ReverseByteMode mode) {
+  // Split the 64-bit value into an 8-bit array, where b[0] is the least
+  // significant byte, and b[7] is the most significant.
+  uint8_t bytes[8];
+  uint64_t mask = 0xff00000000000000UL;
+  for (int i = 7; i >= 0; i--) {
+    bytes[i] = (value & mask) >> (i * 8);
+    mask >>= 8;
+  }
+
+  // Permutation tables for REV instructions.
+  //  permute_table[Reverse16] is used by REV16_x, REV16_w
+  //  permute_table[Reverse32] is used by REV32_x, REV_w
+  //  permute_table[Reverse64] is used by REV_x
+  DCHECK((Reverse16 == 0) && (Reverse32 == 1) && (Reverse64 == 2));
+  static const uint8_t permute_table[3][8] = { {6, 7, 4, 5, 2, 3, 0, 1},
+                                               {4, 5, 6, 7, 0, 1, 2, 3},
+                                               {0, 1, 2, 3, 4, 5, 6, 7} };
+  uint64_t result = 0;
+  for (int i = 0; i < 8; i++) {
+    result <<= 8;
+    result |= bytes[permute_table[mode][i]];
+  }
+  return result;
+}
+
+
+template <typename T>
+void Simulator::DataProcessing2Source(Instruction* instr) {
+  Shift shift_op = NO_SHIFT;
+  T result = 0;
+  switch (instr->Mask(DataProcessing2SourceMask)) {
+    case SDIV_w:
+    case SDIV_x: {
+      T rn = reg<T>(instr->Rn());
+      T rm = reg<T>(instr->Rm());
+      if ((rn == std::numeric_limits<T>::min()) && (rm == -1)) {
+        result = std::numeric_limits<T>::min();
+      } else if (rm == 0) {
+        // Division by zero can be trapped, but not on A-class processors.
+        result = 0;
+      } else {
+        result = rn / rm;
+      }
+      break;
+    }
+    case UDIV_w:
+    case UDIV_x: {
+      typedef typename make_unsigned<T>::type unsignedT;
+      unsignedT rn = static_cast<unsignedT>(reg<T>(instr->Rn()));
+      unsignedT rm = static_cast<unsignedT>(reg<T>(instr->Rm()));
+      if (rm == 0) {
+        // Division by zero can be trapped, but not on A-class processors.
+        result = 0;
+      } else {
+        result = rn / rm;
+      }
+      break;
+    }
+    case LSLV_w:
+    case LSLV_x: shift_op = LSL; break;
+    case LSRV_w:
+    case LSRV_x: shift_op = LSR; break;
+    case ASRV_w:
+    case ASRV_x: shift_op = ASR; break;
+    case RORV_w:
+    case RORV_x: shift_op = ROR; break;
+    default: UNIMPLEMENTED();
+  }
+
+  if (shift_op != NO_SHIFT) {
+    // Shift distance encoded in the least-significant five/six bits of the
+    // register.
+    unsigned shift = wreg(instr->Rm());
+    if (sizeof(T) == kWRegSize) {
+      shift &= kShiftAmountWRegMask;
+    } else {
+      shift &= kShiftAmountXRegMask;
+    }
+    result = ShiftOperand(reg<T>(instr->Rn()), shift_op, shift);
+  }
+  set_reg<T>(instr->Rd(), result);
+}
+
+
+void Simulator::VisitDataProcessing2Source(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    DataProcessing2Source<int64_t>(instr);
+  } else {
+    DataProcessing2Source<int32_t>(instr);
+  }
+}
+
+
+// The algorithm used is described in section 8.2 of
+//   Hacker's Delight, by Henry S. Warren, Jr.
+// It assumes that a right shift on a signed integer is an arithmetic shift.
+static int64_t MultiplyHighSigned(int64_t u, int64_t v) {
+  uint64_t u0, v0, w0;
+  int64_t u1, v1, w1, w2, t;
+
+  u0 = u & 0xffffffffL;
+  u1 = u >> 32;
+  v0 = v & 0xffffffffL;
+  v1 = v >> 32;
+
+  w0 = u0 * v0;
+  t = u1 * v0 + (w0 >> 32);
+  w1 = t & 0xffffffffL;
+  w2 = t >> 32;
+  w1 = u0 * v1 + w1;
+
+  return u1 * v1 + w2 + (w1 >> 32);
+}
+
+
+void Simulator::VisitDataProcessing3Source(Instruction* instr) {
+  int64_t result = 0;
+  // Extract and sign- or zero-extend 32-bit arguments for widening operations.
+  uint64_t rn_u32 = reg<uint32_t>(instr->Rn());
+  uint64_t rm_u32 = reg<uint32_t>(instr->Rm());
+  int64_t rn_s32 = reg<int32_t>(instr->Rn());
+  int64_t rm_s32 = reg<int32_t>(instr->Rm());
+  switch (instr->Mask(DataProcessing3SourceMask)) {
+    case MADD_w:
+    case MADD_x:
+      result = xreg(instr->Ra()) + (xreg(instr->Rn()) * xreg(instr->Rm()));
+      break;
+    case MSUB_w:
+    case MSUB_x:
+      result = xreg(instr->Ra()) - (xreg(instr->Rn()) * xreg(instr->Rm()));
+      break;
+    case SMADDL_x: result = xreg(instr->Ra()) + (rn_s32 * rm_s32); break;
+    case SMSUBL_x: result = xreg(instr->Ra()) - (rn_s32 * rm_s32); break;
+    case UMADDL_x: result = xreg(instr->Ra()) + (rn_u32 * rm_u32); break;
+    case UMSUBL_x: result = xreg(instr->Ra()) - (rn_u32 * rm_u32); break;
+    case SMULH_x:
+      DCHECK(instr->Ra() == kZeroRegCode);
+      result = MultiplyHighSigned(xreg(instr->Rn()), xreg(instr->Rm()));
+      break;
+    default: UNIMPLEMENTED();
+  }
+
+  if (instr->SixtyFourBits()) {
+    set_xreg(instr->Rd(), result);
+  } else {
+    set_wreg(instr->Rd(), result);
+  }
+}
+
+
+template <typename T>
+void Simulator::BitfieldHelper(Instruction* instr) {
+  typedef typename make_unsigned<T>::type unsignedT;
+  T reg_size = sizeof(T) * 8;
+  T R = instr->ImmR();
+  T S = instr->ImmS();
+  T diff = S - R;
+  T mask;
+  if (diff >= 0) {
+    mask = diff < reg_size - 1 ? (static_cast<T>(1) << (diff + 1)) - 1
+                               : static_cast<T>(-1);
+  } else {
+    mask = ((1L << (S + 1)) - 1);
+    mask = (static_cast<uint64_t>(mask) >> R) | (mask << (reg_size - R));
+    diff += reg_size;
+  }
+
+  // inzero indicates if the extracted bitfield is inserted into the
+  // destination register value or in zero.
+  // If extend is true, extend the sign of the extracted bitfield.
+  bool inzero = false;
+  bool extend = false;
+  switch (instr->Mask(BitfieldMask)) {
+    case BFM_x:
+    case BFM_w:
+      break;
+    case SBFM_x:
+    case SBFM_w:
+      inzero = true;
+      extend = true;
+      break;
+    case UBFM_x:
+    case UBFM_w:
+      inzero = true;
+      break;
+    default:
+      UNIMPLEMENTED();
+  }
+
+  T dst = inzero ? 0 : reg<T>(instr->Rd());
+  T src = reg<T>(instr->Rn());
+  // Rotate source bitfield into place.
+  T result = (static_cast<unsignedT>(src) >> R) | (src << (reg_size - R));
+  // Determine the sign extension.
+  T topbits_preshift = (static_cast<T>(1) << (reg_size - diff - 1)) - 1;
+  T signbits = (extend && ((src >> S) & 1) ? topbits_preshift : 0)
+               << (diff + 1);
+
+  // Merge sign extension, dest/zero and bitfield.
+  result = signbits | (result & mask) | (dst & ~mask);
+
+  set_reg<T>(instr->Rd(), result);
+}
+
+
+void Simulator::VisitBitfield(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    BitfieldHelper<int64_t>(instr);
+  } else {
+    BitfieldHelper<int32_t>(instr);
+  }
+}
+
+
+void Simulator::VisitExtract(Instruction* instr) {
+  if (instr->SixtyFourBits()) {
+    Extract<uint64_t>(instr);
+  } else {
+    Extract<uint32_t>(instr);
+  }
+}
+
+
+void Simulator::VisitFPImmediate(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned dest = instr->Rd();
+  switch (instr->Mask(FPImmediateMask)) {
+    case FMOV_s_imm: set_sreg(dest, instr->ImmFP32()); break;
+    case FMOV_d_imm: set_dreg(dest, instr->ImmFP64()); break;
+    default: UNREACHABLE();
+  }
+}
+
+
+void Simulator::VisitFPIntegerConvert(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned dst = instr->Rd();
+  unsigned src = instr->Rn();
+
+  FPRounding round = fpcr().RMode();
+
+  switch (instr->Mask(FPIntegerConvertMask)) {
+    case FCVTAS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieAway)); break;
+    case FCVTAS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieAway)); break;
+    case FCVTAS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieAway)); break;
+    case FCVTAS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieAway)); break;
+    case FCVTAU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieAway)); break;
+    case FCVTAU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieAway)); break;
+    case FCVTAU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieAway)); break;
+    case FCVTAU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieAway)); break;
+    case FCVTMS_ws:
+      set_wreg(dst, FPToInt32(sreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMS_xs:
+      set_xreg(dst, FPToInt64(sreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMS_wd:
+      set_wreg(dst, FPToInt32(dreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMS_xd:
+      set_xreg(dst, FPToInt64(dreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMU_ws:
+      set_wreg(dst, FPToUInt32(sreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMU_xs:
+      set_xreg(dst, FPToUInt64(sreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMU_wd:
+      set_wreg(dst, FPToUInt32(dreg(src), FPNegativeInfinity));
+      break;
+    case FCVTMU_xd:
+      set_xreg(dst, FPToUInt64(dreg(src), FPNegativeInfinity));
+      break;
+    case FCVTNS_ws: set_wreg(dst, FPToInt32(sreg(src), FPTieEven)); break;
+    case FCVTNS_xs: set_xreg(dst, FPToInt64(sreg(src), FPTieEven)); break;
+    case FCVTNS_wd: set_wreg(dst, FPToInt32(dreg(src), FPTieEven)); break;
+    case FCVTNS_xd: set_xreg(dst, FPToInt64(dreg(src), FPTieEven)); break;
+    case FCVTNU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPTieEven)); break;
+    case FCVTNU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPTieEven)); break;
+    case FCVTNU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPTieEven)); break;
+    case FCVTNU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPTieEven)); break;
+    case FCVTZS_ws: set_wreg(dst, FPToInt32(sreg(src), FPZero)); break;
+    case FCVTZS_xs: set_xreg(dst, FPToInt64(sreg(src), FPZero)); break;
+    case FCVTZS_wd: set_wreg(dst, FPToInt32(dreg(src), FPZero)); break;
+    case FCVTZS_xd: set_xreg(dst, FPToInt64(dreg(src), FPZero)); break;
+    case FCVTZU_ws: set_wreg(dst, FPToUInt32(sreg(src), FPZero)); break;
+    case FCVTZU_xs: set_xreg(dst, FPToUInt64(sreg(src), FPZero)); break;
+    case FCVTZU_wd: set_wreg(dst, FPToUInt32(dreg(src), FPZero)); break;
+    case FCVTZU_xd: set_xreg(dst, FPToUInt64(dreg(src), FPZero)); break;
+    case FMOV_ws: set_wreg(dst, sreg_bits(src)); break;
+    case FMOV_xd: set_xreg(dst, dreg_bits(src)); break;
+    case FMOV_sw: set_sreg_bits(dst, wreg(src)); break;
+    case FMOV_dx: set_dreg_bits(dst, xreg(src)); break;
+
+    // A 32-bit input can be handled in the same way as a 64-bit input, since
+    // the sign- or zero-extension will not affect the conversion.
+    case SCVTF_dx: set_dreg(dst, FixedToDouble(xreg(src), 0, round)); break;
+    case SCVTF_dw: set_dreg(dst, FixedToDouble(wreg(src), 0, round)); break;
+    case UCVTF_dx: set_dreg(dst, UFixedToDouble(xreg(src), 0, round)); break;
+    case UCVTF_dw: {
+      set_dreg(dst, UFixedToDouble(reg<uint32_t>(src), 0, round));
+      break;
+    }
+    case SCVTF_sx: set_sreg(dst, FixedToFloat(xreg(src), 0, round)); break;
+    case SCVTF_sw: set_sreg(dst, FixedToFloat(wreg(src), 0, round)); break;
+    case UCVTF_sx: set_sreg(dst, UFixedToFloat(xreg(src), 0, round)); break;
+    case UCVTF_sw: {
+      set_sreg(dst, UFixedToFloat(reg<uint32_t>(src), 0, round));
+      break;
+    }
+
+    default: UNREACHABLE();
+  }
+}
+
+
+void Simulator::VisitFPFixedPointConvert(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned dst = instr->Rd();
+  unsigned src = instr->Rn();
+  int fbits = 64 - instr->FPScale();
+
+  FPRounding round = fpcr().RMode();
+
+  switch (instr->Mask(FPFixedPointConvertMask)) {
+    // A 32-bit input can be handled in the same way as a 64-bit input, since
+    // the sign- or zero-extension will not affect the conversion.
+    case SCVTF_dx_fixed:
+      set_dreg(dst, FixedToDouble(xreg(src), fbits, round));
+      break;
+    case SCVTF_dw_fixed:
+      set_dreg(dst, FixedToDouble(wreg(src), fbits, round));
+      break;
+    case UCVTF_dx_fixed:
+      set_dreg(dst, UFixedToDouble(xreg(src), fbits, round));
+      break;
+    case UCVTF_dw_fixed: {
+      set_dreg(dst,
+               UFixedToDouble(reg<uint32_t>(src), fbits, round));
+      break;
+    }
+    case SCVTF_sx_fixed:
+      set_sreg(dst, FixedToFloat(xreg(src), fbits, round));
+      break;
+    case SCVTF_sw_fixed:
+      set_sreg(dst, FixedToFloat(wreg(src), fbits, round));
+      break;
+    case UCVTF_sx_fixed:
+      set_sreg(dst, UFixedToFloat(xreg(src), fbits, round));
+      break;
+    case UCVTF_sw_fixed: {
+      set_sreg(dst,
+               UFixedToFloat(reg<uint32_t>(src), fbits, round));
+      break;
+    }
+    default: UNREACHABLE();
+  }
+}
+
+
+int32_t Simulator::FPToInt32(double value, FPRounding rmode) {
+  value = FPRoundInt(value, rmode);
+  if (value >= kWMaxInt) {
+    return kWMaxInt;
+  } else if (value < kWMinInt) {
+    return kWMinInt;
+  }
+  return std::isnan(value) ? 0 : static_cast<int32_t>(value);
+}
+
+
+int64_t Simulator::FPToInt64(double value, FPRounding rmode) {
+  value = FPRoundInt(value, rmode);
+  if (value >= kXMaxInt) {
+    return kXMaxInt;
+  } else if (value < kXMinInt) {
+    return kXMinInt;
+  }
+  return std::isnan(value) ? 0 : static_cast<int64_t>(value);
+}
+
+
+uint32_t Simulator::FPToUInt32(double value, FPRounding rmode) {
+  value = FPRoundInt(value, rmode);
+  if (value >= kWMaxUInt) {
+    return kWMaxUInt;
+  } else if (value < 0.0) {
+    return 0;
+  }
+  return std::isnan(value) ? 0 : static_cast<uint32_t>(value);
+}
+
+
+uint64_t Simulator::FPToUInt64(double value, FPRounding rmode) {
+  value = FPRoundInt(value, rmode);
+  if (value >= kXMaxUInt) {
+    return kXMaxUInt;
+  } else if (value < 0.0) {
+    return 0;
+  }
+  return std::isnan(value) ? 0 : static_cast<uint64_t>(value);
+}
+
+
+void Simulator::VisitFPCompare(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits
+                                                  : kSRegSizeInBits;
+  double fn_val = fpreg(reg_size, instr->Rn());
+
+  switch (instr->Mask(FPCompareMask)) {
+    case FCMP_s:
+    case FCMP_d: FPCompare(fn_val, fpreg(reg_size, instr->Rm())); break;
+    case FCMP_s_zero:
+    case FCMP_d_zero: FPCompare(fn_val, 0.0); break;
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::VisitFPConditionalCompare(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  switch (instr->Mask(FPConditionalCompareMask)) {
+    case FCCMP_s:
+    case FCCMP_d: {
+      if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
+        // If the condition passes, set the status flags to the result of
+        // comparing the operands.
+        unsigned reg_size = (instr->Mask(FP64) == FP64) ? kDRegSizeInBits
+                                                        : kSRegSizeInBits;
+        FPCompare(fpreg(reg_size, instr->Rn()), fpreg(reg_size, instr->Rm()));
+      } else {
+        // If the condition fails, set the status flags to the nzcv immediate.
+        nzcv().SetFlags(instr->Nzcv());
+        LogSystemRegister(NZCV);
+      }
+      break;
+    }
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::VisitFPConditionalSelect(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  Instr selected;
+  if (ConditionPassed(static_cast<Condition>(instr->Condition()))) {
+    selected = instr->Rn();
+  } else {
+    selected = instr->Rm();
+  }
+
+  switch (instr->Mask(FPConditionalSelectMask)) {
+    case FCSEL_s: set_sreg(instr->Rd(), sreg(selected)); break;
+    case FCSEL_d: set_dreg(instr->Rd(), dreg(selected)); break;
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::VisitFPDataProcessing1Source(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned fd = instr->Rd();
+  unsigned fn = instr->Rn();
+
+  switch (instr->Mask(FPDataProcessing1SourceMask)) {
+    case FMOV_s: set_sreg(fd, sreg(fn)); break;
+    case FMOV_d: set_dreg(fd, dreg(fn)); break;
+    case FABS_s: set_sreg(fd, std::fabs(sreg(fn))); break;
+    case FABS_d: set_dreg(fd, std::fabs(dreg(fn))); break;
+    case FNEG_s: set_sreg(fd, -sreg(fn)); break;
+    case FNEG_d: set_dreg(fd, -dreg(fn)); break;
+    case FSQRT_s: set_sreg(fd, FPSqrt(sreg(fn))); break;
+    case FSQRT_d: set_dreg(fd, FPSqrt(dreg(fn))); break;
+    case FRINTA_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieAway)); break;
+    case FRINTA_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieAway)); break;
+    case FRINTM_s:
+        set_sreg(fd, FPRoundInt(sreg(fn), FPNegativeInfinity)); break;
+    case FRINTM_d:
+        set_dreg(fd, FPRoundInt(dreg(fn), FPNegativeInfinity)); break;
+    case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break;
+    case FRINTN_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieEven)); break;
+    case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn), FPZero)); break;
+    case FRINTZ_d: set_dreg(fd, FPRoundInt(dreg(fn), FPZero)); break;
+    case FCVT_ds: set_dreg(fd, FPToDouble(sreg(fn))); break;
+    case FCVT_sd: set_sreg(fd, FPToFloat(dreg(fn), FPTieEven)); break;
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+// Assemble the specified IEEE-754 components into the target type and apply
+// appropriate rounding.
+//  sign:     0 = positive, 1 = negative
+//  exponent: Unbiased IEEE-754 exponent.
+//  mantissa: The mantissa of the input. The top bit (which is not encoded for
+//            normal IEEE-754 values) must not be omitted. This bit has the
+//            value 'pow(2, exponent)'.
+//
+// The input value is assumed to be a normalized value. That is, the input may
+// not be infinity or NaN. If the source value is subnormal, it must be
+// normalized before calling this function such that the highest set bit in the
+// mantissa has the value 'pow(2, exponent)'.
+//
+// Callers should use FPRoundToFloat or FPRoundToDouble directly, rather than
+// calling a templated FPRound.
+template <class T, int ebits, int mbits>
+static T FPRound(int64_t sign, int64_t exponent, uint64_t mantissa,
+                 FPRounding round_mode) {
+  DCHECK((sign == 0) || (sign == 1));
+
+  // Only the FPTieEven rounding mode is implemented.
+  DCHECK(round_mode == FPTieEven);
+  USE(round_mode);
+
+  // Rounding can promote subnormals to normals, and normals to infinities. For
+  // example, a double with exponent 127 (FLT_MAX_EXP) would appear to be
+  // encodable as a float, but rounding based on the low-order mantissa bits
+  // could make it overflow. With ties-to-even rounding, this value would become
+  // an infinity.
+
+  // ---- Rounding Method ----
+  //
+  // The exponent is irrelevant in the rounding operation, so we treat the
+  // lowest-order bit that will fit into the result ('onebit') as having
+  // the value '1'. Similarly, the highest-order bit that won't fit into
+  // the result ('halfbit') has the value '0.5'. The 'point' sits between
+  // 'onebit' and 'halfbit':
+  //
+  //            These bits fit into the result.
+  //               |---------------------|
+  //  mantissa = 0bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+  //                                     ||
+  //                                    / |
+  //                                   /  halfbit
+  //                               onebit
+  //
+  // For subnormal outputs, the range of representable bits is smaller and
+  // the position of onebit and halfbit depends on the exponent of the
+  // input, but the method is otherwise similar.
+  //
+  //   onebit(frac)
+  //     |
+  //     | halfbit(frac)          halfbit(adjusted)
+  //     | /                      /
+  //     | |                      |
+  //  0b00.0 (exact)      -> 0b00.0 (exact)                    -> 0b00
+  //  0b00.0...           -> 0b00.0...                         -> 0b00
+  //  0b00.1 (exact)      -> 0b00.0111..111                    -> 0b00
+  //  0b00.1...           -> 0b00.1...                         -> 0b01
+  //  0b01.0 (exact)      -> 0b01.0 (exact)                    -> 0b01
+  //  0b01.0...           -> 0b01.0...                         -> 0b01
+  //  0b01.1 (exact)      -> 0b01.1 (exact)                    -> 0b10
+  //  0b01.1...           -> 0b01.1...                         -> 0b10
+  //  0b10.0 (exact)      -> 0b10.0 (exact)                    -> 0b10
+  //  0b10.0...           -> 0b10.0...                         -> 0b10
+  //  0b10.1 (exact)      -> 0b10.0111..111                    -> 0b10
+  //  0b10.1...           -> 0b10.1...                         -> 0b11
+  //  0b11.0 (exact)      -> 0b11.0 (exact)                    -> 0b11
+  //  ...                   /             |                      /   |
+  //                       /              |                     /    |
+  //                                                           /     |
+  // adjusted = frac - (halfbit(mantissa) & ~onebit(frac));   /      |
+  //
+  //                   mantissa = (mantissa >> shift) + halfbit(adjusted);
+
+  static const int mantissa_offset = 0;
+  static const int exponent_offset = mantissa_offset + mbits;
+  static const int sign_offset = exponent_offset + ebits;
+  STATIC_ASSERT(sign_offset == (sizeof(T) * kByteSize - 1));
+
+  // Bail out early for zero inputs.
+  if (mantissa == 0) {
+    return sign << sign_offset;
+  }
+
+  // If all bits in the exponent are set, the value is infinite or NaN.
+  // This is true for all binary IEEE-754 formats.
+  static const int infinite_exponent = (1 << ebits) - 1;
+  static const int max_normal_exponent = infinite_exponent - 1;
+
+  // Apply the exponent bias to encode it for the result. Doing this early makes
+  // it easy to detect values that will be infinite or subnormal.
+  exponent += max_normal_exponent >> 1;
+
+  if (exponent > max_normal_exponent) {
+    // Overflow: The input is too large for the result type to represent. The
+    // FPTieEven rounding mode handles overflows using infinities.
+    exponent = infinite_exponent;
+    mantissa = 0;
+    return (sign << sign_offset) |
+           (exponent << exponent_offset) |
+           (mantissa << mantissa_offset);
+  }
+
+  // Calculate the shift required to move the top mantissa bit to the proper
+  // place in the destination type.
+  const int highest_significant_bit = 63 - CountLeadingZeros(mantissa, 64);
+  int shift = highest_significant_bit - mbits;
+
+  if (exponent <= 0) {
+    // The output will be subnormal (before rounding).
+
+    // For subnormal outputs, the shift must be adjusted by the exponent. The +1
+    // is necessary because the exponent of a subnormal value (encoded as 0) is
+    // the same as the exponent of the smallest normal value (encoded as 1).
+    shift += -exponent + 1;
+
+    // Handle inputs that would produce a zero output.
+    //
+    // Shifts higher than highest_significant_bit+1 will always produce a zero
+    // result. A shift of exactly highest_significant_bit+1 might produce a
+    // non-zero result after rounding.
+    if (shift > (highest_significant_bit + 1)) {
+      // The result will always be +/-0.0.
+      return sign << sign_offset;
+    }
+
+    // Properly encode the exponent for a subnormal output.
+    exponent = 0;
+  } else {
+    // Clear the topmost mantissa bit, since this is not encoded in IEEE-754
+    // normal values.
+    mantissa &= ~(1UL << highest_significant_bit);
+  }
+
+  if (shift > 0) {
+    // We have to shift the mantissa to the right. Some precision is lost, so we
+    // need to apply rounding.
+    uint64_t onebit_mantissa = (mantissa >> (shift)) & 1;
+    uint64_t halfbit_mantissa = (mantissa >> (shift-1)) & 1;
+    uint64_t adjusted = mantissa - (halfbit_mantissa & ~onebit_mantissa);
+    T halfbit_adjusted = (adjusted >> (shift-1)) & 1;
+
+    T result = (sign << sign_offset) |
+               (exponent << exponent_offset) |
+               ((mantissa >> shift) << mantissa_offset);
+
+    // A very large mantissa can overflow during rounding. If this happens, the
+    // exponent should be incremented and the mantissa set to 1.0 (encoded as
+    // 0). Applying halfbit_adjusted after assembling the float has the nice
+    // side-effect that this case is handled for free.
+    //
+    // This also handles cases where a very large finite value overflows to
+    // infinity, or where a very large subnormal value overflows to become
+    // normal.
+    return result + halfbit_adjusted;
+  } else {
+    // We have to shift the mantissa to the left (or not at all). The input
+    // mantissa is exactly representable in the output mantissa, so apply no
+    // rounding correction.
+    return (sign << sign_offset) |
+           (exponent << exponent_offset) |
+           ((mantissa << -shift) << mantissa_offset);
+  }
+}
+
+
+// See FPRound for a description of this function.
+static inline double FPRoundToDouble(int64_t sign, int64_t exponent,
+                                     uint64_t mantissa, FPRounding round_mode) {
+  int64_t bits =
+      FPRound<int64_t, kDoubleExponentBits, kDoubleMantissaBits>(sign,
+                                                                 exponent,
+                                                                 mantissa,
+                                                                 round_mode);
+  return rawbits_to_double(bits);
+}
+
+
+// See FPRound for a description of this function.
+static inline float FPRoundToFloat(int64_t sign, int64_t exponent,
+                                   uint64_t mantissa, FPRounding round_mode) {
+  int32_t bits =
+      FPRound<int32_t, kFloatExponentBits, kFloatMantissaBits>(sign,
+                                                               exponent,
+                                                               mantissa,
+                                                               round_mode);
+  return rawbits_to_float(bits);
+}
+
+
+double Simulator::FixedToDouble(int64_t src, int fbits, FPRounding round) {
+  if (src >= 0) {
+    return UFixedToDouble(src, fbits, round);
+  } else {
+    // This works for all negative values, including INT64_MIN.
+    return -UFixedToDouble(-src, fbits, round);
+  }
+}
+
+
+double Simulator::UFixedToDouble(uint64_t src, int fbits, FPRounding round) {
+  // An input of 0 is a special case because the result is effectively
+  // subnormal: The exponent is encoded as 0 and there is no implicit 1 bit.
+  if (src == 0) {
+    return 0.0;
+  }
+
+  // Calculate the exponent. The highest significant bit will have the value
+  // 2^exponent.
+  const int highest_significant_bit = 63 - CountLeadingZeros(src, 64);
+  const int64_t exponent = highest_significant_bit - fbits;
+
+  return FPRoundToDouble(0, exponent, src, round);
+}
+
+
+float Simulator::FixedToFloat(int64_t src, int fbits, FPRounding round) {
+  if (src >= 0) {
+    return UFixedToFloat(src, fbits, round);
+  } else {
+    // This works for all negative values, including INT64_MIN.
+    return -UFixedToFloat(-src, fbits, round);
+  }
+}
+
+
+float Simulator::UFixedToFloat(uint64_t src, int fbits, FPRounding round) {
+  // An input of 0 is a special case because the result is effectively
+  // subnormal: The exponent is encoded as 0 and there is no implicit 1 bit.
+  if (src == 0) {
+    return 0.0f;
+  }
+
+  // Calculate the exponent. The highest significant bit will have the value
+  // 2^exponent.
+  const int highest_significant_bit = 63 - CountLeadingZeros(src, 64);
+  const int32_t exponent = highest_significant_bit - fbits;
+
+  return FPRoundToFloat(0, exponent, src, round);
+}
+
+
+double Simulator::FPRoundInt(double value, FPRounding round_mode) {
+  if ((value == 0.0) || (value == kFP64PositiveInfinity) ||
+      (value == kFP64NegativeInfinity)) {
+    return value;
+  } else if (std::isnan(value)) {
+    return FPProcessNaN(value);
+  }
+
+  double int_result = floor(value);
+  double error = value - int_result;
+  switch (round_mode) {
+    case FPTieAway: {
+      // Take care of correctly handling the range ]-0.5, -0.0], which must
+      // yield -0.0.
+      if ((-0.5 < value) && (value < 0.0)) {
+        int_result = -0.0;
+
+      } else if ((error > 0.5) || ((error == 0.5) && (int_result >= 0.0))) {
+        // If the error is greater than 0.5, or is equal to 0.5 and the integer
+        // result is positive, round up.
+        int_result++;
+      }
+      break;
+    }
+    case FPTieEven: {
+      // Take care of correctly handling the range [-0.5, -0.0], which must
+      // yield -0.0.
+      if ((-0.5 <= value) && (value < 0.0)) {
+        int_result = -0.0;
+
+      // If the error is greater than 0.5, or is equal to 0.5 and the integer
+      // result is odd, round up.
+      } else if ((error > 0.5) ||
+          ((error == 0.5) && (fmod(int_result, 2) != 0))) {
+        int_result++;
+      }
+      break;
+    }
+    case FPZero: {
+      // If value > 0 then we take floor(value)
+      // otherwise, ceil(value)
+      if (value < 0) {
+         int_result = ceil(value);
+      }
+      break;
+    }
+    case FPNegativeInfinity: {
+      // We always use floor(value).
+      break;
+    }
+    default: UNIMPLEMENTED();
+  }
+  return int_result;
+}
+
+
+double Simulator::FPToDouble(float value) {
+  switch (std::fpclassify(value)) {
+    case FP_NAN: {
+      if (fpcr().DN()) return kFP64DefaultNaN;
+
+      // Convert NaNs as the processor would:
+      //  - The sign is propagated.
+      //  - The payload (mantissa) is transferred entirely, except that the top
+      //    bit is forced to '1', making the result a quiet NaN. The unused
+      //    (low-order) payload bits are set to 0.
+      uint32_t raw = float_to_rawbits(value);
+
+      uint64_t sign = raw >> 31;
+      uint64_t exponent = (1 << 11) - 1;
+      uint64_t payload = unsigned_bitextract_64(21, 0, raw);
+      payload <<= (52 - 23);  // The unused low-order bits should be 0.
+      payload |= (1L << 51);  // Force a quiet NaN.
+
+      return rawbits_to_double((sign << 63) | (exponent << 52) | payload);
+    }
+
+    case FP_ZERO:
+    case FP_NORMAL:
+    case FP_SUBNORMAL:
+    case FP_INFINITE: {
+      // All other inputs are preserved in a standard cast, because every value
+      // representable using an IEEE-754 float is also representable using an
+      // IEEE-754 double.
+      return static_cast<double>(value);
+    }
+  }
+
+  UNREACHABLE();
+  return static_cast<double>(value);
+}
+
+
+float Simulator::FPToFloat(double value, FPRounding round_mode) {
+  // Only the FPTieEven rounding mode is implemented.
+  DCHECK(round_mode == FPTieEven);
+  USE(round_mode);
+
+  switch (std::fpclassify(value)) {
+    case FP_NAN: {
+      if (fpcr().DN()) return kFP32DefaultNaN;
+
+      // Convert NaNs as the processor would:
+      //  - The sign is propagated.
+      //  - The payload (mantissa) is transferred as much as possible, except
+      //    that the top bit is forced to '1', making the result a quiet NaN.
+      uint64_t raw = double_to_rawbits(value);
+
+      uint32_t sign = raw >> 63;
+      uint32_t exponent = (1 << 8) - 1;
+      uint32_t payload = unsigned_bitextract_64(50, 52 - 23, raw);
+      payload |= (1 << 22);   // Force a quiet NaN.
+
+      return rawbits_to_float((sign << 31) | (exponent << 23) | payload);
+    }
+
+    case FP_ZERO:
+    case FP_INFINITE: {
+      // In a C++ cast, any value representable in the target type will be
+      // unchanged. This is always the case for +/-0.0 and infinities.
+      return static_cast<float>(value);
+    }
+
+    case FP_NORMAL:
+    case FP_SUBNORMAL: {
+      // Convert double-to-float as the processor would, assuming that FPCR.FZ
+      // (flush-to-zero) is not set.
+      uint64_t raw = double_to_rawbits(value);
+      // Extract the IEEE-754 double components.
+      uint32_t sign = raw >> 63;
+      // Extract the exponent and remove the IEEE-754 encoding bias.
+      int32_t exponent = unsigned_bitextract_64(62, 52, raw) - 1023;
+      // Extract the mantissa and add the implicit '1' bit.
+      uint64_t mantissa = unsigned_bitextract_64(51, 0, raw);
+      if (std::fpclassify(value) == FP_NORMAL) {
+        mantissa |= (1UL << 52);
+      }
+      return FPRoundToFloat(sign, exponent, mantissa, round_mode);
+    }
+  }
+
+  UNREACHABLE();
+  return value;
+}
+
+
+void Simulator::VisitFPDataProcessing2Source(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned fd = instr->Rd();
+  unsigned fn = instr->Rn();
+  unsigned fm = instr->Rm();
+
+  // Fmaxnm and Fminnm have special NaN handling.
+  switch (instr->Mask(FPDataProcessing2SourceMask)) {
+    case FMAXNM_s: set_sreg(fd, FPMaxNM(sreg(fn), sreg(fm))); return;
+    case FMAXNM_d: set_dreg(fd, FPMaxNM(dreg(fn), dreg(fm))); return;
+    case FMINNM_s: set_sreg(fd, FPMinNM(sreg(fn), sreg(fm))); return;
+    case FMINNM_d: set_dreg(fd, FPMinNM(dreg(fn), dreg(fm))); return;
+    default:
+      break;    // Fall through.
+  }
+
+  if (FPProcessNaNs(instr)) return;
+
+  switch (instr->Mask(FPDataProcessing2SourceMask)) {
+    case FADD_s: set_sreg(fd, FPAdd(sreg(fn), sreg(fm))); break;
+    case FADD_d: set_dreg(fd, FPAdd(dreg(fn), dreg(fm))); break;
+    case FSUB_s: set_sreg(fd, FPSub(sreg(fn), sreg(fm))); break;
+    case FSUB_d: set_dreg(fd, FPSub(dreg(fn), dreg(fm))); break;
+    case FMUL_s: set_sreg(fd, FPMul(sreg(fn), sreg(fm))); break;
+    case FMUL_d: set_dreg(fd, FPMul(dreg(fn), dreg(fm))); break;
+    case FDIV_s: set_sreg(fd, FPDiv(sreg(fn), sreg(fm))); break;
+    case FDIV_d: set_dreg(fd, FPDiv(dreg(fn), dreg(fm))); break;
+    case FMAX_s: set_sreg(fd, FPMax(sreg(fn), sreg(fm))); break;
+    case FMAX_d: set_dreg(fd, FPMax(dreg(fn), dreg(fm))); break;
+    case FMIN_s: set_sreg(fd, FPMin(sreg(fn), sreg(fm))); break;
+    case FMIN_d: set_dreg(fd, FPMin(dreg(fn), dreg(fm))); break;
+    case FMAXNM_s:
+    case FMAXNM_d:
+    case FMINNM_s:
+    case FMINNM_d:
+      // These were handled before the standard FPProcessNaNs() stage.
+      UNREACHABLE();
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::VisitFPDataProcessing3Source(Instruction* instr) {
+  AssertSupportedFPCR();
+
+  unsigned fd = instr->Rd();
+  unsigned fn = instr->Rn();
+  unsigned fm = instr->Rm();
+  unsigned fa = instr->Ra();
+
+  switch (instr->Mask(FPDataProcessing3SourceMask)) {
+    // fd = fa +/- (fn * fm)
+    case FMADD_s: set_sreg(fd, FPMulAdd(sreg(fa), sreg(fn), sreg(fm))); break;
+    case FMSUB_s: set_sreg(fd, FPMulAdd(sreg(fa), -sreg(fn), sreg(fm))); break;
+    case FMADD_d: set_dreg(fd, FPMulAdd(dreg(fa), dreg(fn), dreg(fm))); break;
+    case FMSUB_d: set_dreg(fd, FPMulAdd(dreg(fa), -dreg(fn), dreg(fm))); break;
+    // Negated variants of the above.
+    case FNMADD_s:
+      set_sreg(fd, FPMulAdd(-sreg(fa), -sreg(fn), sreg(fm)));
+      break;
+    case FNMSUB_s:
+      set_sreg(fd, FPMulAdd(-sreg(fa), sreg(fn), sreg(fm)));
+      break;
+    case FNMADD_d:
+      set_dreg(fd, FPMulAdd(-dreg(fa), -dreg(fn), dreg(fm)));
+      break;
+    case FNMSUB_d:
+      set_dreg(fd, FPMulAdd(-dreg(fa), dreg(fn), dreg(fm)));
+      break;
+    default: UNIMPLEMENTED();
+  }
+}
+
+
+template <typename T>
+T Simulator::FPAdd(T op1, T op2) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(op1) && !std::isnan(op2));
+
+  if (std::isinf(op1) && std::isinf(op2) && (op1 != op2)) {
+    // inf + -inf returns the default NaN.
+    return FPDefaultNaN<T>();
+  } else {
+    // Other cases should be handled by standard arithmetic.
+    return op1 + op2;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPDiv(T op1, T op2) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(op1) && !std::isnan(op2));
+
+  if ((std::isinf(op1) && std::isinf(op2)) || ((op1 == 0.0) && (op2 == 0.0))) {
+    // inf / inf and 0.0 / 0.0 return the default NaN.
+    return FPDefaultNaN<T>();
+  } else {
+    // Other cases should be handled by standard arithmetic.
+    return op1 / op2;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPMax(T a, T b) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(a) && !std::isnan(b));
+
+  if ((a == 0.0) && (b == 0.0) &&
+      (copysign(1.0, a) != copysign(1.0, b))) {
+    // a and b are zero, and the sign differs: return +0.0.
+    return 0.0;
+  } else {
+    return (a > b) ? a : b;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPMaxNM(T a, T b) {
+  if (IsQuietNaN(a) && !IsQuietNaN(b)) {
+    a = kFP64NegativeInfinity;
+  } else if (!IsQuietNaN(a) && IsQuietNaN(b)) {
+    b = kFP64NegativeInfinity;
+  }
+
+  T result = FPProcessNaNs(a, b);
+  return std::isnan(result) ? result : FPMax(a, b);
+}
+
+template <typename T>
+T Simulator::FPMin(T a, T b) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(a) && !std::isnan(b));
+
+  if ((a == 0.0) && (b == 0.0) &&
+      (copysign(1.0, a) != copysign(1.0, b))) {
+    // a and b are zero, and the sign differs: return -0.0.
+    return -0.0;
+  } else {
+    return (a < b) ? a : b;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPMinNM(T a, T b) {
+  if (IsQuietNaN(a) && !IsQuietNaN(b)) {
+    a = kFP64PositiveInfinity;
+  } else if (!IsQuietNaN(a) && IsQuietNaN(b)) {
+    b = kFP64PositiveInfinity;
+  }
+
+  T result = FPProcessNaNs(a, b);
+  return std::isnan(result) ? result : FPMin(a, b);
+}
+
+
+template <typename T>
+T Simulator::FPMul(T op1, T op2) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(op1) && !std::isnan(op2));
+
+  if ((std::isinf(op1) && (op2 == 0.0)) || (std::isinf(op2) && (op1 == 0.0))) {
+    // inf * 0.0 returns the default NaN.
+    return FPDefaultNaN<T>();
+  } else {
+    // Other cases should be handled by standard arithmetic.
+    return op1 * op2;
+  }
+}
+
+
+template<typename T>
+T Simulator::FPMulAdd(T a, T op1, T op2) {
+  T result = FPProcessNaNs3(a, op1, op2);
+
+  T sign_a = copysign(1.0, a);
+  T sign_prod = copysign(1.0, op1) * copysign(1.0, op2);
+  bool isinf_prod = std::isinf(op1) || std::isinf(op2);
+  bool operation_generates_nan =
+      (std::isinf(op1) && (op2 == 0.0)) ||                      // inf * 0.0
+      (std::isinf(op2) && (op1 == 0.0)) ||                      // 0.0 * inf
+      (std::isinf(a) && isinf_prod && (sign_a != sign_prod));   // inf - inf
+
+  if (std::isnan(result)) {
+    // Generated NaNs override quiet NaNs propagated from a.
+    if (operation_generates_nan && IsQuietNaN(a)) {
+      return FPDefaultNaN<T>();
+    } else {
+      return result;
+    }
+  }
+
+  // If the operation would produce a NaN, return the default NaN.
+  if (operation_generates_nan) {
+    return FPDefaultNaN<T>();
+  }
+
+  // Work around broken fma implementations for exact zero results: The sign of
+  // exact 0.0 results is positive unless both a and op1 * op2 are negative.
+  if (((op1 == 0.0) || (op2 == 0.0)) && (a == 0.0)) {
+    return ((sign_a < 0) && (sign_prod < 0)) ? -0.0 : 0.0;
+  }
+
+  result = FusedMultiplyAdd(op1, op2, a);
+  DCHECK(!std::isnan(result));
+
+  // Work around broken fma implementations for rounded zero results: If a is
+  // 0.0, the sign of the result is the sign of op1 * op2 before rounding.
+  if ((a == 0.0) && (result == 0.0)) {
+    return copysign(0.0, sign_prod);
+  }
+
+  return result;
+}
+
+
+template <typename T>
+T Simulator::FPSqrt(T op) {
+  if (std::isnan(op)) {
+    return FPProcessNaN(op);
+  } else if (op < 0.0) {
+    return FPDefaultNaN<T>();
+  } else {
+    return std::sqrt(op);
+  }
+}
+
+
+template <typename T>
+T Simulator::FPSub(T op1, T op2) {
+  // NaNs should be handled elsewhere.
+  DCHECK(!std::isnan(op1) && !std::isnan(op2));
+
+  if (std::isinf(op1) && std::isinf(op2) && (op1 == op2)) {
+    // inf - inf returns the default NaN.
+    return FPDefaultNaN<T>();
+  } else {
+    // Other cases should be handled by standard arithmetic.
+    return op1 - op2;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaN(T op) {
+  DCHECK(std::isnan(op));
+  return fpcr().DN() ? FPDefaultNaN<T>() : ToQuietNaN(op);
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaNs(T op1, T op2) {
+  if (IsSignallingNaN(op1)) {
+    return FPProcessNaN(op1);
+  } else if (IsSignallingNaN(op2)) {
+    return FPProcessNaN(op2);
+  } else if (std::isnan(op1)) {
+    DCHECK(IsQuietNaN(op1));
+    return FPProcessNaN(op1);
+  } else if (std::isnan(op2)) {
+    DCHECK(IsQuietNaN(op2));
+    return FPProcessNaN(op2);
+  } else {
+    return 0.0;
+  }
+}
+
+
+template <typename T>
+T Simulator::FPProcessNaNs3(T op1, T op2, T op3) {
+  if (IsSignallingNaN(op1)) {
+    return FPProcessNaN(op1);
+  } else if (IsSignallingNaN(op2)) {
+    return FPProcessNaN(op2);
+  } else if (IsSignallingNaN(op3)) {
+    return FPProcessNaN(op3);
+  } else if (std::isnan(op1)) {
+    DCHECK(IsQuietNaN(op1));
+    return FPProcessNaN(op1);
+  } else if (std::isnan(op2)) {
+    DCHECK(IsQuietNaN(op2));
+    return FPProcessNaN(op2);
+  } else if (std::isnan(op3)) {
+    DCHECK(IsQuietNaN(op3));
+    return FPProcessNaN(op3);
+  } else {
+    return 0.0;
+  }
+}
+
+
+bool Simulator::FPProcessNaNs(Instruction* instr) {
+  unsigned fd = instr->Rd();
+  unsigned fn = instr->Rn();
+  unsigned fm = instr->Rm();
+  bool done = false;
+
+  if (instr->Mask(FP64) == FP64) {
+    double result = FPProcessNaNs(dreg(fn), dreg(fm));
+    if (std::isnan(result)) {
+      set_dreg(fd, result);
+      done = true;
+    }
+  } else {
+    float result = FPProcessNaNs(sreg(fn), sreg(fm));
+    if (std::isnan(result)) {
+      set_sreg(fd, result);
+      done = true;
+    }
+  }
+
+  return done;
+}
+
+
+void Simulator::VisitSystem(Instruction* instr) {
+  // Some system instructions hijack their Op and Cp fields to represent a
+  // range of immediates instead of indicating a different instruction. This
+  // makes the decoding tricky.
+  if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
+    switch (instr->Mask(SystemSysRegMask)) {
+      case MRS: {
+        switch (instr->ImmSystemRegister()) {
+          case NZCV: set_xreg(instr->Rt(), nzcv().RawValue()); break;
+          case FPCR: set_xreg(instr->Rt(), fpcr().RawValue()); break;
+          default: UNIMPLEMENTED();
+        }
+        break;
+      }
+      case MSR: {
+        switch (instr->ImmSystemRegister()) {
+          case NZCV:
+            nzcv().SetRawValue(xreg(instr->Rt()));
+            LogSystemRegister(NZCV);
+            break;
+          case FPCR:
+            fpcr().SetRawValue(xreg(instr->Rt()));
+            LogSystemRegister(FPCR);
+            break;
+          default: UNIMPLEMENTED();
+        }
+        break;
+      }
+    }
+  } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
+    DCHECK(instr->Mask(SystemHintMask) == HINT);
+    switch (instr->ImmHint()) {
+      case NOP: break;
+      default: UNIMPLEMENTED();
+    }
+  } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
+    __sync_synchronize();
+  } else {
+    UNIMPLEMENTED();
+  }
+}
+
+
+bool Simulator::GetValue(const char* desc, int64_t* value) {
+  int regnum = CodeFromName(desc);
+  if (regnum >= 0) {
+    unsigned code = regnum;
+    if (code == kZeroRegCode) {
+      // Catch the zero register and return 0.
+      *value = 0;
+      return true;
+    } else if (code == kSPRegInternalCode) {
+      // Translate the stack pointer code to 31, for Reg31IsStackPointer.
+      code = 31;
+    }
+    if (desc[0] == 'w') {
+      *value = wreg(code, Reg31IsStackPointer);
+    } else {
+      *value = xreg(code, Reg31IsStackPointer);
+    }
+    return true;
+  } else if (strncmp(desc, "0x", 2) == 0) {
+    return SScanF(desc + 2, "%" SCNx64,
+                  reinterpret_cast<uint64_t*>(value)) == 1;
+  } else {
+    return SScanF(desc, "%" SCNu64,
+                  reinterpret_cast<uint64_t*>(value)) == 1;
+  }
+}
+
+
+bool Simulator::PrintValue(const char* desc) {
+  if (strcmp(desc, "csp") == 0) {
+    DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
+    PrintF(stream_, "%s csp:%s 0x%016" PRIx64 "%s\n",
+        clr_reg_name, clr_reg_value, xreg(31, Reg31IsStackPointer), clr_normal);
+    return true;
+  } else if (strcmp(desc, "wcsp") == 0) {
+    DCHECK(CodeFromName(desc) == static_cast<int>(kSPRegInternalCode));
+    PrintF(stream_, "%s wcsp:%s 0x%08" PRIx32 "%s\n",
+        clr_reg_name, clr_reg_value, wreg(31, Reg31IsStackPointer), clr_normal);
+    return true;
+  }
+
+  int i = CodeFromName(desc);
+  STATIC_ASSERT(kNumberOfRegisters == kNumberOfFPRegisters);
+  if (i < 0 || static_cast<unsigned>(i) >= kNumberOfFPRegisters) return false;
+
+  if (desc[0] == 'v') {
+    PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n",
+        clr_fpreg_name, VRegNameForCode(i),
+        clr_fpreg_value, double_to_rawbits(dreg(i)),
+        clr_normal,
+        clr_fpreg_name, DRegNameForCode(i),
+        clr_fpreg_value, dreg(i),
+        clr_fpreg_name, SRegNameForCode(i),
+        clr_fpreg_value, sreg(i),
+        clr_normal);
+    return true;
+  } else if (desc[0] == 'd') {
+    PrintF(stream_, "%s %s:%s %g%s\n",
+        clr_fpreg_name, DRegNameForCode(i),
+        clr_fpreg_value, dreg(i),
+        clr_normal);
+    return true;
+  } else if (desc[0] == 's') {
+    PrintF(stream_, "%s %s:%s %g%s\n",
+        clr_fpreg_name, SRegNameForCode(i),
+        clr_fpreg_value, sreg(i),
+        clr_normal);
+    return true;
+  } else if (desc[0] == 'w') {
+    PrintF(stream_, "%s %s:%s 0x%08" PRIx32 "%s\n",
+        clr_reg_name, WRegNameForCode(i), clr_reg_value, wreg(i), clr_normal);
+    return true;
+  } else {
+    // X register names have a wide variety of starting characters, but anything
+    // else will be an X register.
+    PrintF(stream_, "%s %s:%s 0x%016" PRIx64 "%s\n",
+        clr_reg_name, XRegNameForCode(i), clr_reg_value, xreg(i), clr_normal);
+    return true;
+  }
+}
+
+
+void Simulator::Debug() {
+#define COMMAND_SIZE 63
+#define ARG_SIZE 255
+
+#define STR(a) #a
+#define XSTR(a) STR(a)
+
+  char cmd[COMMAND_SIZE + 1];
+  char arg1[ARG_SIZE + 1];
+  char arg2[ARG_SIZE + 1];
+  char* argv[3] = { cmd, arg1, arg2 };
+
+  // Make sure to have a proper terminating character if reaching the limit.
+  cmd[COMMAND_SIZE] = 0;
+  arg1[ARG_SIZE] = 0;
+  arg2[ARG_SIZE] = 0;
+
+  bool done = false;
+  bool cleared_log_disasm_bit = false;
+
+  while (!done) {
+    // Disassemble the next instruction to execute before doing anything else.
+    PrintInstructionsAt(pc_, 1);
+    // Read the command line.
+    char* line = ReadLine("sim> ");
+    if (line == NULL) {
+      break;
+    } else {
+      // Repeat last command by default.
+      char* last_input = last_debugger_input();
+      if (strcmp(line, "\n") == 0 && (last_input != NULL)) {
+        DeleteArray(line);
+        line = last_input;
+      } else {
+        // Update the latest command ran
+        set_last_debugger_input(line);
+      }
+
+      // Use sscanf to parse the individual parts of the command line. At the
+      // moment no command expects more than two parameters.
+      int argc = SScanF(line,
+                        "%" XSTR(COMMAND_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s "
+                        "%" XSTR(ARG_SIZE) "s",
+                        cmd, arg1, arg2);
+
+      // stepi / si ------------------------------------------------------------
+      if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
+        // We are about to execute instructions, after which by default we
+        // should increment the pc_. If it was set when reaching this debug
+        // instruction, it has not been cleared because this instruction has not
+        // completed yet. So clear it manually.
+        pc_modified_ = false;
+
+        if (argc == 1) {
+          ExecuteInstruction();
+        } else {
+          int64_t number_of_instructions_to_execute = 1;
+          GetValue(arg1, &number_of_instructions_to_execute);
+
+          set_log_parameters(log_parameters() | LOG_DISASM);
+          while (number_of_instructions_to_execute-- > 0) {
+            ExecuteInstruction();
+          }
+          set_log_parameters(log_parameters() & ~LOG_DISASM);
+          PrintF("\n");
+        }
+
+        // If it was necessary, the pc has already been updated or incremented
+        // when executing the instruction. So we do not want it to be updated
+        // again. It will be cleared when exiting.
+        pc_modified_ = true;
+
+      // next / n --------------------------------------------------------------
+      } else if ((strcmp(cmd, "next") == 0) || (strcmp(cmd, "n") == 0)) {
+        // Tell the simulator to break after the next executed BL.
+        break_on_next_ = true;
+        // Continue.
+        done = true;
+
+      // continue / cont / c ---------------------------------------------------
+      } else if ((strcmp(cmd, "continue") == 0) ||
+                 (strcmp(cmd, "cont") == 0) ||
+                 (strcmp(cmd, "c") == 0)) {
+        // Leave the debugger shell.
+        done = true;
+
+      // disassemble / disasm / di ---------------------------------------------
+      } else if (strcmp(cmd, "disassemble") == 0 ||
+                 strcmp(cmd, "disasm") == 0 ||
+                 strcmp(cmd, "di") == 0) {
+        int64_t n_of_instrs_to_disasm = 10;  // default value.
+        int64_t address = reinterpret_cast<int64_t>(pc_);  // default value.
+        if (argc >= 2) {  // disasm <n of instrs>
+          GetValue(arg1, &n_of_instrs_to_disasm);
+        }
+        if (argc >= 3) {  // disasm <n of instrs> <address>
+          GetValue(arg2, &address);
+        }
+
+        // Disassemble.
+        PrintInstructionsAt(reinterpret_cast<Instruction*>(address),
+                            n_of_instrs_to_disasm);
+        PrintF("\n");
+
+      // print / p -------------------------------------------------------------
+      } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) {
+        if (argc == 2) {
+          if (strcmp(arg1, "all") == 0) {
+            PrintRegisters();
+            PrintFPRegisters();
+          } else {
+            if (!PrintValue(arg1)) {
+              PrintF("%s unrecognized\n", arg1);
+            }
+          }
+        } else {
+          PrintF(
+            "print <register>\n"
+            "    Print the content of a register. (alias 'p')\n"
+            "    'print all' will print all registers.\n"
+            "    Use 'printobject' to get more details about the value.\n");
+        }
+
+      // printobject / po ------------------------------------------------------
+      } else if ((strcmp(cmd, "printobject") == 0) ||
+                 (strcmp(cmd, "po") == 0)) {
+        if (argc == 2) {
+          int64_t value;
+          OFStream os(stdout);
+          if (GetValue(arg1, &value)) {
+            Object* obj = reinterpret_cast<Object*>(value);
+            os << arg1 << ": \n";
+#ifdef DEBUG
+            obj->Print(os);
+            os << "\n";
+#else
+            os << Brief(obj) << "\n";
+#endif
+          } else {
+            os << arg1 << " unrecognized\n";
+          }
+        } else {
+          PrintF("printobject <value>\n"
+                 "printobject <register>\n"
+                 "    Print details about the value. (alias 'po')\n");
+        }
+
+      // stack / mem ----------------------------------------------------------
+      } else if (strcmp(cmd, "stack") == 0 || strcmp(cmd, "mem") == 0) {
+        int64_t* cur = NULL;
+        int64_t* end = NULL;
+        int next_arg = 1;
+
+        if (strcmp(cmd, "stack") == 0) {
+          cur = reinterpret_cast<int64_t*>(jssp());
+
+        } else {  // "mem"
+          int64_t value;
+          if (!GetValue(arg1, &value)) {
+            PrintF("%s unrecognized\n", arg1);
+            continue;
+          }
+          cur = reinterpret_cast<int64_t*>(value);
+          next_arg++;
+        }
+
+        int64_t words = 0;
+        if (argc == next_arg) {
+          words = 10;
+        } else if (argc == next_arg + 1) {
+          if (!GetValue(argv[next_arg], &words)) {
+            PrintF("%s unrecognized\n", argv[next_arg]);
+            PrintF("Printing 10 double words by default");
+            words = 10;
+          }
+        } else {
+          UNREACHABLE();
+        }
+        end = cur + words;
+
+        while (cur < end) {
+          PrintF("  0x%016" PRIx64 ":  0x%016" PRIx64 " %10" PRId64,
+                 reinterpret_cast<uint64_t>(cur), *cur, *cur);
+          HeapObject* obj = reinterpret_cast<HeapObject*>(*cur);
+          int64_t value = *cur;
+          Heap* current_heap = v8::internal::Isolate::Current()->heap();
+          if (((value & 1) == 0) || current_heap->Contains(obj)) {
+            PrintF(" (");
+            if ((value & kSmiTagMask) == 0) {
+              STATIC_ASSERT(kSmiValueSize == 32);
+              int32_t untagged = (value >> kSmiShift) & 0xffffffff;
+              PrintF("smi %" PRId32, untagged);
+            } else {
+              obj->ShortPrint();
+            }
+            PrintF(")");
+          }
+          PrintF("\n");
+          cur++;
+        }
+
+      // trace / t -------------------------------------------------------------
+      } else if (strcmp(cmd, "trace") == 0 || strcmp(cmd, "t") == 0) {
+        if ((log_parameters() & (LOG_DISASM | LOG_REGS)) !=
+            (LOG_DISASM | LOG_REGS)) {
+          PrintF("Enabling disassembly and registers tracing\n");
+          set_log_parameters(log_parameters() | LOG_DISASM | LOG_REGS);
+        } else {
+          PrintF("Disabling disassembly and registers tracing\n");
+          set_log_parameters(log_parameters() & ~(LOG_DISASM | LOG_REGS));
+        }
+
+      // break / b -------------------------------------------------------------
+      } else if (strcmp(cmd, "break") == 0 || strcmp(cmd, "b") == 0) {
+        if (argc == 2) {
+          int64_t value;
+          if (GetValue(arg1, &value)) {
+            SetBreakpoint(reinterpret_cast<Instruction*>(value));
+          } else {
+            PrintF("%s unrecognized\n", arg1);
+          }
+        } else {
+          ListBreakpoints();
+          PrintF("Use `break <address>` to set or disable a breakpoint\n");
+        }
+
+      // gdb -------------------------------------------------------------------
+      } else if (strcmp(cmd, "gdb") == 0) {
+        PrintF("Relinquishing control to gdb.\n");
+        base::OS::DebugBreak();
+        PrintF("Regaining control from gdb.\n");
+
+      // sysregs ---------------------------------------------------------------
+      } else if (strcmp(cmd, "sysregs") == 0) {
+        PrintSystemRegisters();
+
+      // help / h --------------------------------------------------------------
+      } else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "h") == 0) {
+        PrintF(
+          "stepi / si\n"
+          "    stepi <n>\n"
+          "    Step <n> instructions.\n"
+          "next / n\n"
+          "    Continue execution until a BL instruction is reached.\n"
+          "    At this point a breakpoint is set just after this BL.\n"
+          "    Then execution is resumed. It will probably later hit the\n"
+          "    breakpoint just set.\n"
+          "continue / cont / c\n"
+          "    Continue execution from here.\n"
+          "disassemble / disasm / di\n"
+          "    disassemble <n> <address>\n"
+          "    Disassemble <n> instructions from current <address>.\n"
+          "    By default <n> is 20 and <address> is the current pc.\n"
+          "print / p\n"
+          "    print <register>\n"
+          "    Print the content of a register.\n"
+          "    'print all' will print all registers.\n"
+          "    Use 'printobject' to get more details about the value.\n"
+          "printobject / po\n"
+          "    printobject <value>\n"
+          "    printobject <register>\n"
+          "    Print details about the value.\n"
+          "stack\n"
+          "    stack [<words>]\n"
+          "    Dump stack content, default dump 10 words\n"
+          "mem\n"
+          "    mem <address> [<words>]\n"
+          "    Dump memory content, default dump 10 words\n"
+          "trace / t\n"
+          "    Toggle disassembly and register tracing\n"
+          "break / b\n"
+          "    break : list all breakpoints\n"
+          "    break <address> : set / enable / disable a breakpoint.\n"
+          "gdb\n"
+          "    Enter gdb.\n"
+          "sysregs\n"
+          "    Print all system registers (including NZCV).\n");
+      } else {
+        PrintF("Unknown command: %s\n", cmd);
+        PrintF("Use 'help' for more information.\n");
+      }
+    }
+    if (cleared_log_disasm_bit == true) {
+      set_log_parameters(log_parameters_ | LOG_DISASM);
+    }
+  }
+}
+
+
+void Simulator::VisitException(Instruction* instr) {
+  switch (instr->Mask(ExceptionMask)) {
+    case HLT: {
+      if (instr->ImmException() == kImmExceptionIsDebug) {
+        // Read the arguments encoded inline in the instruction stream.
+        uint32_t code;
+        uint32_t parameters;
+
+        memcpy(&code,
+               pc_->InstructionAtOffset(kDebugCodeOffset),
+               sizeof(code));
+        memcpy(&parameters,
+               pc_->InstructionAtOffset(kDebugParamsOffset),
+               sizeof(parameters));
+        char const *message =
+            reinterpret_cast<char const*>(
+                pc_->InstructionAtOffset(kDebugMessageOffset));
+
+        // Always print something when we hit a debug point that breaks.
+        // We are going to break, so printing something is not an issue in
+        // terms of speed.
+        if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) {
+          if (message != NULL) {
+            PrintF(stream_,
+                   "# %sDebugger hit %d: %s%s%s\n",
+                   clr_debug_number,
+                   code,
+                   clr_debug_message,
+                   message,
+                   clr_normal);
+          } else {
+            PrintF(stream_,
+                   "# %sDebugger hit %d.%s\n",
+                   clr_debug_number,
+                   code,
+                   clr_normal);
+          }
+        }
+
+        // Other options.
+        switch (parameters & kDebuggerTracingDirectivesMask) {
+          case TRACE_ENABLE:
+            set_log_parameters(log_parameters() | parameters);
+            if (parameters & LOG_SYS_REGS) { PrintSystemRegisters(); }
+            if (parameters & LOG_REGS) { PrintRegisters(); }
+            if (parameters & LOG_FP_REGS) { PrintFPRegisters(); }
+            break;
+          case TRACE_DISABLE:
+            set_log_parameters(log_parameters() & ~parameters);
+            break;
+          case TRACE_OVERRIDE:
+            set_log_parameters(parameters);
+            break;
+          default:
+            // We don't support a one-shot LOG_DISASM.
+            DCHECK((parameters & LOG_DISASM) == 0);
+            // Don't print information that is already being traced.
+            parameters &= ~log_parameters();
+            // Print the requested information.
+            if (parameters & LOG_SYS_REGS) PrintSystemRegisters();
+            if (parameters & LOG_REGS) PrintRegisters();
+            if (parameters & LOG_FP_REGS) PrintFPRegisters();
+        }
+
+        // The stop parameters are inlined in the code. Skip them:
+        //  - Skip to the end of the message string.
+        size_t size = kDebugMessageOffset + strlen(message) + 1;
+        pc_ = pc_->InstructionAtOffset(RoundUp(size, kInstructionSize));
+        //  - Verify that the unreachable marker is present.
+        DCHECK(pc_->Mask(ExceptionMask) == HLT);
+        DCHECK(pc_->ImmException() ==  kImmExceptionIsUnreachable);
+        //  - Skip past the unreachable marker.
+        set_pc(pc_->following());
+
+        // Check if the debugger should break.
+        if (parameters & BREAK) Debug();
+
+      } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) {
+        DoRuntimeCall(instr);
+      } else if (instr->ImmException() == kImmExceptionIsPrintf) {
+        DoPrintf(instr);
+
+      } else if (instr->ImmException() == kImmExceptionIsUnreachable) {
+        fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n",
+                reinterpret_cast<void*>(pc_));
+        abort();
+
+      } else {
+        base::OS::DebugBreak();
+      }
+      break;
+    }
+
+    default:
+      UNIMPLEMENTED();
+  }
+}
+
+
+void Simulator::DoPrintf(Instruction* instr) {
+  DCHECK((instr->Mask(ExceptionMask) == HLT) &&
+              (instr->ImmException() == kImmExceptionIsPrintf));
+
+  // Read the arguments encoded inline in the instruction stream.
+  uint32_t arg_count;
+  uint32_t arg_pattern_list;
+  STATIC_ASSERT(sizeof(*instr) == 1);
+  memcpy(&arg_count,
+         instr + kPrintfArgCountOffset,
+         sizeof(arg_count));
+  memcpy(&arg_pattern_list,
+         instr + kPrintfArgPatternListOffset,
+         sizeof(arg_pattern_list));
+
+  DCHECK(arg_count <= kPrintfMaxArgCount);
+  DCHECK((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0);
+
+  // We need to call the host printf function with a set of arguments defined by
+  // arg_pattern_list. Because we don't know the types and sizes of the
+  // arguments, this is very difficult to do in a robust and portable way. To
+  // work around the problem, we pick apart the format string, and print one
+  // format placeholder at a time.
+
+  // Allocate space for the format string. We take a copy, so we can modify it.
+  // Leave enough space for one extra character per expected argument (plus the
+  // '\0' termination).
+  const char * format_base = reg<const char *>(0);
+  DCHECK(format_base != NULL);
+  size_t length = strlen(format_base) + 1;
+  char * const format = new char[length + arg_count];
+
+  // A list of chunks, each with exactly one format placeholder.
+  const char * chunks[kPrintfMaxArgCount];
+
+  // Copy the format string and search for format placeholders.
+  uint32_t placeholder_count = 0;
+  char * format_scratch = format;
+  for (size_t i = 0; i < length; i++) {
+    if (format_base[i] != '%') {
+      *format_scratch++ = format_base[i];
+    } else {
+      if (format_base[i + 1] == '%') {
+        // Ignore explicit "%%" sequences.
+        *format_scratch++ = format_base[i];
+
+        if (placeholder_count == 0) {
+          // The first chunk is passed to printf using "%s", so we need to
+          // unescape "%%" sequences in this chunk. (Just skip the next '%'.)
+          i++;
+        } else {
+          // Otherwise, pass through "%%" unchanged.
+          *format_scratch++ = format_base[++i];
+        }
+      } else {
+        CHECK(placeholder_count < arg_count);
+        // Insert '\0' before placeholders, and store their locations.
+        *format_scratch++ = '\0';
+        chunks[placeholder_count++] = format_scratch;
+        *format_scratch++ = format_base[i];
+      }
+    }
+  }
+  DCHECK(format_scratch <= (format + length + arg_count));
+  CHECK(placeholder_count == arg_count);
+
+  // Finally, call printf with each chunk, passing the appropriate register
+  // argument. Normally, printf returns the number of bytes transmitted, so we
+  // can emulate a single printf call by adding the result from each chunk. If
+  // any call returns a negative (error) value, though, just return that value.
+
+  fprintf(stream_, "%s", clr_printf);
+
+  // Because '\0' is inserted before each placeholder, the first string in
+  // 'format' contains no format placeholders and should be printed literally.
+  int result = fprintf(stream_, "%s", format);
+  int pcs_r = 1;      // Start at x1. x0 holds the format string.
+  int pcs_f = 0;      // Start at d0.
+  if (result >= 0) {
+    for (uint32_t i = 0; i < placeholder_count; i++) {
+      int part_result = -1;
+
+      uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits);
+      arg_pattern &= (1 << kPrintfArgPatternBits) - 1;
+      switch (arg_pattern) {
+        case kPrintfArgW:
+          part_result = fprintf(stream_, chunks[i], wreg(pcs_r++));
+          break;
+        case kPrintfArgX:
+          part_result = fprintf(stream_, chunks[i], xreg(pcs_r++));
+          break;
+        case kPrintfArgD:
+          part_result = fprintf(stream_, chunks[i], dreg(pcs_f++));
+          break;
+        default: UNREACHABLE();
+      }
+
+      if (part_result < 0) {
+        // Handle error values.
+        result = part_result;
+        break;
+      }
+
+      result += part_result;
+    }
+  }
+
+  fprintf(stream_, "%s", clr_normal);
+
+#ifdef DEBUG
+  CorruptAllCallerSavedCPURegisters();
+#endif
+
+  // Printf returns its result in x0 (just like the C library's printf).
+  set_xreg(0, result);
+
+  // The printf parameters are inlined in the code, so skip them.
+  set_pc(instr->InstructionAtOffset(kPrintfLength));
+
+  // Set LR as if we'd just called a native printf function.
+  set_lr(pc());
+
+  delete[] format;
+}
+
+
+#endif  // USE_SIMULATOR
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/simulator-arm64.h b/src/arm64/simulator-arm64.h
new file mode 100644
index 0000000..108f6f2
--- /dev/null
+++ b/src/arm64/simulator-arm64.h
@@ -0,0 +1,917 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_SIMULATOR_ARM64_H_
+#define V8_ARM64_SIMULATOR_ARM64_H_
+
+#include <stdarg.h>
+#include <vector>
+
+#include "src/v8.h"
+
+#include "src/allocation.h"
+#include "src/arm64/assembler-arm64.h"
+#include "src/arm64/decoder-arm64.h"
+#include "src/arm64/disasm-arm64.h"
+#include "src/arm64/instrument-arm64.h"
+#include "src/assembler.h"
+#include "src/globals.h"
+#include "src/utils.h"
+
+#define REGISTER_CODE_LIST(R)                                                  \
+R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                                 \
+R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                                \
+R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                                \
+R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
+
+namespace v8 {
+namespace internal {
+
+#if !defined(USE_SIMULATOR)
+
+// Running without a simulator on a native ARM64 platform.
+// When running without a simulator we call the entry directly.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  (entry(p0, p1, p2, p3, p4))
+
+typedef int (*arm64_regexp_matcher)(String* input,
+                                    int64_t start_offset,
+                                    const byte* input_start,
+                                    const byte* input_end,
+                                    int* output,
+                                    int64_t output_size,
+                                    Address stack_base,
+                                    int64_t direct_call,
+                                    void* return_address,
+                                    Isolate* isolate);
+
+// Call the generated regexp code directly. The code at the entry address
+// should act as a function matching the type arm64_regexp_matcher.
+// The ninth argument is a dummy that reserves the space used for
+// the return address added by the ExitFrame in native calls.
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8) \
+  (FUNCTION_CAST<arm64_regexp_matcher>(entry)(                                \
+      p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8))
+
+// Running without a simulator there is nothing to do.
+class SimulatorStack : public v8::internal::AllStatic {
+ public:
+  static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    USE(isolate);
+    return c_limit;
+  }
+
+  static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
+    return try_catch_address;
+  }
+
+  static void UnregisterCTryCatch() { }
+};
+
+#else  // !defined(USE_SIMULATOR)
+
+enum ReverseByteMode {
+  Reverse16 = 0,
+  Reverse32 = 1,
+  Reverse64 = 2
+};
+
+
+// The proper way to initialize a simulated system register (such as NZCV) is as
+// follows:
+//  SimSystemRegister nzcv = SimSystemRegister::DefaultValueFor(NZCV);
+class SimSystemRegister {
+ public:
+  // The default constructor represents a register which has no writable bits.
+  // It is not possible to set its value to anything other than 0.
+  SimSystemRegister() : value_(0), write_ignore_mask_(0xffffffff) { }
+
+  uint32_t RawValue() const {
+    return value_;
+  }
+
+  void SetRawValue(uint32_t new_value) {
+    value_ = (value_ & write_ignore_mask_) | (new_value & ~write_ignore_mask_);
+  }
+
+  uint32_t Bits(int msb, int lsb) const {
+    return unsigned_bitextract_32(msb, lsb, value_);
+  }
+
+  int32_t SignedBits(int msb, int lsb) const {
+    return signed_bitextract_32(msb, lsb, value_);
+  }
+
+  void SetBits(int msb, int lsb, uint32_t bits);
+
+  // Default system register values.
+  static SimSystemRegister DefaultValueFor(SystemRegister id);
+
+#define DEFINE_GETTER(Name, HighBit, LowBit, Func, Type)                       \
+  Type Name() const { return static_cast<Type>(Func(HighBit, LowBit)); }       \
+  void Set##Name(Type bits) {                                                  \
+    SetBits(HighBit, LowBit, static_cast<Type>(bits));                         \
+  }
+#define DEFINE_WRITE_IGNORE_MASK(Name, Mask)                                   \
+  static const uint32_t Name##WriteIgnoreMask = ~static_cast<uint32_t>(Mask);
+  SYSTEM_REGISTER_FIELDS_LIST(DEFINE_GETTER, DEFINE_WRITE_IGNORE_MASK)
+#undef DEFINE_ZERO_BITS
+#undef DEFINE_GETTER
+
+ protected:
+  // Most system registers only implement a few of the bits in the word. Other
+  // bits are "read-as-zero, write-ignored". The write_ignore_mask argument
+  // describes the bits which are not modifiable.
+  SimSystemRegister(uint32_t value, uint32_t write_ignore_mask)
+      : value_(value), write_ignore_mask_(write_ignore_mask) { }
+
+  uint32_t value_;
+  uint32_t write_ignore_mask_;
+};
+
+
+// Represent a register (r0-r31, v0-v31).
+class SimRegisterBase {
+ public:
+  template<typename T>
+  void Set(T new_value) {
+    value_ = 0;
+    memcpy(&value_, &new_value, sizeof(T));
+  }
+
+  template<typename T>
+  T Get() const {
+    T result;
+    memcpy(&result, &value_, sizeof(T));
+    return result;
+  }
+
+ protected:
+  int64_t value_;
+};
+
+
+typedef SimRegisterBase SimRegister;      // r0-r31
+typedef SimRegisterBase SimFPRegister;    // v0-v31
+
+
+class Simulator : public DecoderVisitor {
+ public:
+  explicit Simulator(Decoder<DispatchingDecoderVisitor>* decoder,
+                     Isolate* isolate = NULL,
+                     FILE* stream = stderr);
+  Simulator();
+  ~Simulator();
+
+  // System functions.
+
+  static void Initialize(Isolate* isolate);
+
+  static Simulator* current(v8::internal::Isolate* isolate);
+
+  class CallArgument;
+
+  // Call an arbitrary function taking an arbitrary number of arguments. The
+  // varargs list must be a set of arguments with type CallArgument, and
+  // terminated by CallArgument::End().
+  void CallVoid(byte* entry, CallArgument* args);
+
+  // Like CallVoid, but expect a return value.
+  int64_t CallInt64(byte* entry, CallArgument* args);
+  double CallDouble(byte* entry, CallArgument* args);
+
+  // V8 calls into generated JS code with 5 parameters and into
+  // generated RegExp code with 10 parameters. These are convenience functions,
+  // which set up the simulator state and grab the result on return.
+  int64_t CallJS(byte* entry,
+                 byte* function_entry,
+                 JSFunction* func,
+                 Object* revc,
+                 int64_t argc,
+                 Object*** argv);
+  int64_t CallRegExp(byte* entry,
+                     String* input,
+                     int64_t start_offset,
+                     const byte* input_start,
+                     const byte* input_end,
+                     int* output,
+                     int64_t output_size,
+                     Address stack_base,
+                     int64_t direct_call,
+                     void* return_address,
+                     Isolate* isolate);
+
+  // A wrapper class that stores an argument for one of the above Call
+  // functions.
+  //
+  // Only arguments up to 64 bits in size are supported.
+  class CallArgument {
+   public:
+    template<typename T>
+    explicit CallArgument(T argument) {
+      bits_ = 0;
+      DCHECK(sizeof(argument) <= sizeof(bits_));
+      memcpy(&bits_, &argument, sizeof(argument));
+      type_ = X_ARG;
+    }
+
+    explicit CallArgument(double argument) {
+      DCHECK(sizeof(argument) == sizeof(bits_));
+      memcpy(&bits_, &argument, sizeof(argument));
+      type_ = D_ARG;
+    }
+
+    explicit CallArgument(float argument) {
+      // TODO(all): CallArgument(float) is untested, remove this check once
+      //            tested.
+      UNIMPLEMENTED();
+      // Make the D register a NaN to try to trap errors if the callee expects a
+      // double. If it expects a float, the callee should ignore the top word.
+      DCHECK(sizeof(kFP64SignallingNaN) == sizeof(bits_));
+      memcpy(&bits_, &kFP64SignallingNaN, sizeof(kFP64SignallingNaN));
+      // Write the float payload to the S register.
+      DCHECK(sizeof(argument) <= sizeof(bits_));
+      memcpy(&bits_, &argument, sizeof(argument));
+      type_ = D_ARG;
+    }
+
+    // This indicates the end of the arguments list, so that CallArgument
+    // objects can be passed into varargs functions.
+    static CallArgument End() { return CallArgument(); }
+
+    int64_t bits() const { return bits_; }
+    bool IsEnd() const { return type_ == NO_ARG; }
+    bool IsX() const { return type_ == X_ARG; }
+    bool IsD() const { return type_ == D_ARG; }
+
+   private:
+    enum CallArgumentType { X_ARG, D_ARG, NO_ARG };
+
+    // All arguments are aligned to at least 64 bits and we don't support
+    // passing bigger arguments, so the payload size can be fixed at 64 bits.
+    int64_t bits_;
+    CallArgumentType type_;
+
+    CallArgument() { type_ = NO_ARG; }
+  };
+
+
+  // Start the debugging command line.
+  void Debug();
+
+  bool GetValue(const char* desc, int64_t* value);
+
+  bool PrintValue(const char* desc);
+
+  // Push an address onto the JS stack.
+  uintptr_t PushAddress(uintptr_t address);
+
+  // Pop an address from the JS stack.
+  uintptr_t PopAddress();
+
+  // Accessor to the internal simulator stack area.
+  uintptr_t StackLimit() const;
+
+  void ResetState();
+
+  // Runtime call support.
+  static void* RedirectExternalReference(void* external_function,
+                                         ExternalReference::Type type);
+  void DoRuntimeCall(Instruction* instr);
+
+  // Run the simulator.
+  static const Instruction* kEndOfSimAddress;
+  void DecodeInstruction();
+  void Run();
+  void RunFrom(Instruction* start);
+
+  // Simulation helpers.
+  template <typename T>
+  void set_pc(T new_pc) {
+    DCHECK(sizeof(T) == sizeof(pc_));
+    memcpy(&pc_, &new_pc, sizeof(T));
+    pc_modified_ = true;
+  }
+  Instruction* pc() { return pc_; }
+
+  void increment_pc() {
+    if (!pc_modified_) {
+      pc_ = pc_->following();
+    }
+
+    pc_modified_ = false;
+  }
+
+  virtual void Decode(Instruction* instr) {
+    decoder_->Decode(instr);
+  }
+
+  void ExecuteInstruction() {
+    DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize));
+    CheckBreakNext();
+    Decode(pc_);
+    increment_pc();
+    CheckBreakpoints();
+  }
+
+  // Declare all Visitor functions.
+  #define DECLARE(A)  void Visit##A(Instruction* instr);
+  VISITOR_LIST(DECLARE)
+  #undef DECLARE
+
+  bool IsZeroRegister(unsigned code, Reg31Mode r31mode) const {
+    return ((code == 31) && (r31mode == Reg31IsZeroRegister));
+  }
+
+  // Register accessors.
+  // Return 'size' bits of the value of an integer register, as the specified
+  // type. The value is zero-extended to fill the result.
+  //
+  template<typename T>
+  T reg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
+    DCHECK(code < kNumberOfRegisters);
+    if (IsZeroRegister(code, r31mode)) {
+      return 0;
+    }
+    return registers_[code].Get<T>();
+  }
+
+  // Common specialized accessors for the reg() template.
+  int32_t wreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
+    return reg<int32_t>(code, r31mode);
+  }
+
+  int64_t xreg(unsigned code, Reg31Mode r31mode = Reg31IsZeroRegister) const {
+    return reg<int64_t>(code, r31mode);
+  }
+
+  // Write 'value' into an integer register. The value is zero-extended. This
+  // behaviour matches AArch64 register writes.
+  template<typename T>
+  void set_reg(unsigned code, T value,
+               Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg_no_log(code, value, r31mode);
+    LogRegister(code, r31mode);
+  }
+
+  // Common specialized accessors for the set_reg() template.
+  void set_wreg(unsigned code, int32_t value,
+                Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg(code, value, r31mode);
+  }
+
+  void set_xreg(unsigned code, int64_t value,
+                Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg(code, value, r31mode);
+  }
+
+  // As above, but don't automatically log the register update.
+  template <typename T>
+  void set_reg_no_log(unsigned code, T value,
+                      Reg31Mode r31mode = Reg31IsZeroRegister) {
+    DCHECK(code < kNumberOfRegisters);
+    if (!IsZeroRegister(code, r31mode)) {
+      registers_[code].Set(value);
+    }
+  }
+
+  void set_wreg_no_log(unsigned code, int32_t value,
+                       Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg_no_log(code, value, r31mode);
+  }
+
+  void set_xreg_no_log(unsigned code, int64_t value,
+                       Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg_no_log(code, value, r31mode);
+  }
+
+  // Commonly-used special cases.
+  template<typename T>
+  void set_lr(T value) {
+    DCHECK(sizeof(T) == kPointerSize);
+    set_reg(kLinkRegCode, value);
+  }
+
+  template<typename T>
+  void set_sp(T value) {
+    DCHECK(sizeof(T) == kPointerSize);
+    set_reg(31, value, Reg31IsStackPointer);
+  }
+
+  int64_t sp() { return xreg(31, Reg31IsStackPointer); }
+  int64_t jssp() { return xreg(kJSSPCode, Reg31IsStackPointer); }
+  int64_t fp() {
+      return xreg(kFramePointerRegCode, Reg31IsStackPointer);
+  }
+  Instruction* lr() { return reg<Instruction*>(kLinkRegCode); }
+
+  Address get_sp() { return reg<Address>(31, Reg31IsStackPointer); }
+
+  template<typename T>
+  T fpreg(unsigned code) const {
+    DCHECK(code < kNumberOfRegisters);
+    return fpregisters_[code].Get<T>();
+  }
+
+  // Common specialized accessors for the fpreg() template.
+  float sreg(unsigned code) const {
+    return fpreg<float>(code);
+  }
+
+  uint32_t sreg_bits(unsigned code) const {
+    return fpreg<uint32_t>(code);
+  }
+
+  double dreg(unsigned code) const {
+    return fpreg<double>(code);
+  }
+
+  uint64_t dreg_bits(unsigned code) const {
+    return fpreg<uint64_t>(code);
+  }
+
+  double fpreg(unsigned size, unsigned code) const {
+    switch (size) {
+      case kSRegSizeInBits: return sreg(code);
+      case kDRegSizeInBits: return dreg(code);
+      default:
+        UNREACHABLE();
+        return 0.0;
+    }
+  }
+
+  // Write 'value' into a floating-point register. The value is zero-extended.
+  // This behaviour matches AArch64 register writes.
+  template<typename T>
+  void set_fpreg(unsigned code, T value) {
+    set_fpreg_no_log(code, value);
+
+    if (sizeof(value) <= kSRegSize) {
+      LogFPRegister(code, kPrintSRegValue);
+    } else {
+      LogFPRegister(code, kPrintDRegValue);
+    }
+  }
+
+  // Common specialized accessors for the set_fpreg() template.
+  void set_sreg(unsigned code, float value) {
+    set_fpreg(code, value);
+  }
+
+  void set_sreg_bits(unsigned code, uint32_t value) {
+    set_fpreg(code, value);
+  }
+
+  void set_dreg(unsigned code, double value) {
+    set_fpreg(code, value);
+  }
+
+  void set_dreg_bits(unsigned code, uint64_t value) {
+    set_fpreg(code, value);
+  }
+
+  // As above, but don't automatically log the register update.
+  template <typename T>
+  void set_fpreg_no_log(unsigned code, T value) {
+    DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
+    DCHECK(code < kNumberOfFPRegisters);
+    fpregisters_[code].Set(value);
+  }
+
+  void set_sreg_no_log(unsigned code, float value) {
+    set_fpreg_no_log(code, value);
+  }
+
+  void set_dreg_no_log(unsigned code, double value) {
+    set_fpreg_no_log(code, value);
+  }
+
+  SimSystemRegister& nzcv() { return nzcv_; }
+  SimSystemRegister& fpcr() { return fpcr_; }
+
+  // Debug helpers
+
+  // Simulator breakpoints.
+  struct Breakpoint {
+    Instruction* location;
+    bool enabled;
+  };
+  std::vector<Breakpoint> breakpoints_;
+  void SetBreakpoint(Instruction* breakpoint);
+  void ListBreakpoints();
+  void CheckBreakpoints();
+
+  // Helpers for the 'next' command.
+  // When this is set, the Simulator will insert a breakpoint after the next BL
+  // instruction it meets.
+  bool break_on_next_;
+  // Check if the Simulator should insert a break after the current instruction
+  // for the 'next' command.
+  void CheckBreakNext();
+
+  // Disassemble instruction at the given address.
+  void PrintInstructionsAt(Instruction* pc, uint64_t count);
+
+  // Print all registers of the specified types.
+  void PrintRegisters();
+  void PrintFPRegisters();
+  void PrintSystemRegisters();
+
+  // Like Print* (above), but respect log_parameters().
+  void LogSystemRegisters() {
+    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegisters();
+  }
+  void LogRegisters() {
+    if (log_parameters() & LOG_REGS) PrintRegisters();
+  }
+  void LogFPRegisters() {
+    if (log_parameters() & LOG_FP_REGS) PrintFPRegisters();
+  }
+
+  // Specify relevant register sizes, for PrintFPRegister.
+  //
+  // These values are bit masks; they can be combined in case multiple views of
+  // a machine register are interesting.
+  enum PrintFPRegisterSizes {
+    kPrintDRegValue = 1 << kDRegSize,
+    kPrintSRegValue = 1 << kSRegSize,
+    kPrintAllFPRegValues = kPrintDRegValue | kPrintSRegValue
+  };
+
+  // Print individual register values (after update).
+  void PrintRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer);
+  void PrintFPRegister(unsigned code,
+                       PrintFPRegisterSizes sizes = kPrintAllFPRegValues);
+  void PrintSystemRegister(SystemRegister id);
+
+  // Like Print* (above), but respect log_parameters().
+  void LogRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer) {
+    if (log_parameters() & LOG_REGS) PrintRegister(code, r31mode);
+  }
+  void LogFPRegister(unsigned code,
+                     PrintFPRegisterSizes sizes = kPrintAllFPRegValues) {
+    if (log_parameters() & LOG_FP_REGS) PrintFPRegister(code, sizes);
+  }
+  void LogSystemRegister(SystemRegister id) {
+    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id);
+  }
+
+  // Print memory accesses.
+  void PrintRead(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintReadFP(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintWrite(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintWriteFP(uintptr_t address, size_t size, unsigned reg_code);
+
+  // Like Print* (above), but respect log_parameters().
+  void LogRead(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_REGS) PrintRead(address, size, reg_code);
+  }
+  void LogReadFP(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_FP_REGS) PrintReadFP(address, size, reg_code);
+  }
+  void LogWrite(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_WRITE) PrintWrite(address, size, reg_code);
+  }
+  void LogWriteFP(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_WRITE) PrintWriteFP(address, size, reg_code);
+  }
+
+  int log_parameters() { return log_parameters_; }
+  void set_log_parameters(int new_parameters) {
+    log_parameters_ = new_parameters;
+    if (!decoder_) {
+      if (new_parameters & LOG_DISASM) {
+        PrintF("Run --debug-sim to dynamically turn on disassembler\n");
+      }
+      return;
+    }
+    if (new_parameters & LOG_DISASM) {
+      decoder_->InsertVisitorBefore(print_disasm_, this);
+    } else {
+      decoder_->RemoveVisitor(print_disasm_);
+    }
+  }
+
+  static inline const char* WRegNameForCode(unsigned code,
+      Reg31Mode mode = Reg31IsZeroRegister);
+  static inline const char* XRegNameForCode(unsigned code,
+      Reg31Mode mode = Reg31IsZeroRegister);
+  static inline const char* SRegNameForCode(unsigned code);
+  static inline const char* DRegNameForCode(unsigned code);
+  static inline const char* VRegNameForCode(unsigned code);
+  static inline int CodeFromName(const char* name);
+
+ protected:
+  // Simulation helpers ------------------------------------
+  bool ConditionPassed(Condition cond) {
+    SimSystemRegister& flags = nzcv();
+    switch (cond) {
+      case eq:
+        return flags.Z();
+      case ne:
+        return !flags.Z();
+      case hs:
+        return flags.C();
+      case lo:
+        return !flags.C();
+      case mi:
+        return flags.N();
+      case pl:
+        return !flags.N();
+      case vs:
+        return flags.V();
+      case vc:
+        return !flags.V();
+      case hi:
+        return flags.C() && !flags.Z();
+      case ls:
+        return !(flags.C() && !flags.Z());
+      case ge:
+        return flags.N() == flags.V();
+      case lt:
+        return flags.N() != flags.V();
+      case gt:
+        return !flags.Z() && (flags.N() == flags.V());
+      case le:
+        return !(!flags.Z() && (flags.N() == flags.V()));
+      case nv:  // Fall through.
+      case al:
+        return true;
+      default:
+        UNREACHABLE();
+        return false;
+    }
+  }
+
+  bool ConditionFailed(Condition cond) {
+    return !ConditionPassed(cond);
+  }
+
+  template<typename T>
+  void AddSubHelper(Instruction* instr, T op2);
+  template<typename T>
+  T AddWithCarry(bool set_flags,
+                 T src1,
+                 T src2,
+                 T carry_in = 0);
+  template<typename T>
+  void AddSubWithCarry(Instruction* instr);
+  template<typename T>
+  void LogicalHelper(Instruction* instr, T op2);
+  template<typename T>
+  void ConditionalCompareHelper(Instruction* instr, T op2);
+  void LoadStoreHelper(Instruction* instr,
+                       int64_t offset,
+                       AddrMode addrmode);
+  void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
+  uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset,
+                             AddrMode addrmode);
+  void LoadStoreWriteBack(unsigned addr_reg,
+                          int64_t offset,
+                          AddrMode addrmode);
+  void CheckMemoryAccess(uintptr_t address, uintptr_t stack);
+
+  // Memory read helpers.
+  template <typename T, typename A>
+  T MemoryRead(A address) {
+    T value;
+    STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
+                  (sizeof(value) == 4) || (sizeof(value) == 8));
+    memcpy(&value, reinterpret_cast<const void*>(address), sizeof(value));
+    return value;
+  }
+
+  // Memory write helpers.
+  template <typename T, typename A>
+  void MemoryWrite(A address, T value) {
+    STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
+                  (sizeof(value) == 4) || (sizeof(value) == 8));
+    memcpy(reinterpret_cast<void*>(address), &value, sizeof(value));
+  }
+
+  template <typename T>
+  T ShiftOperand(T value,
+                 Shift shift_type,
+                 unsigned amount);
+  template <typename T>
+  T ExtendValue(T value,
+                Extend extend_type,
+                unsigned left_shift = 0);
+  template <typename T>
+  void Extract(Instruction* instr);
+  template <typename T>
+  void DataProcessing2Source(Instruction* instr);
+  template <typename T>
+  void BitfieldHelper(Instruction* instr);
+
+  uint64_t ReverseBits(uint64_t value, unsigned num_bits);
+  uint64_t ReverseBytes(uint64_t value, ReverseByteMode mode);
+
+  template <typename T>
+  T FPDefaultNaN() const;
+
+  void FPCompare(double val0, double val1);
+  double FPRoundInt(double value, FPRounding round_mode);
+  double FPToDouble(float value);
+  float FPToFloat(double value, FPRounding round_mode);
+  double FixedToDouble(int64_t src, int fbits, FPRounding round_mode);
+  double UFixedToDouble(uint64_t src, int fbits, FPRounding round_mode);
+  float FixedToFloat(int64_t src, int fbits, FPRounding round_mode);
+  float UFixedToFloat(uint64_t src, int fbits, FPRounding round_mode);
+  int32_t FPToInt32(double value, FPRounding rmode);
+  int64_t FPToInt64(double value, FPRounding rmode);
+  uint32_t FPToUInt32(double value, FPRounding rmode);
+  uint64_t FPToUInt64(double value, FPRounding rmode);
+
+  template <typename T>
+  T FPAdd(T op1, T op2);
+
+  template <typename T>
+  T FPDiv(T op1, T op2);
+
+  template <typename T>
+  T FPMax(T a, T b);
+
+  template <typename T>
+  T FPMaxNM(T a, T b);
+
+  template <typename T>
+  T FPMin(T a, T b);
+
+  template <typename T>
+  T FPMinNM(T a, T b);
+
+  template <typename T>
+  T FPMul(T op1, T op2);
+
+  template <typename T>
+  T FPMulAdd(T a, T op1, T op2);
+
+  template <typename T>
+  T FPSqrt(T op);
+
+  template <typename T>
+  T FPSub(T op1, T op2);
+
+  // Standard NaN processing.
+  template <typename T>
+  T FPProcessNaN(T op);
+
+  bool FPProcessNaNs(Instruction* instr);
+
+  template <typename T>
+  T FPProcessNaNs(T op1, T op2);
+
+  template <typename T>
+  T FPProcessNaNs3(T op1, T op2, T op3);
+
+  void CheckStackAlignment();
+
+  inline void CheckPCSComplianceAndRun();
+
+#ifdef DEBUG
+  // Corruption values should have their least significant byte cleared to
+  // allow the code of the register being corrupted to be inserted.
+  static const uint64_t kCallerSavedRegisterCorruptionValue =
+      0xca11edc0de000000UL;
+  // This value is a NaN in both 32-bit and 64-bit FP.
+  static const uint64_t kCallerSavedFPRegisterCorruptionValue =
+      0x7ff000007f801000UL;
+  // This value is a mix of 32/64-bits NaN and "verbose" immediate.
+  static const uint64_t kDefaultCPURegisterCorruptionValue =
+      0x7ffbad007f8bad00UL;
+
+  void CorruptRegisters(CPURegList* list,
+                        uint64_t value = kDefaultCPURegisterCorruptionValue);
+  void CorruptAllCallerSavedCPURegisters();
+#endif
+
+  // Pseudo Printf instruction
+  void DoPrintf(Instruction* instr);
+
+  // Processor state ---------------------------------------
+
+  // Output stream.
+  FILE* stream_;
+  PrintDisassembler* print_disasm_;
+  void PRINTF_METHOD_CHECKING TraceSim(const char* format, ...);
+
+  // Instrumentation.
+  Instrument* instrument_;
+
+  // General purpose registers. Register 31 is the stack pointer.
+  SimRegister registers_[kNumberOfRegisters];
+
+  // Floating point registers
+  SimFPRegister fpregisters_[kNumberOfFPRegisters];
+
+  // Processor state
+  // bits[31, 27]: Condition flags N, Z, C, and V.
+  //               (Negative, Zero, Carry, Overflow)
+  SimSystemRegister nzcv_;
+
+  // Floating-Point Control Register
+  SimSystemRegister fpcr_;
+
+  // Only a subset of FPCR features are supported by the simulator. This helper
+  // checks that the FPCR settings are supported.
+  //
+  // This is checked when floating-point instructions are executed, not when
+  // FPCR is set. This allows generated code to modify FPCR for external
+  // functions, or to save and restore it when entering and leaving generated
+  // code.
+  void AssertSupportedFPCR() {
+    DCHECK(fpcr().FZ() == 0);             // No flush-to-zero support.
+    DCHECK(fpcr().RMode() == FPTieEven);  // Ties-to-even rounding only.
+
+    // The simulator does not support half-precision operations so fpcr().AHP()
+    // is irrelevant, and is not checked here.
+  }
+
+  template <typename T>
+  static int CalcNFlag(T result) {
+    return (result >> (sizeof(T) * 8 - 1)) & 1;
+  }
+
+  static int CalcZFlag(uint64_t result) {
+    return result == 0;
+  }
+
+  static const uint32_t kConditionFlagsMask = 0xf0000000;
+
+  // Stack
+  uintptr_t stack_;
+  static const size_t stack_protection_size_ = KB;
+  size_t stack_size_;
+  uintptr_t stack_limit_;
+
+  Decoder<DispatchingDecoderVisitor>* decoder_;
+  Decoder<DispatchingDecoderVisitor>* disassembler_decoder_;
+
+  // Indicates if the pc has been modified by the instruction and should not be
+  // automatically incremented.
+  bool pc_modified_;
+  Instruction* pc_;
+
+  static const char* xreg_names[];
+  static const char* wreg_names[];
+  static const char* sreg_names[];
+  static const char* dreg_names[];
+  static const char* vreg_names[];
+
+  // Debugger input.
+  void set_last_debugger_input(char* input) {
+    DeleteArray(last_debugger_input_);
+    last_debugger_input_ = input;
+  }
+  char* last_debugger_input() { return last_debugger_input_; }
+  char* last_debugger_input_;
+
+ private:
+  void Init(FILE* stream);
+
+  int  log_parameters_;
+  Isolate* isolate_;
+};
+
+
+// When running with the simulator transition into simulated execution at this
+// point.
+#define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
+  reinterpret_cast<Object*>(Simulator::current(Isolate::Current())->CallJS(    \
+      FUNCTION_ADDR(entry),                                                    \
+      p0, p1, p2, p3, p4))
+
+#define CALL_GENERATED_REGEXP_CODE(entry, p0, p1, p2, p3, p4, p5, p6, p7, p8)  \
+  Simulator::current(Isolate::Current())->CallRegExp(                          \
+      entry,                                                                   \
+      p0, p1, p2, p3, p4, p5, p6, p7, NULL, p8)
+
+
+// The simulator has its own stack. Thus it has a different stack limit from
+// the C-based native code.
+// See also 'class SimulatorStack' in arm/simulator-arm.h.
+class SimulatorStack : public v8::internal::AllStatic {
+ public:
+  static uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate,
+                                            uintptr_t c_limit) {
+    return Simulator::current(isolate)->StackLimit();
+  }
+
+  static uintptr_t RegisterCTryCatch(uintptr_t try_catch_address) {
+    Simulator* sim = Simulator::current(Isolate::Current());
+    return sim->PushAddress(try_catch_address);
+  }
+
+  static void UnregisterCTryCatch() {
+    Simulator::current(Isolate::Current())->PopAddress();
+  }
+};
+
+#endif  // !defined(USE_SIMULATOR)
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_SIMULATOR_ARM64_H_
diff --git a/src/arm64/utils-arm64.cc b/src/arm64/utils-arm64.cc
new file mode 100644
index 0000000..dbfb876
--- /dev/null
+++ b/src/arm64/utils-arm64.cc
@@ -0,0 +1,94 @@
+// Copyright 2013 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.
+
+#if V8_TARGET_ARCH_ARM64
+
+#include "src/arm64/utils-arm64.h"
+
+
+namespace v8 {
+namespace internal {
+
+#define __ assm->
+
+
+int CountLeadingZeros(uint64_t value, int width) {
+  // TODO(jbramley): Optimize this for ARM64 hosts.
+  DCHECK((width == 32) || (width == 64));
+  int count = 0;
+  uint64_t bit_test = 1UL << (width - 1);
+  while ((count < width) && ((bit_test & value) == 0)) {
+    count++;
+    bit_test >>= 1;
+  }
+  return count;
+}
+
+
+int CountLeadingSignBits(int64_t value, int width) {
+  // TODO(jbramley): Optimize this for ARM64 hosts.
+  DCHECK((width == 32) || (width == 64));
+  if (value >= 0) {
+    return CountLeadingZeros(value, width) - 1;
+  } else {
+    return CountLeadingZeros(~value, width) - 1;
+  }
+}
+
+
+int CountTrailingZeros(uint64_t value, int width) {
+  // TODO(jbramley): Optimize this for ARM64 hosts.
+  DCHECK((width == 32) || (width == 64));
+  int count = 0;
+  while ((count < width) && (((value >> count) & 1) == 0)) {
+    count++;
+  }
+  return count;
+}
+
+
+int CountSetBits(uint64_t value, int width) {
+  // TODO(jbramley): Would it be useful to allow other widths? The
+  // implementation already supports them.
+  DCHECK((width == 32) || (width == 64));
+
+  // Mask out unused bits to ensure that they are not counted.
+  value &= (0xffffffffffffffffUL >> (64-width));
+
+  // Add up the set bits.
+  // The algorithm works by adding pairs of bit fields together iteratively,
+  // where the size of each bit field doubles each time.
+  // An example for an 8-bit value:
+  // Bits:  h  g  f  e  d  c  b  a
+  //         \ |   \ |   \ |   \ |
+  // value = h+g   f+e   d+c   b+a
+  //            \    |      \    |
+  // value =   h+g+f+e     d+c+b+a
+  //                  \          |
+  // value =       h+g+f+e+d+c+b+a
+  value = ((value >> 1) & 0x5555555555555555) + (value & 0x5555555555555555);
+  value = ((value >> 2) & 0x3333333333333333) + (value & 0x3333333333333333);
+  value = ((value >> 4) & 0x0f0f0f0f0f0f0f0f) + (value & 0x0f0f0f0f0f0f0f0f);
+  value = ((value >> 8) & 0x00ff00ff00ff00ff) + (value & 0x00ff00ff00ff00ff);
+  value = ((value >> 16) & 0x0000ffff0000ffff) + (value & 0x0000ffff0000ffff);
+  value = ((value >> 32) & 0x00000000ffffffff) + (value & 0x00000000ffffffff);
+
+  return value;
+}
+
+
+uint64_t LargestPowerOf2Divisor(uint64_t value) {
+  return value & -value;
+}
+
+
+int MaskToBit(uint64_t mask) {
+  DCHECK(CountSetBits(mask, 64) == 1);
+  return CountTrailingZeros(mask, 64);
+}
+
+
+} }  // namespace v8::internal
+
+#endif  // V8_TARGET_ARCH_ARM64
diff --git a/src/arm64/utils-arm64.h b/src/arm64/utils-arm64.h
new file mode 100644
index 0000000..c22ed9a
--- /dev/null
+++ b/src/arm64/utils-arm64.h
@@ -0,0 +1,114 @@
+// Copyright 2013 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.
+
+#ifndef V8_ARM64_UTILS_ARM64_H_
+#define V8_ARM64_UTILS_ARM64_H_
+
+#include <cmath>
+#include "src/v8.h"
+
+#include "src/arm64/constants-arm64.h"
+
+#define REGISTER_CODE_LIST(R)                                                  \
+R(0)  R(1)  R(2)  R(3)  R(4)  R(5)  R(6)  R(7)                                 \
+R(8)  R(9)  R(10) R(11) R(12) R(13) R(14) R(15)                                \
+R(16) R(17) R(18) R(19) R(20) R(21) R(22) R(23)                                \
+R(24) R(25) R(26) R(27) R(28) R(29) R(30) R(31)
+
+namespace v8 {
+namespace internal {
+
+// These are global assumptions in v8.
+STATIC_ASSERT((static_cast<int32_t>(-1) >> 1) == -1);
+STATIC_ASSERT((static_cast<uint32_t>(-1) >> 1) == 0x7FFFFFFF);
+
+// Floating point representation.
+static inline uint32_t float_to_rawbits(float value) {
+  uint32_t bits = 0;
+  memcpy(&bits, &value, 4);
+  return bits;
+}
+
+
+static inline uint64_t double_to_rawbits(double value) {
+  uint64_t bits = 0;
+  memcpy(&bits, &value, 8);
+  return bits;
+}
+
+
+static inline float rawbits_to_float(uint32_t bits) {
+  float value = 0.0;
+  memcpy(&value, &bits, 4);
+  return value;
+}
+
+
+static inline double rawbits_to_double(uint64_t bits) {
+  double value = 0.0;
+  memcpy(&value, &bits, 8);
+  return value;
+}
+
+
+// Bit counting.
+int CountLeadingZeros(uint64_t value, int width);
+int CountLeadingSignBits(int64_t value, int width);
+int CountTrailingZeros(uint64_t value, int width);
+int CountSetBits(uint64_t value, int width);
+uint64_t LargestPowerOf2Divisor(uint64_t value);
+int MaskToBit(uint64_t mask);
+
+
+// NaN tests.
+inline bool IsSignallingNaN(double num) {
+  uint64_t raw = double_to_rawbits(num);
+  if (std::isnan(num) && ((raw & kDQuietNanMask) == 0)) {
+    return true;
+  }
+  return false;
+}
+
+
+inline bool IsSignallingNaN(float num) {
+  uint32_t raw = float_to_rawbits(num);
+  if (std::isnan(num) && ((raw & kSQuietNanMask) == 0)) {
+    return true;
+  }
+  return false;
+}
+
+
+template <typename T>
+inline bool IsQuietNaN(T num) {
+  return std::isnan(num) && !IsSignallingNaN(num);
+}
+
+
+// Convert the NaN in 'num' to a quiet NaN.
+inline double ToQuietNaN(double num) {
+  DCHECK(std::isnan(num));
+  return rawbits_to_double(double_to_rawbits(num) | kDQuietNanMask);
+}
+
+
+inline float ToQuietNaN(float num) {
+  DCHECK(std::isnan(num));
+  return rawbits_to_float(float_to_rawbits(num) | kSQuietNanMask);
+}
+
+
+// Fused multiply-add.
+inline double FusedMultiplyAdd(double op1, double op2, double a) {
+  return fma(op1, op2, a);
+}
+
+
+inline float FusedMultiplyAdd(float op1, float op2, float a) {
+  return fmaf(op1, op2, a);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_ARM64_UTILS_ARM64_H_