js/src/jit/arm/Assembler-arm.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/arm/Assembler-arm.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2264 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#ifndef jit_arm_Assembler_arm_h
    1.11 +#define jit_arm_Assembler_arm_h
    1.12 +
    1.13 +#include "mozilla/ArrayUtils.h"
    1.14 +#include "mozilla/Attributes.h"
    1.15 +#include "mozilla/MathAlgorithms.h"
    1.16 +
    1.17 +#include "assembler/assembler/AssemblerBufferWithConstantPool.h"
    1.18 +#include "jit/arm/Architecture-arm.h"
    1.19 +#include "jit/CompactBuffer.h"
    1.20 +#include "jit/IonCode.h"
    1.21 +#include "jit/shared/Assembler-shared.h"
    1.22 +#include "jit/shared/IonAssemblerBufferWithConstantPools.h"
    1.23 +
    1.24 +namespace js {
    1.25 +namespace jit {
    1.26 +
    1.27 +//NOTE: there are duplicates in this list!
    1.28 +// sometimes we want to specifically refer to the
    1.29 +// link register as a link register (bl lr is much
    1.30 +// clearer than bl r14).  HOWEVER, this register can
    1.31 +// easily be a gpr when it is not busy holding the return
    1.32 +// address.
    1.33 +static MOZ_CONSTEXPR_VAR Register r0  = { Registers::r0 };
    1.34 +static MOZ_CONSTEXPR_VAR Register r1  = { Registers::r1 };
    1.35 +static MOZ_CONSTEXPR_VAR Register r2  = { Registers::r2 };
    1.36 +static MOZ_CONSTEXPR_VAR Register r3  = { Registers::r3 };
    1.37 +static MOZ_CONSTEXPR_VAR Register r4  = { Registers::r4 };
    1.38 +static MOZ_CONSTEXPR_VAR Register r5  = { Registers::r5 };
    1.39 +static MOZ_CONSTEXPR_VAR Register r6  = { Registers::r6 };
    1.40 +static MOZ_CONSTEXPR_VAR Register r7  = { Registers::r7 };
    1.41 +static MOZ_CONSTEXPR_VAR Register r8  = { Registers::r8 };
    1.42 +static MOZ_CONSTEXPR_VAR Register r9  = { Registers::r9 };
    1.43 +static MOZ_CONSTEXPR_VAR Register r10 = { Registers::r10 };
    1.44 +static MOZ_CONSTEXPR_VAR Register r11 = { Registers::r11 };
    1.45 +static MOZ_CONSTEXPR_VAR Register r12 = { Registers::ip };
    1.46 +static MOZ_CONSTEXPR_VAR Register ip  = { Registers::ip };
    1.47 +static MOZ_CONSTEXPR_VAR Register sp  = { Registers::sp };
    1.48 +static MOZ_CONSTEXPR_VAR Register r14 = { Registers::lr };
    1.49 +static MOZ_CONSTEXPR_VAR Register lr  = { Registers::lr };
    1.50 +static MOZ_CONSTEXPR_VAR Register pc  = { Registers::pc };
    1.51 +
    1.52 +static MOZ_CONSTEXPR_VAR Register ScratchRegister = {Registers::ip};
    1.53 +
    1.54 +static MOZ_CONSTEXPR_VAR Register OsrFrameReg = r3;
    1.55 +static MOZ_CONSTEXPR_VAR Register ArgumentsRectifierReg = r8;
    1.56 +static MOZ_CONSTEXPR_VAR Register CallTempReg0 = r5;
    1.57 +static MOZ_CONSTEXPR_VAR Register CallTempReg1 = r6;
    1.58 +static MOZ_CONSTEXPR_VAR Register CallTempReg2 = r7;
    1.59 +static MOZ_CONSTEXPR_VAR Register CallTempReg3 = r8;
    1.60 +static MOZ_CONSTEXPR_VAR Register CallTempReg4 = r0;
    1.61 +static MOZ_CONSTEXPR_VAR Register CallTempReg5 = r1;
    1.62 +
    1.63 +static MOZ_CONSTEXPR_VAR Register IntArgReg0 = r0;
    1.64 +static MOZ_CONSTEXPR_VAR Register IntArgReg1 = r1;
    1.65 +static MOZ_CONSTEXPR_VAR Register IntArgReg2 = r2;
    1.66 +static MOZ_CONSTEXPR_VAR Register IntArgReg3 = r3;
    1.67 +static MOZ_CONSTEXPR_VAR Register GlobalReg = r10;
    1.68 +static MOZ_CONSTEXPR_VAR Register HeapReg = r11;
    1.69 +static MOZ_CONSTEXPR_VAR Register CallTempNonArgRegs[] = { r5, r6, r7, r8 };
    1.70 +static const uint32_t NumCallTempNonArgRegs =
    1.71 +    mozilla::ArrayLength(CallTempNonArgRegs);
    1.72 +class ABIArgGenerator
    1.73 +{
    1.74 +    unsigned intRegIndex_;
    1.75 +    unsigned floatRegIndex_;
    1.76 +    uint32_t stackOffset_;
    1.77 +    ABIArg current_;
    1.78 +
    1.79 +  public:
    1.80 +    ABIArgGenerator();
    1.81 +    ABIArg next(MIRType argType);
    1.82 +    ABIArg &current() { return current_; }
    1.83 +    uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
    1.84 +    static const Register NonArgReturnVolatileReg0;
    1.85 +    static const Register NonArgReturnVolatileReg1;
    1.86 +};
    1.87 +
    1.88 +static MOZ_CONSTEXPR_VAR Register PreBarrierReg = r1;
    1.89 +
    1.90 +static MOZ_CONSTEXPR_VAR Register InvalidReg = { Registers::invalid_reg };
    1.91 +static MOZ_CONSTEXPR_VAR FloatRegister InvalidFloatReg = { FloatRegisters::invalid_freg };
    1.92 +
    1.93 +static MOZ_CONSTEXPR_VAR Register JSReturnReg_Type = r3;
    1.94 +static MOZ_CONSTEXPR_VAR Register JSReturnReg_Data = r2;
    1.95 +static MOZ_CONSTEXPR_VAR Register StackPointer = sp;
    1.96 +static MOZ_CONSTEXPR_VAR Register FramePointer = InvalidReg;
    1.97 +static MOZ_CONSTEXPR_VAR Register ReturnReg = r0;
    1.98 +static MOZ_CONSTEXPR_VAR FloatRegister ReturnFloatReg = { FloatRegisters::d0 };
    1.99 +static MOZ_CONSTEXPR_VAR FloatRegister ScratchFloatReg = { FloatRegisters::d15 };
   1.100 +
   1.101 +static MOZ_CONSTEXPR_VAR FloatRegister NANReg = { FloatRegisters::d14 };
   1.102 +
   1.103 +// Registers used in the GenerateFFIIonExit Enable Activation block.
   1.104 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegCallee = r4;
   1.105 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE0 = r0;
   1.106 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE1 = r1;
   1.107 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE2 = r2;
   1.108 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegE3 = r3;
   1.109 +
   1.110 +// Registers used in the GenerateFFIIonExit Disable Activation block.
   1.111 +// None of these may be the second scratch register (lr).
   1.112 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnData = r2;
   1.113 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegReturnType = r3;
   1.114 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD0 = r0;
   1.115 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD1 = r1;
   1.116 +static MOZ_CONSTEXPR_VAR Register AsmJSIonExitRegD2 = r4;
   1.117 +
   1.118 +
   1.119 +static MOZ_CONSTEXPR_VAR FloatRegister d0  = {FloatRegisters::d0};
   1.120 +static MOZ_CONSTEXPR_VAR FloatRegister d1  = {FloatRegisters::d1};
   1.121 +static MOZ_CONSTEXPR_VAR FloatRegister d2  = {FloatRegisters::d2};
   1.122 +static MOZ_CONSTEXPR_VAR FloatRegister d3  = {FloatRegisters::d3};
   1.123 +static MOZ_CONSTEXPR_VAR FloatRegister d4  = {FloatRegisters::d4};
   1.124 +static MOZ_CONSTEXPR_VAR FloatRegister d5  = {FloatRegisters::d5};
   1.125 +static MOZ_CONSTEXPR_VAR FloatRegister d6  = {FloatRegisters::d6};
   1.126 +static MOZ_CONSTEXPR_VAR FloatRegister d7  = {FloatRegisters::d7};
   1.127 +static MOZ_CONSTEXPR_VAR FloatRegister d8  = {FloatRegisters::d8};
   1.128 +static MOZ_CONSTEXPR_VAR FloatRegister d9  = {FloatRegisters::d9};
   1.129 +static MOZ_CONSTEXPR_VAR FloatRegister d10 = {FloatRegisters::d10};
   1.130 +static MOZ_CONSTEXPR_VAR FloatRegister d11 = {FloatRegisters::d11};
   1.131 +static MOZ_CONSTEXPR_VAR FloatRegister d12 = {FloatRegisters::d12};
   1.132 +static MOZ_CONSTEXPR_VAR FloatRegister d13 = {FloatRegisters::d13};
   1.133 +static MOZ_CONSTEXPR_VAR FloatRegister d14 = {FloatRegisters::d14};
   1.134 +static MOZ_CONSTEXPR_VAR FloatRegister d15 = {FloatRegisters::d15};
   1.135 +
   1.136 +// For maximal awesomeness, 8 should be sufficent.
   1.137 +// ldrd/strd (dual-register load/store) operate in a single cycle
   1.138 +// when the address they are dealing with is 8 byte aligned.
   1.139 +// Also, the ARM abi wants the stack to be 8 byte aligned at
   1.140 +// function boundaries.  I'm trying to make sure this is always true.
   1.141 +static const uint32_t StackAlignment = 8;
   1.142 +static const uint32_t CodeAlignment = 8;
   1.143 +static const bool StackKeptAligned = true;
   1.144 +static const uint32_t NativeFrameSize = sizeof(void*);
   1.145 +static const uint32_t AlignmentAtPrologue = 0;
   1.146 +static const uint32_t AlignmentMidPrologue = 4;
   1.147 +
   1.148 +
   1.149 +static const Scale ScalePointer = TimesFour;
   1.150 +
   1.151 +class Instruction;
   1.152 +class InstBranchImm;
   1.153 +uint32_t RM(Register r);
   1.154 +uint32_t RS(Register r);
   1.155 +uint32_t RD(Register r);
   1.156 +uint32_t RT(Register r);
   1.157 +uint32_t RN(Register r);
   1.158 +
   1.159 +uint32_t maybeRD(Register r);
   1.160 +uint32_t maybeRT(Register r);
   1.161 +uint32_t maybeRN(Register r);
   1.162 +
   1.163 +Register toRN (Instruction &i);
   1.164 +Register toRM (Instruction &i);
   1.165 +Register toRD (Instruction &i);
   1.166 +Register toR (Instruction &i);
   1.167 +
   1.168 +class VFPRegister;
   1.169 +uint32_t VD(VFPRegister vr);
   1.170 +uint32_t VN(VFPRegister vr);
   1.171 +uint32_t VM(VFPRegister vr);
   1.172 +
   1.173 +class VFPRegister
   1.174 +{
   1.175 +  public:
   1.176 +    // What type of data is being stored in this register?
   1.177 +    // UInt / Int are specifically for vcvt, where we need
   1.178 +    // to know how the data is supposed to be converted.
   1.179 +    enum RegType {
   1.180 +        Double = 0x0,
   1.181 +        Single = 0x1,
   1.182 +        UInt   = 0x2,
   1.183 +        Int    = 0x3
   1.184 +    };
   1.185 +
   1.186 +  protected:
   1.187 +    RegType kind : 2;
   1.188 +    // ARM doesn't have more than 32 registers...
   1.189 +    // don't take more bits than we'll need.
   1.190 +    // Presently, I don't have plans to address the upper
   1.191 +    // and lower halves of the double registers seprately, so
   1.192 +    // 5 bits should suffice.  If I do decide to address them seprately
   1.193 +    // (vmov, I'm looking at you), I will likely specify it as a separate
   1.194 +    // field.
   1.195 +    uint32_t _code : 5;
   1.196 +    bool _isInvalid : 1;
   1.197 +    bool _isMissing : 1;
   1.198 +
   1.199 +    VFPRegister(int  r, RegType k)
   1.200 +      : kind(k), _code (r), _isInvalid(false), _isMissing(false)
   1.201 +    { }
   1.202 +
   1.203 +  public:
   1.204 +    VFPRegister()
   1.205 +      : _isInvalid(true), _isMissing(false)
   1.206 +    { }
   1.207 +
   1.208 +    VFPRegister(bool b)
   1.209 +      : _isInvalid(false), _isMissing(b)
   1.210 +    { }
   1.211 +
   1.212 +    VFPRegister(FloatRegister fr)
   1.213 +      : kind(Double), _code(fr.code()), _isInvalid(false), _isMissing(false)
   1.214 +    {
   1.215 +        JS_ASSERT(_code == (unsigned)fr.code());
   1.216 +    }
   1.217 +
   1.218 +    VFPRegister(FloatRegister fr, RegType k)
   1.219 +      : kind(k), _code (fr.code()), _isInvalid(false), _isMissing(false)
   1.220 +    {
   1.221 +        JS_ASSERT(_code == (unsigned)fr.code());
   1.222 +    }
   1.223 +    bool isDouble() const { return kind == Double; }
   1.224 +    bool isSingle() const { return kind == Single; }
   1.225 +    bool isFloat() const { return (kind == Double) || (kind == Single); }
   1.226 +    bool isInt() const { return (kind == UInt) || (kind == Int); }
   1.227 +    bool isSInt() const { return kind == Int; }
   1.228 +    bool isUInt() const { return kind == UInt; }
   1.229 +    bool equiv(VFPRegister other) const { return other.kind == kind; }
   1.230 +    size_t size() const { return (kind == Double) ? 8 : 4; }
   1.231 +    bool isInvalid();
   1.232 +    bool isMissing();
   1.233 +
   1.234 +    VFPRegister doubleOverlay() const;
   1.235 +    VFPRegister singleOverlay() const;
   1.236 +    VFPRegister sintOverlay() const;
   1.237 +    VFPRegister uintOverlay() const;
   1.238 +
   1.239 +    struct VFPRegIndexSplit;
   1.240 +    VFPRegIndexSplit encode();
   1.241 +
   1.242 +    // for serializing values
   1.243 +    struct VFPRegIndexSplit {
   1.244 +        const uint32_t block : 4;
   1.245 +        const uint32_t bit : 1;
   1.246 +
   1.247 +      private:
   1.248 +        friend VFPRegIndexSplit js::jit::VFPRegister::encode();
   1.249 +
   1.250 +        VFPRegIndexSplit (uint32_t block_, uint32_t bit_)
   1.251 +          : block(block_), bit(bit_)
   1.252 +        {
   1.253 +            JS_ASSERT (block == block_);
   1.254 +            JS_ASSERT(bit == bit_);
   1.255 +        }
   1.256 +    };
   1.257 +
   1.258 +    uint32_t code() const {
   1.259 +        return _code;
   1.260 +    }
   1.261 +};
   1.262 +
   1.263 +// For being passed into the generic vfp instruction generator when
   1.264 +// there is an instruction that only takes two registers
   1.265 +extern VFPRegister NoVFPRegister;
   1.266 +
   1.267 +struct ImmTag : public Imm32
   1.268 +{
   1.269 +    ImmTag(JSValueTag mask)
   1.270 +      : Imm32(int32_t(mask))
   1.271 +    { }
   1.272 +};
   1.273 +
   1.274 +struct ImmType : public ImmTag
   1.275 +{
   1.276 +    ImmType(JSValueType type)
   1.277 +      : ImmTag(JSVAL_TYPE_TO_TAG(type))
   1.278 +    { }
   1.279 +};
   1.280 +
   1.281 +enum Index {
   1.282 +    Offset = 0 << 21 | 1<<24,
   1.283 +    PreIndex = 1<<21 | 1 << 24,
   1.284 +    PostIndex = 0 << 21 | 0 << 24
   1.285 +    // The docs were rather unclear on this. it sounds like
   1.286 +    // 1<<21 | 0 << 24 encodes dtrt
   1.287 +};
   1.288 +
   1.289 +// Seriously, wtf arm
   1.290 +enum IsImmOp2_ {
   1.291 +    IsImmOp2    = 1 << 25,
   1.292 +    IsNotImmOp2 = 0 << 25
   1.293 +};
   1.294 +enum IsImmDTR_ {
   1.295 +    IsImmDTR    = 0 << 25,
   1.296 +    IsNotImmDTR = 1 << 25
   1.297 +};
   1.298 +// For the extra memory operations, ldrd, ldrsb, ldrh
   1.299 +enum IsImmEDTR_ {
   1.300 +    IsImmEDTR    = 1 << 22,
   1.301 +    IsNotImmEDTR = 0 << 22
   1.302 +};
   1.303 +
   1.304 +
   1.305 +enum ShiftType {
   1.306 +    LSL = 0, // << 5
   1.307 +    LSR = 1, // << 5
   1.308 +    ASR = 2, // << 5
   1.309 +    ROR = 3, // << 5
   1.310 +    RRX = ROR // RRX is encoded as ROR with a 0 offset.
   1.311 +};
   1.312 +
   1.313 +// The actual codes that get set by instructions
   1.314 +// and the codes that are checked by the conditions below.
   1.315 +struct ConditionCodes
   1.316 +{
   1.317 +    bool Zero : 1;
   1.318 +    bool Overflow : 1;
   1.319 +    bool Carry : 1;
   1.320 +    bool Minus : 1;
   1.321 +};
   1.322 +
   1.323 +// Modes for STM/LDM.
   1.324 +// Names are the suffixes applied to
   1.325 +// the instruction.
   1.326 +enum DTMMode {
   1.327 +    A = 0 << 24, // empty / after
   1.328 +    B = 1 << 24, // full / before
   1.329 +    D = 0 << 23, // decrement
   1.330 +    I = 1 << 23, // increment
   1.331 +    DA = D | A,
   1.332 +    DB = D | B,
   1.333 +    IA = I | A,
   1.334 +    IB = I | B
   1.335 +};
   1.336 +
   1.337 +enum DTMWriteBack {
   1.338 +    WriteBack   = 1 << 21,
   1.339 +    NoWriteBack = 0 << 21
   1.340 +};
   1.341 +
   1.342 +enum SetCond_ {
   1.343 +    SetCond   = 1 << 20,
   1.344 +    NoSetCond = 0 << 20
   1.345 +};
   1.346 +enum LoadStore {
   1.347 +    IsLoad  = 1 << 20,
   1.348 +    IsStore = 0 << 20
   1.349 +};
   1.350 +// You almost never want to use this directly.
   1.351 +// Instead, you wantto pass in a signed constant,
   1.352 +// and let this bit be implicitly set for you.
   1.353 +// this is however, necessary if we want a negative index
   1.354 +enum IsUp_ {
   1.355 +    IsUp   = 1 << 23,
   1.356 +    IsDown = 0 << 23
   1.357 +};
   1.358 +enum ALUOp {
   1.359 +    op_mov = 0xd << 21,
   1.360 +    op_mvn = 0xf << 21,
   1.361 +    op_and = 0x0 << 21,
   1.362 +    op_bic = 0xe << 21,
   1.363 +    op_eor = 0x1 << 21,
   1.364 +    op_orr = 0xc << 21,
   1.365 +    op_adc = 0x5 << 21,
   1.366 +    op_add = 0x4 << 21,
   1.367 +    op_sbc = 0x6 << 21,
   1.368 +    op_sub = 0x2 << 21,
   1.369 +    op_rsb = 0x3 << 21,
   1.370 +    op_rsc = 0x7 << 21,
   1.371 +    op_cmn = 0xb << 21,
   1.372 +    op_cmp = 0xa << 21,
   1.373 +    op_teq = 0x9 << 21,
   1.374 +    op_tst = 0x8 << 21,
   1.375 +    op_invalid = -1
   1.376 +};
   1.377 +
   1.378 +
   1.379 +enum MULOp {
   1.380 +    opm_mul   = 0 << 21,
   1.381 +    opm_mla   = 1 << 21,
   1.382 +    opm_umaal = 2 << 21,
   1.383 +    opm_mls   = 3 << 21,
   1.384 +    opm_umull = 4 << 21,
   1.385 +    opm_umlal = 5 << 21,
   1.386 +    opm_smull = 6 << 21,
   1.387 +    opm_smlal = 7 << 21
   1.388 +};
   1.389 +enum BranchTag {
   1.390 +    op_b = 0x0a000000,
   1.391 +    op_b_mask = 0x0f000000,
   1.392 +    op_b_dest_mask = 0x00ffffff,
   1.393 +    op_bl = 0x0b000000,
   1.394 +    op_blx = 0x012fff30,
   1.395 +    op_bx  = 0x012fff10
   1.396 +};
   1.397 +
   1.398 +// Just like ALUOp, but for the vfp instruction set.
   1.399 +enum VFPOp {
   1.400 +    opv_mul  = 0x2 << 20,
   1.401 +    opv_add  = 0x3 << 20,
   1.402 +    opv_sub  = 0x3 << 20 | 0x1 << 6,
   1.403 +    opv_div  = 0x8 << 20,
   1.404 +    opv_mov  = 0xB << 20 | 0x1 << 6,
   1.405 +    opv_abs  = 0xB << 20 | 0x3 << 6,
   1.406 +    opv_neg  = 0xB << 20 | 0x1 << 6 | 0x1 << 16,
   1.407 +    opv_sqrt = 0xB << 20 | 0x3 << 6 | 0x1 << 16,
   1.408 +    opv_cmp  = 0xB << 20 | 0x1 << 6 | 0x4 << 16,
   1.409 +    opv_cmpz  = 0xB << 20 | 0x1 << 6 | 0x5 << 16
   1.410 +};
   1.411 +// Negate the operation, AND negate the immediate that we were passed in.
   1.412 +ALUOp ALUNeg(ALUOp op, Register dest, Imm32 *imm, Register *negDest);
   1.413 +bool can_dbl(ALUOp op);
   1.414 +bool condsAreSafe(ALUOp op);
   1.415 +// If there is a variant of op that has a dest (think cmp/sub)
   1.416 +// return that variant of it.
   1.417 +ALUOp getDestVariant(ALUOp op);
   1.418 +
   1.419 +static const ValueOperand JSReturnOperand = ValueOperand(JSReturnReg_Type, JSReturnReg_Data);
   1.420 +static const ValueOperand softfpReturnOperand = ValueOperand(r1, r0);
   1.421 +// All of these classes exist solely to shuffle data into the various operands.
   1.422 +// For example Operand2 can be an imm8, a register-shifted-by-a-constant or
   1.423 +// a register-shifted-by-a-register.  I represent this in C++ by having a
   1.424 +// base class Operand2, which just stores the 32 bits of data as they will be
   1.425 +// encoded in the instruction.  You cannot directly create an Operand2
   1.426 +// since it is tricky, and not entirely sane to do so.  Instead, you create
   1.427 +// one of its child classes, e.g. Imm8.  Imm8's constructor takes a single
   1.428 +// integer argument.  Imm8 will verify that its argument can be encoded
   1.429 +// as an ARM 12 bit imm8, encode it using an Imm8data, and finally call
   1.430 +// its parent's (Operand2) constructor with the Imm8data.  The Operand2
   1.431 +// constructor will then call the Imm8data's encode() function to extract
   1.432 +// the raw bits from it.  In the future, we should be able to extract
   1.433 +// data from the Operand2 by asking it for its component Imm8data
   1.434 +// structures.  The reason this is so horribly round-about is I wanted
   1.435 +// to have Imm8 and RegisterShiftedRegister inherit directly from Operand2
   1.436 +// but have all of them take up only a single word of storage.
   1.437 +// I also wanted to avoid passing around raw integers at all
   1.438 +// since they are error prone.
   1.439 +class Op2Reg;
   1.440 +class O2RegImmShift;
   1.441 +class O2RegRegShift;
   1.442 +namespace datastore {
   1.443 +struct Reg
   1.444 +{
   1.445 +    // the "second register"
   1.446 +    uint32_t RM : 4;
   1.447 +    // do we get another register for shifting
   1.448 +    uint32_t RRS : 1;
   1.449 +    ShiftType Type : 2;
   1.450 +    // I'd like this to be a more sensible encoding, but that would
   1.451 +    // need to be a struct and that would not pack :(
   1.452 +    uint32_t ShiftAmount : 5;
   1.453 +    uint32_t pad : 20;
   1.454 +
   1.455 +    Reg(uint32_t rm, ShiftType type, uint32_t rsr, uint32_t shiftamount)
   1.456 +      : RM(rm), RRS(rsr), Type(type), ShiftAmount(shiftamount), pad(0)
   1.457 +    { }
   1.458 +
   1.459 +    uint32_t encode() {
   1.460 +        return RM | RRS << 4 | Type << 5 | ShiftAmount << 7;
   1.461 +    }
   1.462 +    explicit Reg(const Op2Reg &op) {
   1.463 +        memcpy(this, &op, sizeof(*this));
   1.464 +    }
   1.465 +};
   1.466 +
   1.467 +// Op2 has a mode labelled "<imm8m>", which is arm's magical
   1.468 +// immediate encoding.  Some instructions actually get 8 bits of
   1.469 +// data, which is called Imm8Data below.  These should have edit
   1.470 +// distance > 1, but this is how it is for now.
   1.471 +struct Imm8mData
   1.472 +{
   1.473 +  private:
   1.474 +    uint32_t data : 8;
   1.475 +    uint32_t rot : 4;
   1.476 +    // Throw in an extra bit that will be 1 if we can't encode this
   1.477 +    // properly.  if we can encode it properly, a simple "|" will still
   1.478 +    // suffice to meld it into the instruction.
   1.479 +    uint32_t buff : 19;
   1.480 +  public:
   1.481 +    uint32_t invalid : 1;
   1.482 +
   1.483 +    uint32_t encode() {
   1.484 +        JS_ASSERT(!invalid);
   1.485 +        return data | rot << 8;
   1.486 +    };
   1.487 +
   1.488 +    // Default constructor makes an invalid immediate.
   1.489 +    Imm8mData()
   1.490 +      : data(0xff), rot(0xf), invalid(1)
   1.491 +    { }
   1.492 +
   1.493 +    Imm8mData(uint32_t data_, uint32_t rot_)
   1.494 +      : data(data_), rot(rot_), invalid(0)
   1.495 +    {
   1.496 +        JS_ASSERT(data == data_);
   1.497 +        JS_ASSERT(rot == rot_);
   1.498 +    }
   1.499 +};
   1.500 +
   1.501 +struct Imm8Data
   1.502 +{
   1.503 +  private:
   1.504 +    uint32_t imm4L : 4;
   1.505 +    uint32_t pad : 4;
   1.506 +    uint32_t imm4H : 4;
   1.507 +
   1.508 +  public:
   1.509 +    uint32_t encode() {
   1.510 +        return imm4L | (imm4H << 8);
   1.511 +    };
   1.512 +    Imm8Data(uint32_t imm) : imm4L(imm&0xf), imm4H(imm>>4) {
   1.513 +        JS_ASSERT(imm <= 0xff);
   1.514 +    }
   1.515 +};
   1.516 +
   1.517 +// VLDR/VSTR take an 8 bit offset, which is implicitly left shifted
   1.518 +// by 2.
   1.519 +struct Imm8VFPOffData
   1.520 +{
   1.521 +  private:
   1.522 +    uint32_t data;
   1.523 +
   1.524 +  public:
   1.525 +    uint32_t encode() {
   1.526 +        return data;
   1.527 +    };
   1.528 +    Imm8VFPOffData(uint32_t imm) : data (imm) {
   1.529 +        JS_ASSERT((imm & ~(0xff)) == 0);
   1.530 +    }
   1.531 +};
   1.532 +
   1.533 +// ARM can magically encode 256 very special immediates to be moved
   1.534 +// into a register.
   1.535 +struct Imm8VFPImmData
   1.536 +{
   1.537 +  private:
   1.538 +    uint32_t imm4L : 4;
   1.539 +    uint32_t pad : 12;
   1.540 +    uint32_t imm4H : 4;
   1.541 +    int32_t isInvalid : 12;
   1.542 +
   1.543 +  public:
   1.544 +    Imm8VFPImmData()
   1.545 +      : imm4L(-1U & 0xf), imm4H(-1U & 0xf), isInvalid(-1)
   1.546 +    { }
   1.547 +
   1.548 +    Imm8VFPImmData(uint32_t imm)
   1.549 +      : imm4L(imm&0xf), imm4H(imm>>4), isInvalid(0)
   1.550 +    {
   1.551 +        JS_ASSERT(imm <= 0xff);
   1.552 +    }
   1.553 +
   1.554 +    uint32_t encode() {
   1.555 +        if (isInvalid != 0)
   1.556 +            return -1;
   1.557 +        return imm4L | (imm4H << 16);
   1.558 +    };
   1.559 +};
   1.560 +
   1.561 +struct Imm12Data
   1.562 +{
   1.563 +    uint32_t data : 12;
   1.564 +    uint32_t encode() {
   1.565 +        return data;
   1.566 +    }
   1.567 +
   1.568 +    Imm12Data(uint32_t imm)
   1.569 +      : data(imm)
   1.570 +    {
   1.571 +        JS_ASSERT(data == imm);
   1.572 +    }
   1.573 +
   1.574 +};
   1.575 +
   1.576 +struct RIS
   1.577 +{
   1.578 +    uint32_t ShiftAmount : 5;
   1.579 +    uint32_t encode () {
   1.580 +        return ShiftAmount;
   1.581 +    }
   1.582 +
   1.583 +    RIS(uint32_t imm)
   1.584 +      : ShiftAmount(imm)
   1.585 +    {
   1.586 +        JS_ASSERT(ShiftAmount == imm);
   1.587 +    }
   1.588 +    explicit RIS(Reg r) : ShiftAmount(r.ShiftAmount) {}
   1.589 +};
   1.590 +
   1.591 +struct RRS
   1.592 +{
   1.593 +    uint32_t MustZero : 1;
   1.594 +    // the register that holds the shift amount
   1.595 +    uint32_t RS : 4;
   1.596 +
   1.597 +    RRS(uint32_t rs)
   1.598 +      : RS(rs)
   1.599 +    {
   1.600 +        JS_ASSERT(rs == RS);
   1.601 +    }
   1.602 +
   1.603 +    uint32_t encode () {
   1.604 +        return RS << 1;
   1.605 +    }
   1.606 +};
   1.607 +
   1.608 +} // namespace datastore
   1.609 +
   1.610 +class MacroAssemblerARM;
   1.611 +class Operand;
   1.612 +class Operand2
   1.613 +{
   1.614 +    friend class Operand;
   1.615 +    friend class MacroAssemblerARM;
   1.616 +    friend class InstALU;
   1.617 +  public:
   1.618 +    uint32_t oper : 31;
   1.619 +    uint32_t invalid : 1;
   1.620 +    bool isO2Reg() {
   1.621 +        return !(oper & IsImmOp2);
   1.622 +    }
   1.623 +    Op2Reg toOp2Reg();
   1.624 +    bool isImm8() {
   1.625 +        return oper & IsImmOp2;
   1.626 +    }
   1.627 +
   1.628 +  protected:
   1.629 +    Operand2(datastore::Imm8mData base)
   1.630 +      : oper(base.invalid ? -1 : (base.encode() | (uint32_t)IsImmOp2)),
   1.631 +        invalid(base.invalid)
   1.632 +    { }
   1.633 +
   1.634 +    Operand2(datastore::Reg base)
   1.635 +      : oper(base.encode() | (uint32_t)IsNotImmOp2)
   1.636 +    { }
   1.637 +
   1.638 +  private:
   1.639 +    Operand2(int blob)
   1.640 +      : oper(blob)
   1.641 +    { }
   1.642 +
   1.643 +  public:
   1.644 +    uint32_t encode() {
   1.645 +        return oper;
   1.646 +    }
   1.647 +};
   1.648 +
   1.649 +class Imm8 : public Operand2
   1.650 +{
   1.651 +  public:
   1.652 +    static datastore::Imm8mData encodeImm(uint32_t imm) {
   1.653 +        // mozilla::CountLeadingZeroes32(imm) requires imm != 0.
   1.654 +        if (imm == 0)
   1.655 +            return datastore::Imm8mData(0, 0);
   1.656 +        int left = mozilla::CountLeadingZeroes32(imm) & 30;
   1.657 +        // See if imm is a simple value that can be encoded with a rotate of 0.
   1.658 +        // This is effectively imm <= 0xff, but I assume this can be optimized
   1.659 +        // more
   1.660 +        if (left >= 24)
   1.661 +            return datastore::Imm8mData(imm, 0);
   1.662 +
   1.663 +        // Mask out the 8 bits following the first bit that we found, see if we
   1.664 +        // have 0 yet.
   1.665 +        int no_imm = imm & ~(0xff << (24 - left));
   1.666 +        if (no_imm == 0) {
   1.667 +            return  datastore::Imm8mData(imm >> (24 - left), ((8+left) >> 1));
   1.668 +        }
   1.669 +        // Look for the most signifigant bit set, once again.
   1.670 +        int right = 32 - (mozilla::CountLeadingZeroes32(no_imm) & 30);
   1.671 +        // If it is in the bottom 8 bits, there is a chance that this is a
   1.672 +        // wraparound case.
   1.673 +        if (right >= 8)
   1.674 +            return datastore::Imm8mData();
   1.675 +        // Rather than masking out bits and checking for 0, just rotate the
   1.676 +        // immediate that we were passed in, and see if it fits into 8 bits.
   1.677 +        unsigned int mask = imm << (8 - right) | imm >> (24 + right);
   1.678 +        if (mask <= 0xff)
   1.679 +            return datastore::Imm8mData(mask, (8-right) >> 1);
   1.680 +        return datastore::Imm8mData();
   1.681 +    }
   1.682 +    // pair template?
   1.683 +    struct TwoImm8mData
   1.684 +    {
   1.685 +        datastore::Imm8mData fst, snd;
   1.686 +
   1.687 +        TwoImm8mData()
   1.688 +          : fst(), snd()
   1.689 +        { }
   1.690 +
   1.691 +        TwoImm8mData(datastore::Imm8mData _fst, datastore::Imm8mData _snd)
   1.692 +          : fst(_fst), snd(_snd)
   1.693 +        { }
   1.694 +    };
   1.695 +
   1.696 +    static TwoImm8mData encodeTwoImms(uint32_t);
   1.697 +    Imm8(uint32_t imm)
   1.698 +      : Operand2(encodeImm(imm))
   1.699 +    { }
   1.700 +};
   1.701 +
   1.702 +class Op2Reg : public Operand2
   1.703 +{
   1.704 +  public:
   1.705 +    Op2Reg(Register rm, ShiftType type, datastore::RIS shiftImm)
   1.706 +      : Operand2(datastore::Reg(rm.code(), type, 0, shiftImm.encode()))
   1.707 +    { }
   1.708 +
   1.709 +    Op2Reg(Register rm, ShiftType type, datastore::RRS shiftReg)
   1.710 +      : Operand2(datastore::Reg(rm.code(), type, 1, shiftReg.encode()))
   1.711 +    { }
   1.712 +    bool isO2RegImmShift() {
   1.713 +        datastore::Reg r(*this);
   1.714 +        return !r.RRS;
   1.715 +    }
   1.716 +    O2RegImmShift toO2RegImmShift();
   1.717 +    bool isO2RegRegShift() {
   1.718 +        datastore::Reg r(*this);
   1.719 +        return r.RRS;
   1.720 +    }
   1.721 +    O2RegRegShift toO2RegRegShift();
   1.722 +
   1.723 +    bool checkType(ShiftType type) {
   1.724 +        datastore::Reg r(*this);
   1.725 +        return r.Type == type;
   1.726 +    }
   1.727 +    bool checkRM(Register rm) {
   1.728 +        datastore::Reg r(*this);
   1.729 +        return r.RM == rm.code();
   1.730 +    }
   1.731 +    bool getRM(Register *rm) {
   1.732 +        datastore::Reg r(*this);
   1.733 +        *rm = Register::FromCode(r.RM);
   1.734 +        return true;
   1.735 +    }
   1.736 +};
   1.737 +
   1.738 +class O2RegImmShift : public Op2Reg
   1.739 +{
   1.740 +  public:
   1.741 +    O2RegImmShift(Register rn, ShiftType type, uint32_t shift)
   1.742 +      : Op2Reg(rn, type, datastore::RIS(shift))
   1.743 +    { }
   1.744 +    int getShift() {
   1.745 +        datastore::Reg r(*this);
   1.746 +        datastore::RIS ris(r);
   1.747 +        return ris.ShiftAmount;
   1.748 +    }
   1.749 +};
   1.750 +
   1.751 +class O2RegRegShift : public Op2Reg
   1.752 +{
   1.753 +  public:
   1.754 +    O2RegRegShift(Register rn, ShiftType type, Register rs)
   1.755 +      : Op2Reg(rn, type, datastore::RRS(rs.code()))
   1.756 +    { }
   1.757 +};
   1.758 +
   1.759 +O2RegImmShift O2Reg(Register r);
   1.760 +O2RegImmShift lsl (Register r, int amt);
   1.761 +O2RegImmShift lsr (Register r, int amt);
   1.762 +O2RegImmShift asr (Register r, int amt);
   1.763 +O2RegImmShift rol (Register r, int amt);
   1.764 +O2RegImmShift ror (Register r, int amt);
   1.765 +
   1.766 +O2RegRegShift lsl (Register r, Register amt);
   1.767 +O2RegRegShift lsr (Register r, Register amt);
   1.768 +O2RegRegShift asr (Register r, Register amt);
   1.769 +O2RegRegShift ror (Register r, Register amt);
   1.770 +
   1.771 +// An offset from a register to be used for ldr/str.  This should include
   1.772 +// the sign bit, since ARM has "signed-magnitude" offsets.  That is it encodes
   1.773 +// an unsigned offset, then the instruction specifies if the offset is positive
   1.774 +// or negative.  The +/- bit is necessary if the instruction set wants to be
   1.775 +// able to have a negative register offset e.g. ldr pc, [r1,-r2];
   1.776 +class DtrOff
   1.777 +{
   1.778 +    uint32_t data;
   1.779 +
   1.780 +  protected:
   1.781 +    DtrOff(datastore::Imm12Data immdata, IsUp_ iu)
   1.782 +      : data(immdata.encode() | (uint32_t)IsImmDTR | ((uint32_t)iu))
   1.783 +    { }
   1.784 +
   1.785 +    DtrOff(datastore::Reg reg, IsUp_ iu = IsUp)
   1.786 +      : data(reg.encode() | (uint32_t) IsNotImmDTR | iu)
   1.787 +    { }
   1.788 +
   1.789 +  public:
   1.790 +    uint32_t encode() { return data; }
   1.791 +};
   1.792 +
   1.793 +class DtrOffImm : public DtrOff
   1.794 +{
   1.795 +  public:
   1.796 +    DtrOffImm(int32_t imm)
   1.797 +      : DtrOff(datastore::Imm12Data(mozilla::Abs(imm)), imm >= 0 ? IsUp : IsDown)
   1.798 +    {
   1.799 +        JS_ASSERT(mozilla::Abs(imm) < 4096);
   1.800 +    }
   1.801 +};
   1.802 +
   1.803 +class DtrOffReg : public DtrOff
   1.804 +{
   1.805 +    // These are designed to be called by a constructor of a subclass.
   1.806 +    // Constructing the necessary RIS/RRS structures are annoying
   1.807 +  protected:
   1.808 +    DtrOffReg(Register rn, ShiftType type, datastore::RIS shiftImm, IsUp_ iu = IsUp)
   1.809 +      : DtrOff(datastore::Reg(rn.code(), type, 0, shiftImm.encode()), iu)
   1.810 +    { }
   1.811 +
   1.812 +    DtrOffReg(Register rn, ShiftType type, datastore::RRS shiftReg, IsUp_ iu = IsUp)
   1.813 +      : DtrOff(datastore::Reg(rn.code(), type, 1, shiftReg.encode()), iu)
   1.814 +    { }
   1.815 +};
   1.816 +
   1.817 +class DtrRegImmShift : public DtrOffReg
   1.818 +{
   1.819 +  public:
   1.820 +    DtrRegImmShift(Register rn, ShiftType type, uint32_t shift, IsUp_ iu = IsUp)
   1.821 +      : DtrOffReg(rn, type, datastore::RIS(shift), iu)
   1.822 +    { }
   1.823 +};
   1.824 +
   1.825 +class DtrRegRegShift : public DtrOffReg
   1.826 +{
   1.827 +  public:
   1.828 +    DtrRegRegShift(Register rn, ShiftType type, Register rs, IsUp_ iu = IsUp)
   1.829 +      : DtrOffReg(rn, type, datastore::RRS(rs.code()), iu)
   1.830 +    { }
   1.831 +};
   1.832 +
   1.833 +// we will frequently want to bundle a register with its offset so that we have
   1.834 +// an "operand" to a load instruction.
   1.835 +class DTRAddr
   1.836 +{
   1.837 +    uint32_t data;
   1.838 +
   1.839 +  public:
   1.840 +    DTRAddr(Register reg, DtrOff dtr)
   1.841 +      : data(dtr.encode() | (reg.code() << 16))
   1.842 +    { }
   1.843 +
   1.844 +    uint32_t encode() {
   1.845 +        return data;
   1.846 +    }
   1.847 +    Register getBase() {
   1.848 +        return Register::FromCode((data >> 16) &0xf);
   1.849 +    }
   1.850 +  private:
   1.851 +    friend class Operand;
   1.852 +    DTRAddr(uint32_t blob)
   1.853 +      : data(blob)
   1.854 +    { }
   1.855 +};
   1.856 +
   1.857 +// Offsets for the extended data transfer instructions:
   1.858 +// ldrsh, ldrd, ldrsb, etc.
   1.859 +class EDtrOff
   1.860 +{
   1.861 +    uint32_t data;
   1.862 +
   1.863 +  protected:
   1.864 +    EDtrOff(datastore::Imm8Data imm8, IsUp_ iu = IsUp)
   1.865 +      : data(imm8.encode() | IsImmEDTR | (uint32_t)iu)
   1.866 +    { }
   1.867 +
   1.868 +    EDtrOff(Register rm, IsUp_ iu = IsUp)
   1.869 +      : data(rm.code() | IsNotImmEDTR | iu)
   1.870 +    { }
   1.871 +
   1.872 +  public:
   1.873 +    uint32_t encode() {
   1.874 +        return data;
   1.875 +    }
   1.876 +};
   1.877 +
   1.878 +class EDtrOffImm : public EDtrOff
   1.879 +{
   1.880 +  public:
   1.881 +    EDtrOffImm(int32_t imm)
   1.882 +      : EDtrOff(datastore::Imm8Data(mozilla::Abs(imm)), (imm >= 0) ? IsUp : IsDown)
   1.883 +    {
   1.884 +        JS_ASSERT(mozilla::Abs(imm) < 256);
   1.885 +    }
   1.886 +};
   1.887 +
   1.888 +// this is the most-derived class, since the extended data
   1.889 +// transfer instructions don't support any sort of modifying the
   1.890 +// "index" operand
   1.891 +class EDtrOffReg : public EDtrOff
   1.892 +{
   1.893 +  public:
   1.894 +    EDtrOffReg(Register rm)
   1.895 +      : EDtrOff(rm)
   1.896 +    { }
   1.897 +};
   1.898 +
   1.899 +class EDtrAddr
   1.900 +{
   1.901 +    uint32_t data;
   1.902 +
   1.903 +  public:
   1.904 +    EDtrAddr(Register r, EDtrOff off)
   1.905 +      : data(RN(r) | off.encode())
   1.906 +    { }
   1.907 +
   1.908 +    uint32_t encode() {
   1.909 +        return data;
   1.910 +    }
   1.911 +};
   1.912 +
   1.913 +class VFPOff
   1.914 +{
   1.915 +    uint32_t data;
   1.916 +
   1.917 +  protected:
   1.918 +    VFPOff(datastore::Imm8VFPOffData imm, IsUp_ isup)
   1.919 +      : data(imm.encode() | (uint32_t)isup)
   1.920 +    { }
   1.921 +
   1.922 +  public:
   1.923 +    uint32_t encode() {
   1.924 +        return data;
   1.925 +    }
   1.926 +};
   1.927 +
   1.928 +class VFPOffImm : public VFPOff
   1.929 +{
   1.930 +  public:
   1.931 +    VFPOffImm(int32_t imm)
   1.932 +      : VFPOff(datastore::Imm8VFPOffData(mozilla::Abs(imm) / 4), imm < 0 ? IsDown : IsUp)
   1.933 +    {
   1.934 +        JS_ASSERT(mozilla::Abs(imm) <= 255 * 4);
   1.935 +    }
   1.936 +};
   1.937 +class VFPAddr
   1.938 +{
   1.939 +    friend class Operand;
   1.940 +
   1.941 +    uint32_t data;
   1.942 +
   1.943 +  protected:
   1.944 +    VFPAddr(uint32_t blob)
   1.945 +      : data(blob)
   1.946 +    { }
   1.947 +
   1.948 +  public:
   1.949 +    VFPAddr(Register base, VFPOff off)
   1.950 +      : data(RN(base) | off.encode())
   1.951 +    { }
   1.952 +
   1.953 +    uint32_t encode() {
   1.954 +        return data;
   1.955 +    }
   1.956 +};
   1.957 +
   1.958 +class VFPImm {
   1.959 +    uint32_t data;
   1.960 +
   1.961 +  public:
   1.962 +    static const VFPImm one;
   1.963 +
   1.964 +    VFPImm(uint32_t topWordOfDouble);
   1.965 +
   1.966 +    uint32_t encode() {
   1.967 +        return data;
   1.968 +    }
   1.969 +    bool isValid() {
   1.970 +        return data != -1U;
   1.971 +    }
   1.972 +};
   1.973 +
   1.974 +// A BOffImm is an immediate that is used for branches. Namely, it is the offset that will
   1.975 +// be encoded in the branch instruction. This is the only sane way of constructing a branch.
   1.976 +class BOffImm
   1.977 +{
   1.978 +    uint32_t data;
   1.979 +
   1.980 +  public:
   1.981 +    uint32_t encode() {
   1.982 +        return data;
   1.983 +    }
   1.984 +    int32_t decode() {
   1.985 +        return ((((int32_t)data) << 8) >> 6) + 8;
   1.986 +    }
   1.987 +
   1.988 +    explicit BOffImm(int offset)
   1.989 +      : data ((offset - 8) >> 2 & 0x00ffffff)
   1.990 +    {
   1.991 +        JS_ASSERT((offset & 0x3) == 0);
   1.992 +        if (!isInRange(offset))
   1.993 +            CrashAtUnhandlableOOM("BOffImm");
   1.994 +    }
   1.995 +    static bool isInRange(int offset)
   1.996 +    {
   1.997 +        if ((offset - 8) < -33554432)
   1.998 +            return false;
   1.999 +        if ((offset - 8) > 33554428)
  1.1000 +            return false;
  1.1001 +        return true;
  1.1002 +    }
  1.1003 +    static const int INVALID = 0x00800000;
  1.1004 +    BOffImm()
  1.1005 +      : data(INVALID)
  1.1006 +    { }
  1.1007 +
  1.1008 +    bool isInvalid() {
  1.1009 +        return data == uint32_t(INVALID);
  1.1010 +    }
  1.1011 +    Instruction *getDest(Instruction *src);
  1.1012 +
  1.1013 +  private:
  1.1014 +    friend class InstBranchImm;
  1.1015 +    BOffImm(Instruction &inst);
  1.1016 +};
  1.1017 +
  1.1018 +class Imm16
  1.1019 +{
  1.1020 +    uint32_t lower : 12;
  1.1021 +    uint32_t pad : 4;
  1.1022 +    uint32_t upper : 4;
  1.1023 +    uint32_t invalid : 12;
  1.1024 +
  1.1025 +  public:
  1.1026 +    Imm16();
  1.1027 +    Imm16(uint32_t imm);
  1.1028 +    Imm16(Instruction &inst);
  1.1029 +
  1.1030 +    uint32_t encode() {
  1.1031 +        return lower | upper << 16;
  1.1032 +    }
  1.1033 +    uint32_t decode() {
  1.1034 +        return lower | upper << 12;
  1.1035 +    }
  1.1036 +
  1.1037 +    bool isInvalid () {
  1.1038 +        return invalid;
  1.1039 +    }
  1.1040 +};
  1.1041 +
  1.1042 +/* I would preffer that these do not exist, since there are essentially
  1.1043 +* no instructions that would ever take more than one of these, however,
  1.1044 +* the MIR wants to only have one type of arguments to functions, so bugger.
  1.1045 +*/
  1.1046 +class Operand
  1.1047 +{
  1.1048 +    // the encoding of registers is the same for OP2, DTR and EDTR
  1.1049 +    // yet the type system doesn't let us express this, so choices
  1.1050 +    // must be made.
  1.1051 +  public:
  1.1052 +    enum Tag_ {
  1.1053 +        OP2,
  1.1054 +        MEM,
  1.1055 +        FOP
  1.1056 +    };
  1.1057 +
  1.1058 +  private:
  1.1059 +    Tag_ Tag : 3;
  1.1060 +    uint32_t reg : 5;
  1.1061 +    int32_t offset;
  1.1062 +    uint32_t data;
  1.1063 +
  1.1064 +  public:
  1.1065 +    Operand (Register reg_)
  1.1066 +      : Tag(OP2), reg(reg_.code())
  1.1067 +    { }
  1.1068 +
  1.1069 +    Operand (FloatRegister freg)
  1.1070 +      : Tag(FOP), reg(freg.code())
  1.1071 +    { }
  1.1072 +
  1.1073 +    Operand (Register base, Imm32 off)
  1.1074 +      : Tag(MEM), reg(base.code()), offset(off.value)
  1.1075 +    { }
  1.1076 +
  1.1077 +    Operand (Register base, int32_t off)
  1.1078 +      : Tag(MEM), reg(base.code()), offset(off)
  1.1079 +    { }
  1.1080 +
  1.1081 +    Operand (const Address &addr)
  1.1082 +      : Tag(MEM), reg(addr.base.code()), offset(addr.offset)
  1.1083 +    { }
  1.1084 +
  1.1085 +    Tag_ getTag() const {
  1.1086 +        return Tag;
  1.1087 +    }
  1.1088 +
  1.1089 +    Operand2 toOp2() const {
  1.1090 +        JS_ASSERT(Tag == OP2);
  1.1091 +        return O2Reg(Register::FromCode(reg));
  1.1092 +    }
  1.1093 +
  1.1094 +    Register toReg() const {
  1.1095 +        JS_ASSERT(Tag == OP2);
  1.1096 +        return Register::FromCode(reg);
  1.1097 +    }
  1.1098 +
  1.1099 +    void toAddr(Register *r, Imm32 *dest) const {
  1.1100 +        JS_ASSERT(Tag == MEM);
  1.1101 +        *r = Register::FromCode(reg);
  1.1102 +        *dest = Imm32(offset);
  1.1103 +    }
  1.1104 +    Address toAddress() const {
  1.1105 +        return Address(Register::FromCode(reg), offset);
  1.1106 +    }
  1.1107 +    int32_t disp() const {
  1.1108 +        JS_ASSERT(Tag == MEM);
  1.1109 +        return offset;
  1.1110 +    }
  1.1111 +
  1.1112 +    int32_t base() const {
  1.1113 +        JS_ASSERT(Tag == MEM);
  1.1114 +        return reg;
  1.1115 +    }
  1.1116 +    Register baseReg() const {
  1.1117 +        return Register::FromCode(reg);
  1.1118 +    }
  1.1119 +    DTRAddr toDTRAddr() const {
  1.1120 +        return DTRAddr(baseReg(), DtrOffImm(offset));
  1.1121 +    }
  1.1122 +    VFPAddr toVFPAddr() const {
  1.1123 +        return VFPAddr(baseReg(), VFPOffImm(offset));
  1.1124 +    }
  1.1125 +};
  1.1126 +
  1.1127 +void
  1.1128 +PatchJump(CodeLocationJump &jump_, CodeLocationLabel label);
  1.1129 +class InstructionIterator;
  1.1130 +class Assembler;
  1.1131 +typedef js::jit::AssemblerBufferWithConstantPool<1024, 4, Instruction, Assembler, 1> ARMBuffer;
  1.1132 +
  1.1133 +class Assembler : public AssemblerShared
  1.1134 +{
  1.1135 +  public:
  1.1136 +    // ARM conditional constants
  1.1137 +    enum ARMCondition {
  1.1138 +        EQ = 0x00000000, // Zero
  1.1139 +        NE = 0x10000000, // Non-zero
  1.1140 +        CS = 0x20000000,
  1.1141 +        CC = 0x30000000,
  1.1142 +        MI = 0x40000000,
  1.1143 +        PL = 0x50000000,
  1.1144 +        VS = 0x60000000,
  1.1145 +        VC = 0x70000000,
  1.1146 +        HI = 0x80000000,
  1.1147 +        LS = 0x90000000,
  1.1148 +        GE = 0xa0000000,
  1.1149 +        LT = 0xb0000000,
  1.1150 +        GT = 0xc0000000,
  1.1151 +        LE = 0xd0000000,
  1.1152 +        AL = 0xe0000000
  1.1153 +    };
  1.1154 +
  1.1155 +    enum Condition {
  1.1156 +        Equal = EQ,
  1.1157 +        NotEqual = NE,
  1.1158 +        Above = HI,
  1.1159 +        AboveOrEqual = CS,
  1.1160 +        Below = CC,
  1.1161 +        BelowOrEqual = LS,
  1.1162 +        GreaterThan = GT,
  1.1163 +        GreaterThanOrEqual = GE,
  1.1164 +        LessThan = LT,
  1.1165 +        LessThanOrEqual = LE,
  1.1166 +        Overflow = VS,
  1.1167 +        Signed = MI,
  1.1168 +        NotSigned = PL,
  1.1169 +        Zero = EQ,
  1.1170 +        NonZero = NE,
  1.1171 +        Always  = AL,
  1.1172 +
  1.1173 +        VFP_NotEqualOrUnordered = NE,
  1.1174 +        VFP_Equal = EQ,
  1.1175 +        VFP_Unordered = VS,
  1.1176 +        VFP_NotUnordered = VC,
  1.1177 +        VFP_GreaterThanOrEqualOrUnordered = CS,
  1.1178 +        VFP_GreaterThanOrEqual = GE,
  1.1179 +        VFP_GreaterThanOrUnordered = HI,
  1.1180 +        VFP_GreaterThan = GT,
  1.1181 +        VFP_LessThanOrEqualOrUnordered = LE,
  1.1182 +        VFP_LessThanOrEqual = LS,
  1.1183 +        VFP_LessThanOrUnordered = LT,
  1.1184 +        VFP_LessThan = CC // MI is valid too.
  1.1185 +    };
  1.1186 +
  1.1187 +    // Bit set when a DoubleCondition does not map to a single ARM condition.
  1.1188 +    // The macro assembler has to special-case these conditions, or else
  1.1189 +    // ConditionFromDoubleCondition will complain.
  1.1190 +    static const int DoubleConditionBitSpecial = 0x1;
  1.1191 +
  1.1192 +    enum DoubleCondition {
  1.1193 +        // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN.
  1.1194 +        DoubleOrdered = VFP_NotUnordered,
  1.1195 +        DoubleEqual = VFP_Equal,
  1.1196 +        DoubleNotEqual = VFP_NotEqualOrUnordered | DoubleConditionBitSpecial,
  1.1197 +        DoubleGreaterThan = VFP_GreaterThan,
  1.1198 +        DoubleGreaterThanOrEqual = VFP_GreaterThanOrEqual,
  1.1199 +        DoubleLessThan = VFP_LessThan,
  1.1200 +        DoubleLessThanOrEqual = VFP_LessThanOrEqual,
  1.1201 +        // If either operand is NaN, these conditions always evaluate to true.
  1.1202 +        DoubleUnordered = VFP_Unordered,
  1.1203 +        DoubleEqualOrUnordered = VFP_Equal | DoubleConditionBitSpecial,
  1.1204 +        DoubleNotEqualOrUnordered = VFP_NotEqualOrUnordered,
  1.1205 +        DoubleGreaterThanOrUnordered = VFP_GreaterThanOrUnordered,
  1.1206 +        DoubleGreaterThanOrEqualOrUnordered = VFP_GreaterThanOrEqualOrUnordered,
  1.1207 +        DoubleLessThanOrUnordered = VFP_LessThanOrUnordered,
  1.1208 +        DoubleLessThanOrEqualOrUnordered = VFP_LessThanOrEqualOrUnordered
  1.1209 +    };
  1.1210 +
  1.1211 +    Condition getCondition(uint32_t inst) {
  1.1212 +        return (Condition) (0xf0000000 & inst);
  1.1213 +    }
  1.1214 +    static inline Condition ConditionFromDoubleCondition(DoubleCondition cond) {
  1.1215 +        JS_ASSERT(!(cond & DoubleConditionBitSpecial));
  1.1216 +        return static_cast<Condition>(cond);
  1.1217 +    }
  1.1218 +
  1.1219 +    // :( this should be protected, but since CodeGenerator
  1.1220 +    // wants to use it, It needs to go out here :(
  1.1221 +
  1.1222 +    BufferOffset nextOffset() {
  1.1223 +        return m_buffer.nextOffset();
  1.1224 +    }
  1.1225 +
  1.1226 +  protected:
  1.1227 +    BufferOffset labelOffset (Label *l) {
  1.1228 +        return BufferOffset(l->bound());
  1.1229 +    }
  1.1230 +
  1.1231 +    Instruction * editSrc (BufferOffset bo) {
  1.1232 +        return m_buffer.getInst(bo);
  1.1233 +    }
  1.1234 +  public:
  1.1235 +    void resetCounter();
  1.1236 +    uint32_t actualOffset(uint32_t) const;
  1.1237 +    uint32_t actualIndex(uint32_t) const;
  1.1238 +    static uint8_t *PatchableJumpAddress(JitCode *code, uint32_t index);
  1.1239 +    BufferOffset actualOffset(BufferOffset) const;
  1.1240 +  protected:
  1.1241 +
  1.1242 +    // structure for fixing up pc-relative loads/jumps when a the machine code
  1.1243 +    // gets moved (executable copy, gc, etc.)
  1.1244 +    struct RelativePatch
  1.1245 +    {
  1.1246 +        void *target;
  1.1247 +        Relocation::Kind kind;
  1.1248 +        RelativePatch(void *target, Relocation::Kind kind)
  1.1249 +            : target(target), kind(kind)
  1.1250 +        { }
  1.1251 +    };
  1.1252 +
  1.1253 +    // TODO: this should actually be a pool-like object
  1.1254 +    //       It is currently a big hack, and probably shouldn't exist
  1.1255 +    js::Vector<CodeLabel, 0, SystemAllocPolicy> codeLabels_;
  1.1256 +    js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
  1.1257 +    js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpJumpRelocations_;
  1.1258 +    js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpDataRelocations_;
  1.1259 +    js::Vector<BufferOffset, 0, SystemAllocPolicy> tmpPreBarriers_;
  1.1260 +
  1.1261 +    CompactBufferWriter jumpRelocations_;
  1.1262 +    CompactBufferWriter dataRelocations_;
  1.1263 +    CompactBufferWriter relocations_;
  1.1264 +    CompactBufferWriter preBarriers_;
  1.1265 +
  1.1266 +    bool enoughMemory_;
  1.1267 +
  1.1268 +    //typedef JSC::AssemblerBufferWithConstantPool<1024, 4, 4, js::jit::Assembler> ARMBuffer;
  1.1269 +    ARMBuffer m_buffer;
  1.1270 +
  1.1271 +    // There is now a semi-unified interface for instruction generation.
  1.1272 +    // During assembly, there is an active buffer that instructions are
  1.1273 +    // being written into, but later, we may wish to modify instructions
  1.1274 +    // that have already been created.  In order to do this, we call the
  1.1275 +    // same assembly function, but pass it a destination address, which
  1.1276 +    // will be overwritten with a new instruction. In order to do this very
  1.1277 +    // after assembly buffers no longer exist, when calling with a third
  1.1278 +    // dest parameter, a this object is still needed.  dummy always happens
  1.1279 +    // to be null, but we shouldn't be looking at it in any case.
  1.1280 +    static Assembler *dummy;
  1.1281 +    mozilla::Array<Pool, 4> pools_;
  1.1282 +    Pool *int32Pool;
  1.1283 +    Pool *doublePool;
  1.1284 +
  1.1285 +  public:
  1.1286 +    Assembler()
  1.1287 +      : enoughMemory_(true),
  1.1288 +        m_buffer(4, 4, 0, &pools_[0], 8),
  1.1289 +        int32Pool(m_buffer.getPool(1)),
  1.1290 +        doublePool(m_buffer.getPool(0)),
  1.1291 +        isFinished(false),
  1.1292 +        dtmActive(false),
  1.1293 +        dtmCond(Always)
  1.1294 +    {
  1.1295 +    }
  1.1296 +
  1.1297 +    // We need to wait until an AutoIonContextAlloc is created by the
  1.1298 +    // IonMacroAssembler, before allocating any space.
  1.1299 +    void initWithAllocator() {
  1.1300 +        m_buffer.initWithAllocator();
  1.1301 +
  1.1302 +        // Set up the backwards double region
  1.1303 +        new (&pools_[2]) Pool (1024, 8, 4, 8, 8, m_buffer.LifoAlloc_, true);
  1.1304 +        // Set up the backwards 32 bit region
  1.1305 +        new (&pools_[3]) Pool (4096, 4, 4, 8, 4, m_buffer.LifoAlloc_, true, true);
  1.1306 +        // Set up the forwards double region
  1.1307 +        new (doublePool) Pool (1024, 8, 4, 8, 8, m_buffer.LifoAlloc_, false, false, &pools_[2]);
  1.1308 +        // Set up the forwards 32 bit region
  1.1309 +        new (int32Pool) Pool (4096, 4, 4, 8, 4, m_buffer.LifoAlloc_, false, true, &pools_[3]);
  1.1310 +        for (int i = 0; i < 4; i++) {
  1.1311 +            if (pools_[i].poolData == nullptr) {
  1.1312 +                m_buffer.fail_oom();
  1.1313 +                return;
  1.1314 +            }
  1.1315 +        }
  1.1316 +    }
  1.1317 +
  1.1318 +    static Condition InvertCondition(Condition cond);
  1.1319 +
  1.1320 +    // MacroAssemblers hold onto gcthings, so they are traced by the GC.
  1.1321 +    void trace(JSTracer *trc);
  1.1322 +    void writeRelocation(BufferOffset src) {
  1.1323 +        tmpJumpRelocations_.append(src);
  1.1324 +    }
  1.1325 +
  1.1326 +    // As opposed to x86/x64 version, the data relocation has to be executed
  1.1327 +    // before to recover the pointer, and not after.
  1.1328 +    void writeDataRelocation(const ImmGCPtr &ptr) {
  1.1329 +        if (ptr.value)
  1.1330 +            tmpDataRelocations_.append(nextOffset());
  1.1331 +    }
  1.1332 +    void writePrebarrierOffset(CodeOffsetLabel label) {
  1.1333 +        tmpPreBarriers_.append(BufferOffset(label.offset()));
  1.1334 +    }
  1.1335 +
  1.1336 +    enum RelocBranchStyle {
  1.1337 +        B_MOVWT,
  1.1338 +        B_LDR_BX,
  1.1339 +        B_LDR,
  1.1340 +        B_MOVW_ADD
  1.1341 +    };
  1.1342 +
  1.1343 +    enum RelocStyle {
  1.1344 +        L_MOVWT,
  1.1345 +        L_LDR
  1.1346 +    };
  1.1347 +
  1.1348 +  public:
  1.1349 +    // Given the start of a Control Flow sequence, grab the value that is finally branched to
  1.1350 +    // given the start of a function that loads an address into a register get the address that
  1.1351 +    // ends up in the register.
  1.1352 +    template <class Iter>
  1.1353 +    static const uint32_t * getCF32Target(Iter *iter);
  1.1354 +
  1.1355 +    static uintptr_t getPointer(uint8_t *);
  1.1356 +    template <class Iter>
  1.1357 +    static const uint32_t * getPtr32Target(Iter *iter, Register *dest = nullptr, RelocStyle *rs = nullptr);
  1.1358 +
  1.1359 +    bool oom() const;
  1.1360 +
  1.1361 +    void setPrinter(Sprinter *sp) {
  1.1362 +    }
  1.1363 +
  1.1364 +  private:
  1.1365 +    bool isFinished;
  1.1366 +  public:
  1.1367 +    void finish();
  1.1368 +    void executableCopy(void *buffer);
  1.1369 +    void copyJumpRelocationTable(uint8_t *dest);
  1.1370 +    void copyDataRelocationTable(uint8_t *dest);
  1.1371 +    void copyPreBarrierTable(uint8_t *dest);
  1.1372 +
  1.1373 +    bool addCodeLabel(CodeLabel label);
  1.1374 +    size_t numCodeLabels() const {
  1.1375 +        return codeLabels_.length();
  1.1376 +    }
  1.1377 +    CodeLabel codeLabel(size_t i) {
  1.1378 +        return codeLabels_[i];
  1.1379 +    }
  1.1380 +
  1.1381 +    // Size of the instruction stream, in bytes.
  1.1382 +    size_t size() const;
  1.1383 +    // Size of the jump relocation table, in bytes.
  1.1384 +    size_t jumpRelocationTableBytes() const;
  1.1385 +    size_t dataRelocationTableBytes() const;
  1.1386 +    size_t preBarrierTableBytes() const;
  1.1387 +
  1.1388 +    // Size of the data table, in bytes.
  1.1389 +    size_t bytesNeeded() const;
  1.1390 +
  1.1391 +    // Write a blob of binary into the instruction stream *OR*
  1.1392 +    // into a destination address. If dest is nullptr (the default), then the
  1.1393 +    // instruction gets written into the instruction stream. If dest is not null
  1.1394 +    // it is interpreted as a pointer to the location that we want the
  1.1395 +    // instruction to be written.
  1.1396 +    BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr);
  1.1397 +    // A static variant for the cases where we don't want to have an assembler
  1.1398 +    // object at all. Normally, you would use the dummy (nullptr) object.
  1.1399 +    static void writeInstStatic(uint32_t x, uint32_t *dest);
  1.1400 +
  1.1401 +  public:
  1.1402 +    void writeCodePointer(AbsoluteLabel *label);
  1.1403 +
  1.1404 +    BufferOffset align(int alignment);
  1.1405 +    BufferOffset as_nop();
  1.1406 +    BufferOffset as_alu(Register dest, Register src1, Operand2 op2,
  1.1407 +                ALUOp op, SetCond_ sc = NoSetCond, Condition c = Always, Instruction *instdest = nullptr);
  1.1408 +
  1.1409 +    BufferOffset as_mov(Register dest,
  1.1410 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always, Instruction *instdest = nullptr);
  1.1411 +    BufferOffset as_mvn(Register dest, Operand2 op2,
  1.1412 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1413 +    // logical operations
  1.1414 +    BufferOffset as_and(Register dest, Register src1,
  1.1415 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1416 +    BufferOffset as_bic(Register dest, Register src1,
  1.1417 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1418 +    BufferOffset as_eor(Register dest, Register src1,
  1.1419 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1420 +    BufferOffset as_orr(Register dest, Register src1,
  1.1421 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1422 +    // mathematical operations
  1.1423 +    BufferOffset as_adc(Register dest, Register src1,
  1.1424 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1425 +    BufferOffset as_add(Register dest, Register src1,
  1.1426 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1427 +    BufferOffset as_sbc(Register dest, Register src1,
  1.1428 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1429 +    BufferOffset as_sub(Register dest, Register src1,
  1.1430 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1431 +    BufferOffset as_rsb(Register dest, Register src1,
  1.1432 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1433 +    BufferOffset as_rsc(Register dest, Register src1,
  1.1434 +                Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
  1.1435 +    // test operations
  1.1436 +    BufferOffset as_cmn(Register src1, Operand2 op2,
  1.1437 +                Condition c = Always);
  1.1438 +    BufferOffset as_cmp(Register src1, Operand2 op2,
  1.1439 +                Condition c = Always);
  1.1440 +    BufferOffset as_teq(Register src1, Operand2 op2,
  1.1441 +                Condition c = Always);
  1.1442 +    BufferOffset as_tst(Register src1, Operand2 op2,
  1.1443 +                Condition c = Always);
  1.1444 +
  1.1445 +    // Not quite ALU worthy, but useful none the less:
  1.1446 +    // These also have the isue of these being formatted
  1.1447 +    // completly differently from the standard ALU operations.
  1.1448 +    BufferOffset as_movw(Register dest, Imm16 imm, Condition c = Always, Instruction *pos = nullptr);
  1.1449 +    BufferOffset as_movt(Register dest, Imm16 imm, Condition c = Always, Instruction *pos = nullptr);
  1.1450 +
  1.1451 +    BufferOffset as_genmul(Register d1, Register d2, Register rm, Register rn,
  1.1452 +                   MULOp op, SetCond_ sc, Condition c = Always);
  1.1453 +    BufferOffset as_mul(Register dest, Register src1, Register src2,
  1.1454 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1455 +    BufferOffset as_mla(Register dest, Register acc, Register src1, Register src2,
  1.1456 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1457 +    BufferOffset as_umaal(Register dest1, Register dest2, Register src1, Register src2,
  1.1458 +                  Condition c = Always);
  1.1459 +    BufferOffset as_mls(Register dest, Register acc, Register src1, Register src2,
  1.1460 +                Condition c = Always);
  1.1461 +    BufferOffset as_umull(Register dest1, Register dest2, Register src1, Register src2,
  1.1462 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1463 +    BufferOffset as_umlal(Register dest1, Register dest2, Register src1, Register src2,
  1.1464 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1465 +    BufferOffset as_smull(Register dest1, Register dest2, Register src1, Register src2,
  1.1466 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1467 +    BufferOffset as_smlal(Register dest1, Register dest2, Register src1, Register src2,
  1.1468 +                SetCond_ sc = NoSetCond, Condition c = Always);
  1.1469 +
  1.1470 +    BufferOffset as_sdiv(Register dest, Register num, Register div, Condition c = Always);
  1.1471 +    BufferOffset as_udiv(Register dest, Register num, Register div, Condition c = Always);
  1.1472 +
  1.1473 +    // Data transfer instructions: ldr, str, ldrb, strb.
  1.1474 +    // Using an int to differentiate between 8 bits and 32 bits is
  1.1475 +    // overkill, but meh
  1.1476 +    BufferOffset as_dtr(LoadStore ls, int size, Index mode,
  1.1477 +                Register rt, DTRAddr addr, Condition c = Always, uint32_t *dest = nullptr);
  1.1478 +    // Handles all of the other integral data transferring functions:
  1.1479 +    // ldrsb, ldrsh, ldrd, etc.
  1.1480 +    // size is given in bits.
  1.1481 +    BufferOffset as_extdtr(LoadStore ls, int size, bool IsSigned, Index mode,
  1.1482 +                   Register rt, EDtrAddr addr, Condition c = Always, uint32_t *dest = nullptr);
  1.1483 +
  1.1484 +    BufferOffset as_dtm(LoadStore ls, Register rn, uint32_t mask,
  1.1485 +                DTMMode mode, DTMWriteBack wb, Condition c = Always);
  1.1486 +    //overwrite a pool entry with new data.
  1.1487 +    void as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data);
  1.1488 +    // load a 32 bit immediate from a pool into a register
  1.1489 +    BufferOffset as_Imm32Pool(Register dest, uint32_t value, Condition c = Always);
  1.1490 +    // make a patchable jump that can target the entire 32 bit address space.
  1.1491 +    BufferOffset as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEntry *pe = nullptr, Condition c = Always);
  1.1492 +
  1.1493 +    // load a 64 bit floating point immediate from a pool into a register
  1.1494 +    BufferOffset as_FImm64Pool(VFPRegister dest, double value, Condition c = Always);
  1.1495 +    // load a 32 bit floating point immediate from a pool into a register
  1.1496 +    BufferOffset as_FImm32Pool(VFPRegister dest, float value, Condition c = Always);
  1.1497 +
  1.1498 +    // Control flow stuff:
  1.1499 +
  1.1500 +    // bx can *only* branch to a register
  1.1501 +    // never to an immediate.
  1.1502 +    BufferOffset as_bx(Register r, Condition c = Always, bool isPatchable = false);
  1.1503 +
  1.1504 +    // Branch can branch to an immediate *or* to a register.
  1.1505 +    // Branches to immediates are pc relative, branches to registers
  1.1506 +    // are absolute
  1.1507 +    BufferOffset as_b(BOffImm off, Condition c, bool isPatchable = false);
  1.1508 +
  1.1509 +    BufferOffset as_b(Label *l, Condition c = Always, bool isPatchable = false);
  1.1510 +    BufferOffset as_b(BOffImm off, Condition c, BufferOffset inst);
  1.1511 +
  1.1512 +    // blx can go to either an immediate or a register.
  1.1513 +    // When blx'ing to a register, we change processor mode
  1.1514 +    // depending on the low bit of the register
  1.1515 +    // when blx'ing to an immediate, we *always* change processor state.
  1.1516 +    BufferOffset as_blx(Label *l);
  1.1517 +
  1.1518 +    BufferOffset as_blx(Register r, Condition c = Always);
  1.1519 +    BufferOffset as_bl(BOffImm off, Condition c);
  1.1520 +    // bl can only branch+link to an immediate, never to a register
  1.1521 +    // it never changes processor state
  1.1522 +    BufferOffset as_bl();
  1.1523 +    // bl #imm can have a condition code, blx #imm cannot.
  1.1524 +    // blx reg can be conditional.
  1.1525 +    BufferOffset as_bl(Label *l, Condition c);
  1.1526 +    BufferOffset as_bl(BOffImm off, Condition c, BufferOffset inst);
  1.1527 +
  1.1528 +    BufferOffset as_mrs(Register r, Condition c = Always);
  1.1529 +    BufferOffset as_msr(Register r, Condition c = Always);
  1.1530 +    // VFP instructions!
  1.1531 +  private:
  1.1532 +
  1.1533 +    enum vfp_size {
  1.1534 +        isDouble = 1 << 8,
  1.1535 +        isSingle = 0 << 8
  1.1536 +    };
  1.1537 +
  1.1538 +    BufferOffset writeVFPInst(vfp_size sz, uint32_t blob, uint32_t *dest=nullptr);
  1.1539 +    // Unityped variants: all registers hold the same (ieee754 single/double)
  1.1540 +    // notably not included are vcvt; vmov vd, #imm; vmov rt, vn.
  1.1541 +    BufferOffset as_vfp_float(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1542 +                      VFPOp op, Condition c = Always);
  1.1543 +
  1.1544 +  public:
  1.1545 +    BufferOffset as_vadd(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1546 +                 Condition c = Always);
  1.1547 +
  1.1548 +    BufferOffset as_vdiv(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1549 +                 Condition c = Always);
  1.1550 +
  1.1551 +    BufferOffset as_vmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1552 +                 Condition c = Always);
  1.1553 +
  1.1554 +    BufferOffset as_vnmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1555 +                  Condition c = Always);
  1.1556 +
  1.1557 +    BufferOffset as_vnmla(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1558 +                  Condition c = Always);
  1.1559 +
  1.1560 +    BufferOffset as_vnmls(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1561 +                  Condition c = Always);
  1.1562 +
  1.1563 +    BufferOffset as_vneg(VFPRegister vd, VFPRegister vm, Condition c = Always);
  1.1564 +
  1.1565 +    BufferOffset as_vsqrt(VFPRegister vd, VFPRegister vm, Condition c = Always);
  1.1566 +
  1.1567 +    BufferOffset as_vabs(VFPRegister vd, VFPRegister vm, Condition c = Always);
  1.1568 +
  1.1569 +    BufferOffset as_vsub(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1570 +                 Condition c = Always);
  1.1571 +
  1.1572 +    BufferOffset as_vcmp(VFPRegister vd, VFPRegister vm,
  1.1573 +                 Condition c = Always);
  1.1574 +    BufferOffset as_vcmpz(VFPRegister vd,  Condition c = Always);
  1.1575 +
  1.1576 +    // specifically, a move between two same sized-registers
  1.1577 +    BufferOffset as_vmov(VFPRegister vd, VFPRegister vsrc, Condition c = Always);
  1.1578 +    /*xfer between Core and VFP*/
  1.1579 +    enum FloatToCore_ {
  1.1580 +        FloatToCore = 1 << 20,
  1.1581 +        CoreToFloat = 0 << 20
  1.1582 +    };
  1.1583 +
  1.1584 +  private:
  1.1585 +    enum VFPXferSize {
  1.1586 +        WordTransfer   = 0x02000010,
  1.1587 +        DoubleTransfer = 0x00400010
  1.1588 +    };
  1.1589 +
  1.1590 +  public:
  1.1591 +    // Unlike the next function, moving between the core registers and vfp
  1.1592 +    // registers can't be *that* properly typed.  Namely, since I don't want to
  1.1593 +    // munge the type VFPRegister to also include core registers.  Thus, the core
  1.1594 +    // and vfp registers are passed in based on their type, and src/dest is
  1.1595 +    // determined by the float2core.
  1.1596 +
  1.1597 +    BufferOffset as_vxfer(Register vt1, Register vt2, VFPRegister vm, FloatToCore_ f2c,
  1.1598 +                  Condition c = Always, int idx = 0);
  1.1599 +
  1.1600 +    // our encoding actually allows just the src and the dest (and theiyr types)
  1.1601 +    // to uniquely specify the encoding that we are going to use.
  1.1602 +    BufferOffset as_vcvt(VFPRegister vd, VFPRegister vm, bool useFPSCR = false,
  1.1603 +                         Condition c = Always);
  1.1604 +    // hard coded to a 32 bit fixed width result for now
  1.1605 +    BufferOffset as_vcvtFixed(VFPRegister vd, bool isSigned, uint32_t fixedPoint, bool toFixed, Condition c = Always);
  1.1606 +
  1.1607 +    /* xfer between VFP and memory*/
  1.1608 +    BufferOffset as_vdtr(LoadStore ls, VFPRegister vd, VFPAddr addr,
  1.1609 +                 Condition c = Always /* vfp doesn't have a wb option*/,
  1.1610 +                 uint32_t *dest = nullptr);
  1.1611 +
  1.1612 +    // VFP's ldm/stm work differently from the standard arm ones.
  1.1613 +    // You can only transfer a range
  1.1614 +
  1.1615 +    BufferOffset as_vdtm(LoadStore st, Register rn, VFPRegister vd, int length,
  1.1616 +                 /*also has update conditions*/Condition c = Always);
  1.1617 +
  1.1618 +    BufferOffset as_vimm(VFPRegister vd, VFPImm imm, Condition c = Always);
  1.1619 +
  1.1620 +    BufferOffset as_vmrs(Register r, Condition c = Always);
  1.1621 +    BufferOffset as_vmsr(Register r, Condition c = Always);
  1.1622 +    // label operations
  1.1623 +    bool nextLink(BufferOffset b, BufferOffset *next);
  1.1624 +    void bind(Label *label, BufferOffset boff = BufferOffset());
  1.1625 +    void bind(RepatchLabel *label);
  1.1626 +    uint32_t currentOffset() {
  1.1627 +        return nextOffset().getOffset();
  1.1628 +    }
  1.1629 +    void retarget(Label *label, Label *target);
  1.1630 +    // I'm going to pretend this doesn't exist for now.
  1.1631 +    void retarget(Label *label, void *target, Relocation::Kind reloc);
  1.1632 +
  1.1633 +    void Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address);
  1.1634 +
  1.1635 +    // See Bind
  1.1636 +    size_t labelOffsetToPatchOffset(size_t offset) {
  1.1637 +        return actualOffset(offset);
  1.1638 +    }
  1.1639 +
  1.1640 +    void call(Label *label);
  1.1641 +    void call(void *target);
  1.1642 +
  1.1643 +    void as_bkpt();
  1.1644 +
  1.1645 +  public:
  1.1646 +    static void TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
  1.1647 +    static void TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader);
  1.1648 +
  1.1649 +  protected:
  1.1650 +    void addPendingJump(BufferOffset src, ImmPtr target, Relocation::Kind kind) {
  1.1651 +        enoughMemory_ &= jumps_.append(RelativePatch(target.value, kind));
  1.1652 +        if (kind == Relocation::JITCODE)
  1.1653 +            writeRelocation(src);
  1.1654 +    }
  1.1655 +
  1.1656 +  public:
  1.1657 +    // The buffer is about to be linked, make sure any constant pools or excess
  1.1658 +    // bookkeeping has been flushed to the instruction stream.
  1.1659 +    void flush() {
  1.1660 +        JS_ASSERT(!isFinished);
  1.1661 +        m_buffer.flushPool();
  1.1662 +        return;
  1.1663 +    }
  1.1664 +
  1.1665 +    // Copy the assembly code to the given buffer, and perform any pending
  1.1666 +    // relocations relying on the target address.
  1.1667 +    void executableCopy(uint8_t *buffer);
  1.1668 +
  1.1669 +    // Actual assembly emitting functions.
  1.1670 +
  1.1671 +    // Since I can't think of a reasonable default for the mode, I'm going to
  1.1672 +    // leave it as a required argument.
  1.1673 +    void startDataTransferM(LoadStore ls, Register rm,
  1.1674 +                            DTMMode mode, DTMWriteBack update = NoWriteBack,
  1.1675 +                            Condition c = Always)
  1.1676 +    {
  1.1677 +        JS_ASSERT(!dtmActive);
  1.1678 +        dtmUpdate = update;
  1.1679 +        dtmBase = rm;
  1.1680 +        dtmLoadStore = ls;
  1.1681 +        dtmLastReg = -1;
  1.1682 +        dtmRegBitField = 0;
  1.1683 +        dtmActive = 1;
  1.1684 +        dtmCond = c;
  1.1685 +        dtmMode = mode;
  1.1686 +    }
  1.1687 +
  1.1688 +    void transferReg(Register rn) {
  1.1689 +        JS_ASSERT(dtmActive);
  1.1690 +        JS_ASSERT(rn.code() > dtmLastReg);
  1.1691 +        dtmRegBitField |= 1 << rn.code();
  1.1692 +        if (dtmLoadStore == IsLoad && rn.code() == 13 && dtmBase.code() == 13) {
  1.1693 +            MOZ_ASSUME_UNREACHABLE("ARM Spec says this is invalid");
  1.1694 +        }
  1.1695 +    }
  1.1696 +    void finishDataTransfer() {
  1.1697 +        dtmActive = false;
  1.1698 +        as_dtm(dtmLoadStore, dtmBase, dtmRegBitField, dtmMode, dtmUpdate, dtmCond);
  1.1699 +    }
  1.1700 +
  1.1701 +    void startFloatTransferM(LoadStore ls, Register rm,
  1.1702 +                             DTMMode mode, DTMWriteBack update = NoWriteBack,
  1.1703 +                             Condition c = Always)
  1.1704 +    {
  1.1705 +        JS_ASSERT(!dtmActive);
  1.1706 +        dtmActive = true;
  1.1707 +        dtmUpdate = update;
  1.1708 +        dtmLoadStore = ls;
  1.1709 +        dtmBase = rm;
  1.1710 +        dtmCond = c;
  1.1711 +        dtmLastReg = -1;
  1.1712 +        dtmMode = mode;
  1.1713 +        dtmDelta = 0;
  1.1714 +    }
  1.1715 +    void transferFloatReg(VFPRegister rn)
  1.1716 +    {
  1.1717 +        if (dtmLastReg == -1) {
  1.1718 +            vdtmFirstReg = rn.code();
  1.1719 +        } else {
  1.1720 +            if (dtmDelta == 0) {
  1.1721 +                dtmDelta = rn.code() - dtmLastReg;
  1.1722 +                JS_ASSERT(dtmDelta == 1 || dtmDelta == -1);
  1.1723 +            }
  1.1724 +            JS_ASSERT(dtmLastReg >= 0);
  1.1725 +            JS_ASSERT(rn.code() == unsigned(dtmLastReg) + dtmDelta);
  1.1726 +        }
  1.1727 +        dtmLastReg = rn.code();
  1.1728 +    }
  1.1729 +    void finishFloatTransfer() {
  1.1730 +        JS_ASSERT(dtmActive);
  1.1731 +        dtmActive = false;
  1.1732 +        JS_ASSERT(dtmLastReg != -1);
  1.1733 +        dtmDelta = dtmDelta ? dtmDelta : 1;
  1.1734 +        // fencepost problem.
  1.1735 +        int len = dtmDelta * (dtmLastReg - vdtmFirstReg) + 1;
  1.1736 +        as_vdtm(dtmLoadStore, dtmBase,
  1.1737 +                VFPRegister(FloatRegister::FromCode(Min(vdtmFirstReg, dtmLastReg))),
  1.1738 +                len, dtmCond);
  1.1739 +    }
  1.1740 +
  1.1741 +  private:
  1.1742 +    int dtmRegBitField;
  1.1743 +    int vdtmFirstReg;
  1.1744 +    int dtmLastReg;
  1.1745 +    int dtmDelta;
  1.1746 +    Register dtmBase;
  1.1747 +    DTMWriteBack dtmUpdate;
  1.1748 +    DTMMode dtmMode;
  1.1749 +    LoadStore dtmLoadStore;
  1.1750 +    bool dtmActive;
  1.1751 +    Condition dtmCond;
  1.1752 +
  1.1753 +  public:
  1.1754 +    enum {
  1.1755 +        padForAlign8  = (int)0x00,
  1.1756 +        padForAlign16 = (int)0x0000,
  1.1757 +        padForAlign32 = (int)0xe12fff7f  // 'bkpt 0xffff'
  1.1758 +    };
  1.1759 +
  1.1760 +    // API for speaking with the IonAssemblerBufferWithConstantPools
  1.1761 +    // generate an initial placeholder instruction that we want to later fix up
  1.1762 +    static void insertTokenIntoTag(uint32_t size, uint8_t *load, int32_t token);
  1.1763 +    // take the stub value that was written in before, and write in an actual load
  1.1764 +    // using the index we'd computed previously as well as the address of the pool start.
  1.1765 +    static bool patchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
  1.1766 +    // this is a callback for when we have filled a pool, and MUST flush it now.
  1.1767 +    // The pool requires the assembler to place a branch past the pool, and it
  1.1768 +    // calls this function.
  1.1769 +    static uint32_t placeConstantPoolBarrier(int offset);
  1.1770 +    // END API
  1.1771 +
  1.1772 +    // move our entire pool into the instruction stream
  1.1773 +    // This is to force an opportunistic dump of the pool, prefferably when it
  1.1774 +    // is more convenient to do a dump.
  1.1775 +    void dumpPool();
  1.1776 +    void flushBuffer();
  1.1777 +    void enterNoPool();
  1.1778 +    void leaveNoPool();
  1.1779 +    // this should return a BOffImm, but I didn't want to require everyplace that used the
  1.1780 +    // AssemblerBuffer to make that class.
  1.1781 +    static ptrdiff_t getBranchOffset(const Instruction *i);
  1.1782 +    static void retargetNearBranch(Instruction *i, int offset, Condition cond, bool final = true);
  1.1783 +    static void retargetNearBranch(Instruction *i, int offset, bool final = true);
  1.1784 +    static void retargetFarBranch(Instruction *i, uint8_t **slot, uint8_t *dest, Condition cond);
  1.1785 +
  1.1786 +    static void writePoolHeader(uint8_t *start, Pool *p, bool isNatural);
  1.1787 +    static void writePoolFooter(uint8_t *start, Pool *p, bool isNatural);
  1.1788 +    static void writePoolGuard(BufferOffset branch, Instruction *inst, BufferOffset dest);
  1.1789 +
  1.1790 +
  1.1791 +    static uint32_t patchWrite_NearCallSize();
  1.1792 +    static uint32_t nopSize() { return 4; }
  1.1793 +    static void patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall);
  1.1794 +    static void patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
  1.1795 +                                        PatchedImmPtr expectedValue);
  1.1796 +    static void patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue,
  1.1797 +                                        ImmPtr expectedValue);
  1.1798 +    static void patchWrite_Imm32(CodeLocationLabel label, Imm32 imm);
  1.1799 +    static uint32_t alignDoubleArg(uint32_t offset) {
  1.1800 +        return (offset+1)&~1;
  1.1801 +    }
  1.1802 +    static uint8_t *nextInstruction(uint8_t *instruction, uint32_t *count = nullptr);
  1.1803 +    // Toggle a jmp or cmp emitted by toggledJump().
  1.1804 +
  1.1805 +    static void ToggleToJmp(CodeLocationLabel inst_);
  1.1806 +    static void ToggleToCmp(CodeLocationLabel inst_);
  1.1807 +
  1.1808 +    static void ToggleCall(CodeLocationLabel inst_, bool enabled);
  1.1809 +
  1.1810 +    static void updateBoundsCheck(uint32_t logHeapSize, Instruction *inst);
  1.1811 +    void processCodeLabels(uint8_t *rawCode);
  1.1812 +    bool bailed() {
  1.1813 +        return m_buffer.bail();
  1.1814 +    }
  1.1815 +}; // Assembler
  1.1816 +
  1.1817 +// An Instruction is a structure for both encoding and decoding any and all ARM instructions.
  1.1818 +// many classes have not been implemented thusfar.
  1.1819 +class Instruction
  1.1820 +{
  1.1821 +    uint32_t data;
  1.1822 +
  1.1823 +  protected:
  1.1824 +    // This is not for defaulting to always, this is for instructions that
  1.1825 +    // cannot be made conditional, and have the usually invalid 4b1111 cond field
  1.1826 +    Instruction (uint32_t data_, bool fake = false) : data(data_ | 0xf0000000) {
  1.1827 +        JS_ASSERT (fake || ((data_ & 0xf0000000) == 0));
  1.1828 +    }
  1.1829 +    // Standard constructor
  1.1830 +    Instruction (uint32_t data_, Assembler::Condition c) : data(data_ | (uint32_t) c) {
  1.1831 +        JS_ASSERT ((data_ & 0xf0000000) == 0);
  1.1832 +    }
  1.1833 +    // You should never create an instruction directly.  You should create a
  1.1834 +    // more specific instruction which will eventually call one of these
  1.1835 +    // constructors for you.
  1.1836 +  public:
  1.1837 +    uint32_t encode() const {
  1.1838 +        return data;
  1.1839 +    }
  1.1840 +    // Check if this instruction is really a particular case
  1.1841 +    template <class C>
  1.1842 +    bool is() const { return C::isTHIS(*this); }
  1.1843 +
  1.1844 +    // safely get a more specific variant of this pointer
  1.1845 +    template <class C>
  1.1846 +    C *as() const { return C::asTHIS(*this); }
  1.1847 +
  1.1848 +    const Instruction & operator=(const Instruction &src) {
  1.1849 +        data = src.data;
  1.1850 +        return *this;
  1.1851 +    }
  1.1852 +    // Since almost all instructions have condition codes, the condition
  1.1853 +    // code extractor resides in the base class.
  1.1854 +    void extractCond(Assembler::Condition *c) {
  1.1855 +        if (data >> 28 != 0xf )
  1.1856 +            *c = (Assembler::Condition)(data & 0xf0000000);
  1.1857 +    }
  1.1858 +    // Get the next instruction in the instruction stream.
  1.1859 +    // This does neat things like ignoreconstant pools and their guards.
  1.1860 +    Instruction *next();
  1.1861 +
  1.1862 +    // Sometimes, an api wants a uint32_t (or a pointer to it) rather than
  1.1863 +    // an instruction.  raw() just coerces this into a pointer to a uint32_t
  1.1864 +    const uint32_t *raw() const { return &data; }
  1.1865 +    uint32_t size() const { return 4; }
  1.1866 +}; // Instruction
  1.1867 +
  1.1868 +// make sure that it is the right size
  1.1869 +JS_STATIC_ASSERT(sizeof(Instruction) == 4);
  1.1870 +
  1.1871 +// Data Transfer Instructions
  1.1872 +class InstDTR : public Instruction
  1.1873 +{
  1.1874 +  public:
  1.1875 +    enum IsByte_ {
  1.1876 +        IsByte = 0x00400000,
  1.1877 +        IsWord = 0x00000000
  1.1878 +    };
  1.1879 +    static const int IsDTR     = 0x04000000;
  1.1880 +    static const int IsDTRMask = 0x0c000000;
  1.1881 +
  1.1882 +    // TODO: Replace the initialization with something that is safer.
  1.1883 +    InstDTR(LoadStore ls, IsByte_ ib, Index mode, Register rt, DTRAddr addr, Assembler::Condition c)
  1.1884 +      : Instruction(ls | ib | mode | RT(rt) | addr.encode() | IsDTR, c)
  1.1885 +    { }
  1.1886 +
  1.1887 +    static bool isTHIS(const Instruction &i);
  1.1888 +    static InstDTR *asTHIS(const Instruction &i);
  1.1889 +
  1.1890 +};
  1.1891 +JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(Instruction));
  1.1892 +
  1.1893 +class InstLDR : public InstDTR
  1.1894 +{
  1.1895 +  public:
  1.1896 +    InstLDR(Index mode, Register rt, DTRAddr addr, Assembler::Condition c)
  1.1897 +        : InstDTR(IsLoad, IsWord, mode, rt, addr, c)
  1.1898 +    { }
  1.1899 +    static bool isTHIS(const Instruction &i);
  1.1900 +    static InstLDR *asTHIS(const Instruction &i);
  1.1901 +
  1.1902 +};
  1.1903 +JS_STATIC_ASSERT(sizeof(InstDTR) == sizeof(InstLDR));
  1.1904 +
  1.1905 +class InstNOP : public Instruction
  1.1906 +{
  1.1907 +    static const uint32_t NopInst = 0x0320f000;
  1.1908 +
  1.1909 +  public:
  1.1910 +    InstNOP()
  1.1911 +      : Instruction(NopInst, Assembler::Always)
  1.1912 +    { }
  1.1913 +
  1.1914 +    static bool isTHIS(const Instruction &i);
  1.1915 +    static InstNOP *asTHIS(Instruction &i);
  1.1916 +};
  1.1917 +
  1.1918 +// Branching to a register, or calling a register
  1.1919 +class InstBranchReg : public Instruction
  1.1920 +{
  1.1921 +  protected:
  1.1922 +    // Don't use BranchTag yourself, use a derived instruction.
  1.1923 +    enum BranchTag {
  1.1924 +        IsBX  = 0x012fff10,
  1.1925 +        IsBLX = 0x012fff30
  1.1926 +    };
  1.1927 +    static const uint32_t IsBRegMask = 0x0ffffff0;
  1.1928 +    InstBranchReg(BranchTag tag, Register rm, Assembler::Condition c)
  1.1929 +      : Instruction(tag | rm.code(), c)
  1.1930 +    { }
  1.1931 +  public:
  1.1932 +    static bool isTHIS (const Instruction &i);
  1.1933 +    static InstBranchReg *asTHIS (const Instruction &i);
  1.1934 +    // Get the register that is being branched to
  1.1935 +    void extractDest(Register *dest);
  1.1936 +    // Make sure we are branching to a pre-known register
  1.1937 +    bool checkDest(Register dest);
  1.1938 +};
  1.1939 +JS_STATIC_ASSERT(sizeof(InstBranchReg) == sizeof(Instruction));
  1.1940 +
  1.1941 +// Branching to an immediate offset, or calling an immediate offset
  1.1942 +class InstBranchImm : public Instruction
  1.1943 +{
  1.1944 +  protected:
  1.1945 +    enum BranchTag {
  1.1946 +        IsB   = 0x0a000000,
  1.1947 +        IsBL  = 0x0b000000
  1.1948 +    };
  1.1949 +    static const uint32_t IsBImmMask = 0x0f000000;
  1.1950 +
  1.1951 +    InstBranchImm(BranchTag tag, BOffImm off, Assembler::Condition c)
  1.1952 +      : Instruction(tag | off.encode(), c)
  1.1953 +    { }
  1.1954 +
  1.1955 +  public:
  1.1956 +    static bool isTHIS (const Instruction &i);
  1.1957 +    static InstBranchImm *asTHIS (const Instruction &i);
  1.1958 +    void extractImm(BOffImm *dest);
  1.1959 +};
  1.1960 +JS_STATIC_ASSERT(sizeof(InstBranchImm) == sizeof(Instruction));
  1.1961 +
  1.1962 +// Very specific branching instructions.
  1.1963 +class InstBXReg : public InstBranchReg
  1.1964 +{
  1.1965 +  public:
  1.1966 +    static bool isTHIS (const Instruction &i);
  1.1967 +    static InstBXReg *asTHIS (const Instruction &i);
  1.1968 +};
  1.1969 +class InstBLXReg : public InstBranchReg
  1.1970 +{
  1.1971 +  public:
  1.1972 +    InstBLXReg(Register reg, Assembler::Condition c)
  1.1973 +      : InstBranchReg(IsBLX, reg, c)
  1.1974 +    { }
  1.1975 +
  1.1976 +    static bool isTHIS (const Instruction &i);
  1.1977 +    static InstBLXReg *asTHIS (const Instruction &i);
  1.1978 +};
  1.1979 +class InstBImm : public InstBranchImm
  1.1980 +{
  1.1981 +  public:
  1.1982 +    InstBImm(BOffImm off, Assembler::Condition c)
  1.1983 +      : InstBranchImm(IsB, off, c)
  1.1984 +    { }
  1.1985 +
  1.1986 +    static bool isTHIS (const Instruction &i);
  1.1987 +    static InstBImm *asTHIS (const Instruction &i);
  1.1988 +};
  1.1989 +class InstBLImm : public InstBranchImm
  1.1990 +{
  1.1991 +  public:
  1.1992 +    InstBLImm(BOffImm off, Assembler::Condition c)
  1.1993 +      : InstBranchImm(IsBL, off, c)
  1.1994 +    { }
  1.1995 +
  1.1996 +    static bool isTHIS (const Instruction &i);
  1.1997 +    static InstBLImm *asTHIS (Instruction &i);
  1.1998 +};
  1.1999 +
  1.2000 +// Both movw and movt. The layout of both the immediate and the destination
  1.2001 +// register is the same so the code is being shared.
  1.2002 +class InstMovWT : public Instruction
  1.2003 +{
  1.2004 +  protected:
  1.2005 +    enum WT {
  1.2006 +        IsW = 0x03000000,
  1.2007 +        IsT = 0x03400000
  1.2008 +    };
  1.2009 +    static const uint32_t IsWTMask = 0x0ff00000;
  1.2010 +
  1.2011 +    InstMovWT(Register rd, Imm16 imm, WT wt, Assembler::Condition c)
  1.2012 +      : Instruction (RD(rd) | imm.encode() | wt, c)
  1.2013 +    { }
  1.2014 +
  1.2015 +  public:
  1.2016 +    void extractImm(Imm16 *dest);
  1.2017 +    void extractDest(Register *dest);
  1.2018 +    bool checkImm(Imm16 dest);
  1.2019 +    bool checkDest(Register dest);
  1.2020 +
  1.2021 +    static bool isTHIS (Instruction &i);
  1.2022 +    static InstMovWT *asTHIS (Instruction &i);
  1.2023 +
  1.2024 +};
  1.2025 +JS_STATIC_ASSERT(sizeof(InstMovWT) == sizeof(Instruction));
  1.2026 +
  1.2027 +class InstMovW : public InstMovWT
  1.2028 +{
  1.2029 +  public:
  1.2030 +    InstMovW (Register rd, Imm16 imm, Assembler::Condition c)
  1.2031 +      : InstMovWT(rd, imm, IsW, c)
  1.2032 +    { }
  1.2033 +
  1.2034 +    static bool isTHIS (const Instruction &i);
  1.2035 +    static InstMovW *asTHIS (const Instruction &i);
  1.2036 +};
  1.2037 +
  1.2038 +class InstMovT : public InstMovWT
  1.2039 +{
  1.2040 +  public:
  1.2041 +    InstMovT (Register rd, Imm16 imm, Assembler::Condition c)
  1.2042 +      : InstMovWT(rd, imm, IsT, c)
  1.2043 +    { }
  1.2044 +    static bool isTHIS (const Instruction &i);
  1.2045 +    static InstMovT *asTHIS (const Instruction &i);
  1.2046 +};
  1.2047 +
  1.2048 +class InstALU : public Instruction
  1.2049 +{
  1.2050 +    static const int32_t ALUMask = 0xc << 24;
  1.2051 +  public:
  1.2052 +    InstALU (Register rd, Register rn, Operand2 op2, ALUOp op, SetCond_ sc, Assembler::Condition c)
  1.2053 +        : Instruction(maybeRD(rd) | maybeRN(rn) | op2.encode() | op | sc, c)
  1.2054 +    { }
  1.2055 +    static bool isTHIS (const Instruction &i);
  1.2056 +    static InstALU *asTHIS (const Instruction &i);
  1.2057 +    void extractOp(ALUOp *ret);
  1.2058 +    bool checkOp(ALUOp op);
  1.2059 +    void extractDest(Register *ret);
  1.2060 +    bool checkDest(Register rd);
  1.2061 +    void extractOp1(Register *ret);
  1.2062 +    bool checkOp1(Register rn);
  1.2063 +    Operand2 extractOp2();
  1.2064 +};
  1.2065 +
  1.2066 +class InstCMP : public InstALU
  1.2067 +{
  1.2068 +  public:
  1.2069 +    static bool isTHIS (const Instruction &i);
  1.2070 +    static InstCMP *asTHIS (const Instruction &i);
  1.2071 +};
  1.2072 +
  1.2073 +class InstMOV : public InstALU
  1.2074 +{
  1.2075 +  public:
  1.2076 +    static bool isTHIS (const Instruction &i);
  1.2077 +    static InstMOV *asTHIS (const Instruction &i);
  1.2078 +};
  1.2079 +
  1.2080 +
  1.2081 +class InstructionIterator {
  1.2082 +  private:
  1.2083 +    Instruction *i;
  1.2084 +  public:
  1.2085 +    InstructionIterator(Instruction *i_);
  1.2086 +    Instruction *next() {
  1.2087 +        i = i->next();
  1.2088 +        return cur();
  1.2089 +    }
  1.2090 +    Instruction *cur() const {
  1.2091 +        return i;
  1.2092 +    }
  1.2093 +};
  1.2094 +
  1.2095 +static const uint32_t NumIntArgRegs = 4;
  1.2096 +static const uint32_t NumFloatArgRegs = 8;
  1.2097 +
  1.2098 +static inline bool
  1.2099 +GetIntArgReg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out)
  1.2100 +{
  1.2101 +    if (usedIntArgs >= NumIntArgRegs)
  1.2102 +        return false;
  1.2103 +    *out = Register::FromCode(usedIntArgs);
  1.2104 +    return true;
  1.2105 +}
  1.2106 +
  1.2107 +// Get a register in which we plan to put a quantity that will be used as an
  1.2108 +// integer argument.  This differs from GetIntArgReg in that if we have no more
  1.2109 +// actual argument registers to use we will fall back on using whatever
  1.2110 +// CallTempReg* don't overlap the argument registers, and only fail once those
  1.2111 +// run out too.
  1.2112 +static inline bool
  1.2113 +GetTempRegForIntArg(uint32_t usedIntArgs, uint32_t usedFloatArgs, Register *out)
  1.2114 +{
  1.2115 +    if (GetIntArgReg(usedIntArgs, usedFloatArgs, out))
  1.2116 +        return true;
  1.2117 +    // Unfortunately, we have to assume things about the point at which
  1.2118 +    // GetIntArgReg returns false, because we need to know how many registers it
  1.2119 +    // can allocate.
  1.2120 +    usedIntArgs -= NumIntArgRegs;
  1.2121 +    if (usedIntArgs >= NumCallTempNonArgRegs)
  1.2122 +        return false;
  1.2123 +    *out = CallTempNonArgRegs[usedIntArgs];
  1.2124 +    return true;
  1.2125 +}
  1.2126 +
  1.2127 +
  1.2128 +#if !defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
  1.2129 +
  1.2130 +static inline uint32_t
  1.2131 +GetArgStackDisp(uint32_t arg)
  1.2132 +{
  1.2133 +    JS_ASSERT(!useHardFpABI());
  1.2134 +    JS_ASSERT(arg >= NumIntArgRegs);
  1.2135 +    return (arg - NumIntArgRegs) * sizeof(intptr_t);
  1.2136 +}
  1.2137 +
  1.2138 +#endif
  1.2139 +
  1.2140 +
  1.2141 +#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_ARM_SIMULATOR)
  1.2142 +
  1.2143 +static inline bool
  1.2144 +GetFloatArgReg(uint32_t usedIntArgs, uint32_t usedFloatArgs, FloatRegister *out)
  1.2145 +{
  1.2146 +    JS_ASSERT(useHardFpABI());
  1.2147 +    if (usedFloatArgs >= NumFloatArgRegs)
  1.2148 +        return false;
  1.2149 +    *out = FloatRegister::FromCode(usedFloatArgs);
  1.2150 +    return true;
  1.2151 +}
  1.2152 +
  1.2153 +static inline uint32_t
  1.2154 +GetIntArgStackDisp(uint32_t usedIntArgs, uint32_t usedFloatArgs, uint32_t *padding)
  1.2155 +{
  1.2156 +    JS_ASSERT(useHardFpABI());
  1.2157 +    JS_ASSERT(usedIntArgs >= NumIntArgRegs);
  1.2158 +    uint32_t doubleSlots = Max(0, (int32_t)usedFloatArgs - (int32_t)NumFloatArgRegs);
  1.2159 +    doubleSlots *= 2;
  1.2160 +    int intSlots = usedIntArgs - NumIntArgRegs;
  1.2161 +    return (intSlots + doubleSlots + *padding) * sizeof(intptr_t);
  1.2162 +}
  1.2163 +
  1.2164 +static inline uint32_t
  1.2165 +GetFloat32ArgStackDisp(uint32_t usedIntArgs, uint32_t usedFloatArgs, uint32_t *padding)
  1.2166 +{
  1.2167 +    JS_ASSERT(useHardFpABI());
  1.2168 +    JS_ASSERT(usedFloatArgs >= NumFloatArgRegs);
  1.2169 +    uint32_t intSlots = 0;
  1.2170 +    if (usedIntArgs > NumIntArgRegs)
  1.2171 +        intSlots = usedIntArgs - NumIntArgRegs;
  1.2172 +    uint32_t float32Slots = usedFloatArgs - NumFloatArgRegs;
  1.2173 +    return (intSlots + float32Slots + *padding) * sizeof(intptr_t);
  1.2174 +}
  1.2175 +
  1.2176 +static inline uint32_t
  1.2177 +GetDoubleArgStackDisp(uint32_t usedIntArgs, uint32_t usedFloatArgs, uint32_t *padding)
  1.2178 +{
  1.2179 +    JS_ASSERT(useHardFpABI());
  1.2180 +    JS_ASSERT(usedFloatArgs >= NumFloatArgRegs);
  1.2181 +    uint32_t intSlots = 0;
  1.2182 +    if (usedIntArgs > NumIntArgRegs) {
  1.2183 +        intSlots = usedIntArgs - NumIntArgRegs;
  1.2184 +        // update the amount of padding required.
  1.2185 +        *padding += (*padding + usedIntArgs) % 2;
  1.2186 +    }
  1.2187 +    uint32_t doubleSlots = usedFloatArgs - NumFloatArgRegs;
  1.2188 +    doubleSlots *= 2;
  1.2189 +    return (intSlots + doubleSlots + *padding) * sizeof(intptr_t);
  1.2190 +}
  1.2191 +
  1.2192 +#endif
  1.2193 +
  1.2194 +
  1.2195 +
  1.2196 +class DoubleEncoder {
  1.2197 +    uint32_t rep(bool b, uint32_t count) {
  1.2198 +        uint32_t ret = 0;
  1.2199 +        for (uint32_t i = 0; i < count; i++)
  1.2200 +            ret = (ret << 1) | b;
  1.2201 +        return ret;
  1.2202 +    }
  1.2203 +
  1.2204 +    uint32_t encode(uint8_t value) {
  1.2205 +        //ARM ARM "VFP modified immediate constants"
  1.2206 +        // aBbbbbbb bbcdefgh 000...
  1.2207 +        // we want to return the top 32 bits of the double
  1.2208 +        // the rest are 0.
  1.2209 +        bool a = value >> 7;
  1.2210 +        bool b = value >> 6 & 1;
  1.2211 +        bool B = !b;
  1.2212 +        uint32_t cdefgh = value & 0x3f;
  1.2213 +        return a << 31 |
  1.2214 +            B << 30 |
  1.2215 +            rep(b, 8) << 22 |
  1.2216 +            cdefgh << 16;
  1.2217 +    }
  1.2218 +
  1.2219 +    struct DoubleEntry
  1.2220 +    {
  1.2221 +        uint32_t dblTop;
  1.2222 +        datastore::Imm8VFPImmData data;
  1.2223 +
  1.2224 +        DoubleEntry()
  1.2225 +          : dblTop(-1)
  1.2226 +        { }
  1.2227 +        DoubleEntry(uint32_t dblTop_, datastore::Imm8VFPImmData data_)
  1.2228 +          : dblTop(dblTop_), data(data_)
  1.2229 +        { }
  1.2230 +    };
  1.2231 +
  1.2232 +    mozilla::Array<DoubleEntry, 256> table;
  1.2233 +
  1.2234 +  public:
  1.2235 +    DoubleEncoder()
  1.2236 +    {
  1.2237 +        for (int i = 0; i < 256; i++) {
  1.2238 +            table[i] = DoubleEntry(encode(i), datastore::Imm8VFPImmData(i));
  1.2239 +        }
  1.2240 +    }
  1.2241 +
  1.2242 +    bool lookup(uint32_t top, datastore::Imm8VFPImmData *ret) {
  1.2243 +        for (int i = 0; i < 256; i++) {
  1.2244 +            if (table[i].dblTop == top) {
  1.2245 +                *ret = table[i].data;
  1.2246 +                return true;
  1.2247 +            }
  1.2248 +        }
  1.2249 +        return false;
  1.2250 +    }
  1.2251 +};
  1.2252 +
  1.2253 +class AutoForbidPools {
  1.2254 +    Assembler *masm_;
  1.2255 +  public:
  1.2256 +    AutoForbidPools(Assembler *masm) : masm_(masm) {
  1.2257 +        masm_->enterNoPool();
  1.2258 +    }
  1.2259 +    ~AutoForbidPools() {
  1.2260 +        masm_->leaveNoPool();
  1.2261 +    }
  1.2262 +};
  1.2263 +
  1.2264 +} // namespace jit
  1.2265 +} // namespace js
  1.2266 +
  1.2267 +#endif /* jit_arm_Assembler_arm_h */

mercurial