text: // Copyright (c) 1994-2006 Sun Microsystems Inc.
  // 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.
  //
  // - Redistribution 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 Sun Microsystems or the names of 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.
  
  // The original source code covered by the above license above has been modified
  // significantly by Google Inc.
  // Copyright 2006-2008 the V8 project authors. All rights reserved.
  
  // A light-weight ARM Assembler
  // Generates user mode instructions for the ARM architecture up to version 5
  
  #ifndef V8_ARM_ASSEMBLER_ARM_H_
  #define V8_ARM_ASSEMBLER_ARM_H_
  #include <stdio.h>
  #include "assembler.h"
  
  namespace v8 {
  namespace internal {
  
  // CPU Registers.
  //
  // 1) We would prefer to use an enum, but enum values are assignment-
  // compatible with int, which has caused code-generation bugs.
  //
  // 2) We would prefer to use a class instead of a struct but we don't like
  // the register initialization to depend on the particular initialization
  // order (which appears to be different on OS X, Linux, and Windows for the
  // installed versions of C++ we tried). Using a struct permits C-style
  // "initialization". Also, the Register objects cannot be const as this
  // forces initialization stubs in MSVC, making us dependent on initialization
  // order.
  //
  // 3) By not using an enum, we are possibly preventing the compiler from
  // doing certain constant folds, which may significantly reduce the
  // code generated for some assembly instructions (because they boil down
  // to a few constants). If this is a problem, we could change the code
  // such that we use an enum in optimized mode, and the struct in debug
  // mode. This way we get the compile-time error checking in debug mode
  // and best performance in optimized code.
  //
  // Core register
  struct Register {
    bool is_valid() const  { return 0 <= code_ && code_ < 16; }
    bool is(Register reg) const  { return code_ == reg.code_; }
    int code() const  {
      ASSERT(is_valid());
      return code_;
    }
    int bit() const  {
      ASSERT(is_valid());
      return 1 << code_;
    }
  
    // (unfortunately we can't make this private in a struct)
    int code_;
  };
  
  
  extern Register no_reg;
  extern Register r0;
  extern Register r1;
  extern Register r2;
  extern Register r3;
  extern Register r4;
  extern Register r5;
  extern Register r6;
  extern Register r7;
  extern Register r8;
  extern Register r9;
  extern Register r10;
  extern Register fp;
  extern Register ip;
  extern Register sp;
  extern Register lr;
  extern Register pc;
  
  
  // Coprocessor register
  struct CRegister {
    bool is_valid() const  { return 0 <= code_ && code_ < 16; }
    bool is(CRegister creg) const  { return code_ == creg.code_; }
    int code() const  {
      ASSERT(is_valid());
      return code_;
    }
    int bit() const  {
      ASSERT(is_valid());
      return 1 << code_;
    }
  
    // (unfortunately we can't make this private in a struct)
    int code_;
  };
  
  
  extern CRegister no_creg;
  extern CRegister cr0;
  extern CRegister cr1;
  extern CRegister cr2;
  extern CRegister cr3;
  extern CRegister cr4;
  extern CRegister cr5;
  extern CRegister cr6;
  extern CRegister cr7;
  extern CRegister cr8;
  extern CRegister cr9;
  extern CRegister cr10;
  extern CRegister cr11;
  extern CRegister cr12;
  extern CRegister cr13;
  extern CRegister cr14;
  extern CRegister cr15;
  
  
  // Coprocessor number
  enum Coprocessor {
    p0  = 0,
    p1  = 1,
    p2  = 2,
    p3  = 3,
    p4  = 4,
    p5  = 5,
    p6  = 6,
    p7  = 7,
    p8  = 8,
    p9  = 9,
    p10 = 10,
    p11 = 11,
    p12 = 12,
    p13 = 13,
    p14 = 14,
    p15 = 15
  };
  
  
  // Condition field in instructions
  enum Condition {
    eq =  0 << 28,  // Z set            equal.
    ne =  1 << 28,  // Z clear          not equal.
    nz =  1 << 28,  // Z clear          not zero.
    cs =  2 << 28,  // C set            carry set.
    hs =  2 << 28,  // C set            unsigned higher or same.
    cc =  3 << 28,  // C clear          carry clear.
    lo =  3 << 28,  // C clear          unsigned lower.
    mi =  4 << 28,  // N set            negative.
    pl =  5 << 28,  // N clear          positive or zero.
    vs =  6 << 28,  // V set            overflow.
    vc =  7 << 28,  // V clear          no overflow.
    hi =  8 << 28,  // C set, Z clear   unsigned higher.
    ls =  9 << 28,  // C clear or Z set unsigned lower or same.
    ge = 10 << 28,  // N == V           greater or equal.
    lt = 11 << 28,  // N != V           less than.
    gt = 12 << 28,  // Z clear, N == V  greater than.
    le = 13 << 28,  // Z set or N != V  less then or equal
    al = 14 << 28   //                  always.
  };
  
  
  // Returns the equivalent of !cc.
  INLINE(Condition NegateCondition(Condition cc));
  
  
  // Corresponds to transposing the operands of a comparison.
  inline Condition ReverseCondition(Condition cc) {
    switch (cc) {
      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;
      default:
        return cc;
    };
  }
  
  
  // Branch hints are not used on the ARM.  They are defined so that they can
  // appear in shared function signatures, but will be ignored in ARM
  // implementations.
  enum Hint { no_hint };
  
  // Hints are not used on the arm.  Negating is trivial.
  inline Hint NegateHint(Hint ignored) { return no_hint; }
  
  
  // -----------------------------------------------------------------------------
  // Addressing modes and instruction variants
  
  // Shifter operand shift operation
  enum ShiftOp {
    LSL = 0 << 5,
    LSR = 1 << 5,
    ASR = 2 << 5,
    ROR = 3 << 5,
    RRX = -1
  };
  
  
  // Condition code updating mode
  enum SBit {
    SetCC   = 1 << 20,  // set condition code
    LeaveCC = 0 << 20   // leave condition code unchanged
  };
  
  
  // Status register selection
  enum SRegister {
    CPSR = 0 << 22,
    SPSR = 1 << 22
  };
  
  
  // Status register fields
  enum SRegisterField {
    CPSR_c = CPSR | 1 << 16,
    CPSR_x = CPSR | 1 << 17,
    CPSR_s = CPSR | 1 << 18,
    CPSR_f = CPSR | 1 << 19,
    SPSR_c = SPSR | 1 << 16,
    SPSR_x = SPSR | 1 << 17,
    SPSR_s = SPSR | 1 << 18,
    SPSR_f = SPSR | 1 << 19
  };
  
  // Status register field mask (or'ed SRegisterField enum values)
  typedef uint32_t SRegisterFieldMask;
  
  
  // Memory operand addressing mode
  enum AddrMode {
    // bit encoding P U W
    Offset       = (8|4|0) << 21,  // offset (without writeback to base)
    PreIndex     = (8|4|1) << 21,  // pre-indexed addressing with writeback
    PostIndex    = (0|4|0) << 21,  // post-indexed addressing with writeback
    NegOffset    = (8|0|0) << 21,  // negative offset (without writeback to base)
    NegPreIndex  = (8|0|1) << 21,  // negative pre-indexed with writeback
    NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback
  };
  
  
  // Load/store multiple addressing mode
  enum BlockAddrMode {
    // bit encoding P U W
    da           = (0|0|0) << 21,  // decrement after
    ia           = (0|4|0) << 21,  // increment after
    db           = (8|0|0) << 21,  // decrement before
    ib           = (8|4|0) << 21,  // increment before
    da_w         = (0|0|1) << 21,  // decrement after with writeback to base
    ia_w         = (0|4|1) << 21,  // increment after with writeback to base
    db_w         = (8|0|1) << 21,  // decrement before with writeback to base
    ib_w         = (8|4|1) << 21   // increment before with writeback to base
  };
  
  
  // Coprocessor load/store operand size
  enum LFlag {
    Long  = 1 << 22,  // long load/store coprocessor
    Short = 0 << 22   // short load/store coprocessor
  };
  
  
  // -----------------------------------------------------------------------------
  // Machine instruction Operands
  
  // Class Operand represents a shifter operand in data processing instructions
  class Operand BASE_EMBEDDED {
   public:
    // immediate
    INLINE(explicit Operand(int32_t immediate,
           RelocInfo::Mode rmode = RelocInfo::NONE));
    INLINE(explicit Operand(const ExternalReference& f));
    INLINE(explicit Operand(const char* s));
    INLINE(explicit Operand(Object** opp));
    INLINE(explicit Operand(Context** cpp));
    explicit Operand(Handle<Object> handle);
    INLINE(explicit Operand(Smi* value));
  
    // rm
    INLINE(explicit Operand(Register rm));
  
    // rm <shift_op> shift_imm
    explicit Operand(Register rm, ShiftOp shift_op, int shift_imm);
  
    // rm <shift_op> rs
    explicit Operand(Register rm, ShiftOp shift_op, Register rs);
  
    // Return true if this is a register operand.
    INLINE(bool is_reg() const);
  
    Register rm() const { return rm_; }
  
   private:
    Register rm_;
    Register rs_;
    ShiftOp shift_op_;
    int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg
    int32_t imm32_;  // valid if rm_ == no_reg
    RelocInfo::Mode rmode_;
  
    friend class Assembler;
  };
  
  
  // Class MemOperand represents a memory operand in load and store instructions
  class MemOperand BASE_EMBEDDED {
   public:
    // [rn +/- offset]      Offset/NegOffset
    // [rn +/- offset]!     PreIndex/NegPreIndex
    // [rn], +/- offset     PostIndex/NegPostIndex
    // offset is any signed 32-bit value; offset is first loaded to register ip if
    // it does not fit the addressing mode (12-bit unsigned and sign bit)
    explicit MemOperand(Register rn, int32_t offset = 0, AddrMode am = Offset);
  
    // [rn +/- rm]          Offset/NegOffset
    // [rn +/- rm]!         PreIndex/NegPreIndex
    // [rn], +/- rm         PostIndex/NegPostIndex
    explicit MemOperand(Register rn, Register rm, AddrMode am = Offset);
  
    // [rn +/- rm <shift_op> shift_imm]      Offset/NegOffset
    // [rn +/- rm <shift_op> shift_imm]!     PreIndex/NegPreIndex
    // [rn], +/- rm <shift_op> shift_imm     PostIndex/NegPostIndex
    explicit MemOperand(Register rn, Register rm,
                        ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
  
   private:
    Register rn_;  // base
    Register rm_;  // register offset
    int32_t offset_;  // valid if rm_ == no_reg
    ShiftOp shift_op_;
    int shift_imm_;  // valid if rm_ != no_reg && rs_ == no_reg
    AddrMode am_;  // bits P, U, and W
  
    friend class Assembler;
  };
  
  
  typedef int32_t Instr;
  
  
  extern const Instr kMovLrPc;
  extern const Instr kLdrPCPattern;
  
  
  class Assembler : public Malloced {
   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(void* buffer, int buffer_size);
    ~Assembler();
  
    // 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.
    void GetCode(CodeDesc* desc);
  
    // Label operations & relative jumps (PPUM Appendix D)
    //
    // Takes a branch opcode (cc) and a label (L) and generates
    // either a backward branch or a forward branch and links it
    // to the label fixup chain. Usage:
    //
    // Label L;    // unbound label
    // j(cc, &L);  // forward branch to unbound label
    // bind(&L);   // bind label to the current pc
    // j(cc, &L);  // backward branch to bound label
    // bind(&L);   // illegal: a label may be bound only once
    //
    // Note: The same Label can be used for forward and backward branches
    // but it may be bound only once.
  
    void bind(Label* L);  // binds an unbound label L to the current code position
  
    // Returns the branch offset to the given label from the current code position
    // Links the label to the current position if it is still unbound
    // Manages the jump elimination optimization if the second parameter is true.
    int branch_offset(Label* L, bool jump_elimination_allowed);
  
    // Puts a labels target address at the given position.
    // The high 8 bits are set to zero.
    void label_at_put(Label* L, int at_offset);
  
    // Return the address in the constant pool of the code target address used by
    // the branch/call instruction at pc.
    INLINE(static Address target_address_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));
    INLINE(static void set_target_address_at(Address pc, Address target));
  
    // Size of an instruction.
    static const int kInstrSize = sizeof(Instr);
  
    // Distance between the instruction referring to the address of the call
    // target (ldr pc, [target addr in const pool]) and the return address
    static const int kCallTargetAddressOffset = kInstrSize;
  
    // Distance between start of patched return sequence and the emitted address
    // to jump to.
    static const int kPatchReturnSequenceAddressOffset = kInstrSize;
  
    // Difference between address of current opcode and value read from pc
    // register.
    static const int kPcLoadDelta = 8;
  
  
    // ---------------------------------------------------------------------------
    // Code generation
  
    // 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);
  
    // Branch instructions
    void b(int branch_offset, Condition cond = al);
    void bl(int branch_offset, Condition cond = al);
    void blx(int branch_offset);  // v5 and above
    void blx(Register target, Condition cond = al);  // v5 and above
    void bx(Register target, Condition cond = al);  // v5 and above, plus v4t
  
    // Convenience branch instructions using labels
    void b(Label* L, Condition cond = al)  {
      b(branch_offset(L, cond == al), cond);
    }
    void b(Condition cond, Label* L)  { b(branch_offset(L, cond == al), cond); }
    void bl(Label* L, Condition cond = al)  { bl(branch_offset(L, false), cond); }
    void bl(Condition cond, Label* L)  { bl(branch_offset(L, false), cond); }
    void blx(Label* L)  { blx(branch_offset(L, false)); }  // v5 and above
  
    // Data-processing instructions
    void and_(Register dst, Register src1, const Operand& src2,
              SBit s = LeaveCC, Condition cond = al);
  
    void eor(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void sub(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
    void sub(Register dst, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al) {
      sub(dst, src1, Operand(src2), s, cond);
    }
  
    void rsb(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void add(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void adc(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void sbc(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void rsc(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void tst(Register src1, const Operand& src2, Condition cond = al);
    void tst(Register src1, Register src2, Condition cond = al) {
      tst(src1, Operand(src2), cond);
    }
  
    void teq(Register src1, const Operand& src2, Condition cond = al);
  
    void cmp(Register src1, const Operand& src2, Condition cond = al);
    void cmp(Register src1, Register src2, Condition cond = al) {
      cmp(src1, Operand(src2), cond);
    }
  
    void cmn(Register src1, const Operand& src2, Condition cond = al);
  
    void orr(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
    void orr(Register dst, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al) {
      orr(dst, src1, Operand(src2), s, cond);
    }
  
    void mov(Register dst, const Operand& src,
             SBit s = LeaveCC, Condition cond = al);
    void mov(Register dst, Register src, SBit s = LeaveCC, Condition cond = al) {
      mov(dst, Operand(src), s, cond);
    }
  
    void bic(Register dst, Register src1, const Operand& src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void mvn(Register dst, const Operand& src,
             SBit s = LeaveCC, Condition cond = al);
  
    // Multiply instructions
  
    void mla(Register dst, Register src1, Register src2, Register srcA,
             SBit s = LeaveCC, Condition cond = al);
  
    void mul(Register dst, Register src1, Register src2,
             SBit s = LeaveCC, Condition cond = al);
  
    void smlal(Register dstL, Register dstH, Register src1, Register src2,
               SBit s = LeaveCC, Condition cond = al);
  
    void smull(Register dstL, Register dstH, Register src1, Register src2,
               SBit s = LeaveCC, Condition cond = al);
  
    void umlal(Register dstL, Register dstH, Register src1, Register src2,
               SBit s = LeaveCC, Condition cond = al);
  
    void umull(Register dstL, Register dstH, Register src1, Register src2,
               SBit s = LeaveCC, Condition cond = al);
  
    // Miscellaneous arithmetic instructions
  
    void clz(Register dst, Register src, Condition cond = al);  // v5 and above
  
    // Status register access instructions
  
    void mrs(Register dst, SRegister s, Condition cond = al);
    void msr(SRegisterFieldMask fields, const Operand& src, Condition cond = al);
  
    // Load/Store instructions
    void ldr(Register dst, const MemOperand& src, Condition cond = al);
    void str(Register src, const MemOperand& dst, Condition cond = al);
    void ldrb(Register dst, const MemOperand& src, Condition cond = al);
    void strb(Register src, const MemOperand& dst, Condition cond = al);
    void ldrh(Register dst, const MemOperand& src, Condition cond = al);
    void strh(Register src, const MemOperand& dst, Condition cond = al);
    void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
    void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
  
    // Load/Store multiple instructions
    void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
    void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al);
  
    // Semaphore instructions
    void swp(Register dst, Register src, Register base, Condition cond = al);
    void swpb(Register dst, Register src, Register base, Condition cond = al);
  
    // Exception-generating instructions and debugging support
    void stop(const char* msg);
  
    void bkpt(uint32_t imm16);  // v5 and above
    void swi(uint32_t imm24, Condition cond = al);
  
    // Coprocessor instructions
  
    void cdp(Coprocessor coproc, int opcode_1,
             CRegister crd, CRegister crn, CRegister crm,
             int opcode_2, Condition cond = al);
  
    void cdp2(Coprocessor coproc, int opcode_1,
              CRegister crd, CRegister crn, CRegister crm,
              int opcode_2);  // v5 and above
  
    void mcr(Coprocessor coproc, int opcode_1,
             Register rd, CRegister crn, CRegister crm,
             int opcode_2 = 0, Condition cond = al);
  
    void mcr2(Coprocessor coproc, int opcode_1,
              Register rd, CRegister crn, CRegister crm,
              int opcode_2 = 0);  // v5 and above
  
    void mrc(Coprocessor coproc, int opcode_1,
             Register rd, CRegister crn, CRegister crm,
             int opcode_2 = 0, Condition cond = al);
  
    void mrc2(Coprocessor coproc, int opcode_1,
              Register rd, CRegister crn, CRegister crm,
              int opcode_2 = 0);  // v5 and above
  
    void ldc(Coprocessor coproc, CRegister crd, const MemOperand& src,
             LFlag l = Short, Condition cond = al);
    void ldc(Coprocessor coproc, CRegister crd, Register base, int option,
             LFlag l = Short, Condition cond = al);
  
    void ldc2(Coprocessor coproc, CRegister crd, const MemOperand& src,
              LFlag l = Short);  // v5 and above
    void ldc2(Coprocessor coproc, CRegister crd, Register base, int option,
              LFlag l = Short);  // v5 and above
  
    void stc(Coprocessor coproc, CRegister crd, const MemOperand& dst,
             LFlag l = Short, Condition cond = al);
    void stc(Coprocessor coproc, CRegister crd, Register base, int option,
             LFlag l = Short, Condition cond = al);
  
    void stc2(Coprocessor coproc, CRegister crd, const MemOperand& dst,
              LFlag l = Short);  // v5 and above
    void stc2(Coprocessor coproc, CRegister crd, Register base, int option,
              LFlag l = Short);  // v5 and above
  
    // Pseudo instructions
    void nop()  { mov(r0, Operand(r0)); }
  
    void push(Register src, Condition cond = al) {
      str(src, MemOperand(sp, 4, NegPreIndex), cond);
    }
  
    void pop(Register dst, Condition cond = al) {
      ldr(dst, MemOperand(sp, 4, PostIndex), cond);
    }
  
    void pop() {
      add(sp, sp, Operand(kPointerSize));
    }
  
    // Load effective address of memory operand x into register dst
    void lea(Register dst, const MemOperand& x,
             SBit s = LeaveCC, Condition cond = al);
  
    // Jump unconditionally to given label.
    void jmp(Label* L) { b(L, al); }
  
    // Check the code size generated from label to here.
    int InstructionsGeneratedSince(Label* l) {
      return (pc_offset() - l->pos()) / kInstrSize;
    }
  
    // Debugging
  
    // Mark address of the ExitJSFrame code.
    void RecordJSReturn();
  
    // Record a comment relocation entry that can be used by a disassembler.
    // Use --debug_code to enable.
    void RecordComment(const char* msg);
  
    void RecordPosition(int pos);
    void RecordStatementPosition(int pos);
    void WriteRecordedPositions();
  
    int pc_offset() const { return pc_ - buffer_; }
    int current_position() const { return current_position_; }
    int current_statement_position() const { return current_position_; }
  
   protected:
    int buffer_space() const { return reloc_info_writer.pos() - pc_; }
  
    // Read/patch instructions
    static Instr instr_at(byte* pc) { return *reinterpret_cast<Instr*>(pc); }
    void instr_at_put(byte* pc, Instr instr) {
      *reinterpret_cast<Instr*>(pc) = instr;
    }
    Instr instr_at(int pos) { return *reinterpret_cast<Instr*>(buffer_ + pos); }
    void instr_at_put(int pos, Instr instr) {
      *reinterpret_cast<Instr*>(buffer_ + pos) = instr;
    }
  
    // Decode branch instruction at pos and return branch target pos
    int target_at(int pos);
  
    // Patch branch instruction at pos to branch to given branch target pos
    void target_at_put(int pos, int target_pos);
  
    // Check if is time to emit a constant pool for pending reloc info entries
    void CheckConstPool(bool force_emit, bool require_jump);
  
    // Block the emission of the constant pool before pc_offset
    void BlockConstPoolBefore(int pc_offset) {
      if (no_const_pool_before_ < pc_offset) no_const_pool_before_ = pc_offset;
    }
  
   private:
    // Code buffer:
    // The buffer into which code and relocation info are generated.
    byte* buffer_;
    int buffer_size_;
    // True if the assembler owns the buffer, false if buffer is external.
    bool own_buffer_;
  
    // Buffer size and constant pool distance are checked together at regular
    // intervals of kBufferCheckInterval emitted bytes
    static const int kBufferCheckInterval = 1*KB/2;
    int next_buffer_check_;  // pc offset of next buffer check
  
    // 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.
    static const int kGap = 32;
    byte* pc_;  // the program counter; moves forward
  
    // Constant pool generation
    // Pools are emitted in the instruction stream, preferably after unconditional
    // jumps or after returns from functions (in dead code locations).
    // If a long code sequence does not contain unconditional jumps, it is
    // necessary to emit the constant pool before the pool gets too far from the
    // location it is accessed from. In this case, we emit a jump over the emitted
    // constant pool.
    // 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 kCheckConstIntervalInst = 32;
    static const int kCheckConstInterval = kCheckConstIntervalInst * kInstrSize;
  
  
    // Pools are emitted after function return and in dead code at (more or less)
    // regular intervals of kDistBetweenPools bytes
    static const int kDistBetweenPools = 1*KB;
  
    // Constants in pools are accessed via pc relative addressing, which can
    // reach +/-4KB thereby defining a maximum distance between the instruction
    // and the accessed constant. We satisfy this constraint by limiting the
    // distance between pools.
    static const int kMaxDistBetweenPools = 4*KB - 2*kBufferCheckInterval;
  
    // Emission of the constant pool may be blocked in some code sequences
    int no_const_pool_before_;  // block emission before this pc offset
  
    // Keep track of the last emitted pool to guarantee a maximal distance
    int last_const_pool_end_;  // pc offset following the last constant pool
  
    // 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.
    static const int kMaxNumPRInfo = kMaxDistBetweenPools/kInstrSize;
    RelocInfo prinfo_[kMaxNumPRInfo];  // the buffer of pending relocation info
    int num_prinfo_;  // number of pending reloc info entries in the buffer
  
    // The bound position, before this we cannot do instruction elimination.
    int last_bound_pos_;
  
    // source position information
    int current_position_;
    int current_statement_position_;
    int written_position_;
    int written_statement_position_;
  
    // Code emission
    inline void CheckBuffer();
    void GrowBuffer();
    inline void emit(Instr x);
  
    // Instruction generation
    void addrmod1(Instr instr, Register rn, Register rd, const Operand& x);
    void addrmod2(Instr instr, Register rd, const MemOperand& x);
    void addrmod3(Instr instr, Register rd, const MemOperand& x);
    void addrmod4(Instr instr, Register rn, RegList rl);
    void addrmod5(Instr instr, CRegister crd, const MemOperand& x);
  
    // Labels
    void print(Label* L);
    void bind_to(Label* L, int pos);
    void link_to(Label* L, Label* appendix);
    void next(Label* L);
  
    // Record reloc info for current pc_
    void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0);
  
    friend class RegExpMacroAssemblerARM;
    friend class RelocInfo;
    friend class CodePatcher;
  };
  
  } }  // namespace v8::internal
  
  #endif  // V8_ARM_ASSEMBLER_ARM_H_
  