diff options
author | Ryan <ry@tinyclouds.org> | 2009-05-12 00:12:56 +0200 |
---|---|---|
committer | Ryan <ry@tinyclouds.org> | 2009-05-12 00:12:56 +0200 |
commit | 3a41367c40863efc08d1f0922a91b5b0bdca6c80 (patch) | |
tree | b74fc97840245f551ef66b0d5e109962533fe075 /deps/v8/src/arm/assembler-arm.h | |
parent | 7869ed6681e76f553f6380187e5349ee6854e207 (diff) | |
download | node-new-3a41367c40863efc08d1f0922a91b5b0bdca6c80.tar.gz |
Upgrade v8 to version 1.2.3.
Diffstat (limited to 'deps/v8/src/arm/assembler-arm.h')
-rw-r--r-- | deps/v8/src/arm/assembler-arm.h | 789 |
1 files changed, 789 insertions, 0 deletions
diff --git a/deps/v8/src/arm/assembler-arm.h b/deps/v8/src/arm/assembler-arm.h new file mode 100644 index 0000000000..d7535e0da4 --- /dev/null +++ b/deps/v8/src/arm/assembler-arm.h @@ -0,0 +1,789 @@ +// 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 "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_; +}; + + +const int kNumRegisters = 16; + +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. + cs = 2 << 28, // C set unsigned higher or same. + hs = 2 << 28, // C set unsigned higher or same. + cc = 3 << 28, // C clear unsigned lower. + 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; + + +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); + + // 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)); + + // 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 kTargetAddrToReturnAddrDist = sizeof(Instr); + + + // --------------------------------------------------------------------------- + // 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) { + str(src, MemOperand(sp, 4, NegPreIndex), al); + } + + void pop(Register dst) { + ldr(dst, MemOperand(sp, 4, PostIndex), al); + } + + 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); } + + + // Debugging + + // 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 + 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 + static const int kInstrSize = sizeof(Instr); // signed size + // 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); +}; + +} } // namespace v8::internal + +#endif // V8_ARM_ASSEMBLER_ARM_H_ |