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

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jit/arm/Assembler-arm.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2759 @@
     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 +#include "jit/arm/Assembler-arm.h"
    1.11 +
    1.12 +#include "mozilla/DebugOnly.h"
    1.13 +#include "mozilla/MathAlgorithms.h"
    1.14 +
    1.15 +#include "jscompartment.h"
    1.16 +#include "jsutil.h"
    1.17 +
    1.18 +#include "assembler/jit/ExecutableAllocator.h"
    1.19 +#include "gc/Marking.h"
    1.20 +#include "jit/arm/MacroAssembler-arm.h"
    1.21 +#include "jit/JitCompartment.h"
    1.22 +
    1.23 +using namespace js;
    1.24 +using namespace js::jit;
    1.25 +
    1.26 +using mozilla::CountLeadingZeroes32;
    1.27 +
    1.28 +// Note this is used for inter-AsmJS calls and may pass arguments and results
    1.29 +// in floating point registers even if the system ABI does not.
    1.30 +ABIArgGenerator::ABIArgGenerator() :
    1.31 +    intRegIndex_(0),
    1.32 +    floatRegIndex_(0),
    1.33 +    stackOffset_(0),
    1.34 +    current_()
    1.35 +{}
    1.36 +
    1.37 +ABIArg
    1.38 +ABIArgGenerator::next(MIRType type)
    1.39 +{
    1.40 +    switch (type) {
    1.41 +      case MIRType_Int32:
    1.42 +      case MIRType_Pointer:
    1.43 +        if (intRegIndex_ == NumIntArgRegs) {
    1.44 +            current_ = ABIArg(stackOffset_);
    1.45 +            stackOffset_ += sizeof(uint32_t);
    1.46 +            break;
    1.47 +        }
    1.48 +        current_ = ABIArg(Register::FromCode(intRegIndex_));
    1.49 +        intRegIndex_++;
    1.50 +        break;
    1.51 +      case MIRType_Float32:
    1.52 +      case MIRType_Double:
    1.53 +        if (floatRegIndex_ == NumFloatArgRegs) {
    1.54 +            static const int align = sizeof(double) - 1;
    1.55 +            stackOffset_ = (stackOffset_ + align) & ~align;
    1.56 +            current_ = ABIArg(stackOffset_);
    1.57 +            stackOffset_ += sizeof(uint64_t);
    1.58 +            break;
    1.59 +        }
    1.60 +        current_ = ABIArg(FloatRegister::FromCode(floatRegIndex_));
    1.61 +        floatRegIndex_++;
    1.62 +        break;
    1.63 +      default:
    1.64 +        MOZ_ASSUME_UNREACHABLE("Unexpected argument type");
    1.65 +    }
    1.66 +
    1.67 +    return current_;
    1.68 +}
    1.69 +const Register ABIArgGenerator::NonArgReturnVolatileReg0 = r4;
    1.70 +const Register ABIArgGenerator::NonArgReturnVolatileReg1 = r5;
    1.71 +
    1.72 +// Encode a standard register when it is being used as src1, the dest, and
    1.73 +// an extra register. These should never be called with an InvalidReg.
    1.74 +uint32_t
    1.75 +js::jit::RT(Register r)
    1.76 +{
    1.77 +    JS_ASSERT((r.code() & ~0xf) == 0);
    1.78 +    return r.code() << 12;
    1.79 +}
    1.80 +
    1.81 +uint32_t
    1.82 +js::jit::RN(Register r)
    1.83 +{
    1.84 +    JS_ASSERT((r.code() & ~0xf) == 0);
    1.85 +    return r.code() << 16;
    1.86 +}
    1.87 +
    1.88 +uint32_t
    1.89 +js::jit::RD(Register r)
    1.90 +{
    1.91 +    JS_ASSERT((r.code() & ~0xf) == 0);
    1.92 +    return r.code() << 12;
    1.93 +}
    1.94 +
    1.95 +uint32_t
    1.96 +js::jit::RM(Register r)
    1.97 +{
    1.98 +    JS_ASSERT((r.code() & ~0xf) == 0);
    1.99 +    return r.code() << 8;
   1.100 +}
   1.101 +
   1.102 +// Encode a standard register when it is being used as src1, the dest, and
   1.103 +// an extra register.  For these, an InvalidReg is used to indicate a optional
   1.104 +// register that has been omitted.
   1.105 +uint32_t
   1.106 +js::jit::maybeRT(Register r)
   1.107 +{
   1.108 +    if (r == InvalidReg)
   1.109 +        return 0;
   1.110 +
   1.111 +    JS_ASSERT((r.code() & ~0xf) == 0);
   1.112 +    return r.code() << 12;
   1.113 +}
   1.114 +
   1.115 +uint32_t
   1.116 +js::jit::maybeRN(Register r)
   1.117 +{
   1.118 +    if (r == InvalidReg)
   1.119 +        return 0;
   1.120 +
   1.121 +    JS_ASSERT((r.code() & ~0xf) == 0);
   1.122 +    return r.code() << 16;
   1.123 +}
   1.124 +
   1.125 +uint32_t
   1.126 +js::jit::maybeRD(Register r)
   1.127 +{
   1.128 +    if (r == InvalidReg)
   1.129 +        return 0;
   1.130 +
   1.131 +    JS_ASSERT((r.code() & ~0xf) == 0);
   1.132 +    return r.code() << 12;
   1.133 +}
   1.134 +
   1.135 +Register
   1.136 +js::jit::toRD(Instruction &i)
   1.137 +{
   1.138 +    return Register::FromCode((i.encode()>>12) & 0xf);
   1.139 +}
   1.140 +Register
   1.141 +js::jit::toR(Instruction &i)
   1.142 +{
   1.143 +    return Register::FromCode(i.encode() & 0xf);
   1.144 +}
   1.145 +
   1.146 +Register
   1.147 +js::jit::toRM(Instruction &i)
   1.148 +{
   1.149 +    return Register::FromCode((i.encode()>>8) & 0xf);
   1.150 +}
   1.151 +
   1.152 +Register
   1.153 +js::jit::toRN(Instruction &i)
   1.154 +{
   1.155 +    return Register::FromCode((i.encode()>>16) & 0xf);
   1.156 +}
   1.157 +
   1.158 +uint32_t
   1.159 +js::jit::VD(VFPRegister vr)
   1.160 +{
   1.161 +    if (vr.isMissing())
   1.162 +        return 0;
   1.163 +
   1.164 +    //bits 15,14,13,12, 22
   1.165 +    VFPRegister::VFPRegIndexSplit s = vr.encode();
   1.166 +    return s.bit << 22 | s.block << 12;
   1.167 +}
   1.168 +uint32_t
   1.169 +js::jit::VN(VFPRegister vr)
   1.170 +{
   1.171 +    if (vr.isMissing())
   1.172 +        return 0;
   1.173 +
   1.174 +    // bits 19,18,17,16, 7
   1.175 +    VFPRegister::VFPRegIndexSplit s = vr.encode();
   1.176 +    return s.bit << 7 | s.block << 16;
   1.177 +}
   1.178 +uint32_t
   1.179 +js::jit::VM(VFPRegister vr)
   1.180 +{
   1.181 +    if (vr.isMissing())
   1.182 +        return 0;
   1.183 +
   1.184 +    // bits 5, 3,2,1,0
   1.185 +    VFPRegister::VFPRegIndexSplit s = vr.encode();
   1.186 +    return s.bit << 5 | s.block;
   1.187 +}
   1.188 +
   1.189 +VFPRegister::VFPRegIndexSplit
   1.190 +jit::VFPRegister::encode()
   1.191 +{
   1.192 +    JS_ASSERT(!_isInvalid);
   1.193 +
   1.194 +    switch (kind) {
   1.195 +      case Double:
   1.196 +        return VFPRegIndexSplit(_code &0xf , _code >> 4);
   1.197 +      case Single:
   1.198 +        return VFPRegIndexSplit(_code >> 1, _code & 1);
   1.199 +      default:
   1.200 +        // vfp register treated as an integer, NOT a gpr
   1.201 +        return VFPRegIndexSplit(_code >> 1, _code & 1);
   1.202 +    }
   1.203 +}
   1.204 +
   1.205 +VFPRegister js::jit::NoVFPRegister(true);
   1.206 +
   1.207 +bool
   1.208 +InstDTR::isTHIS(const Instruction &i)
   1.209 +{
   1.210 +    return (i.encode() & IsDTRMask) == (uint32_t)IsDTR;
   1.211 +}
   1.212 +
   1.213 +InstDTR *
   1.214 +InstDTR::asTHIS(const Instruction &i)
   1.215 +{
   1.216 +    if (isTHIS(i))
   1.217 +        return (InstDTR*)&i;
   1.218 +    return nullptr;
   1.219 +}
   1.220 +
   1.221 +bool
   1.222 +InstLDR::isTHIS(const Instruction &i)
   1.223 +{
   1.224 +    return (i.encode() & IsDTRMask) == (uint32_t)IsDTR;
   1.225 +}
   1.226 +
   1.227 +InstLDR *
   1.228 +InstLDR::asTHIS(const Instruction &i)
   1.229 +{
   1.230 +    if (isTHIS(i))
   1.231 +        return (InstLDR*)&i;
   1.232 +    return nullptr;
   1.233 +}
   1.234 +
   1.235 +InstNOP *
   1.236 +InstNOP::asTHIS(Instruction &i)
   1.237 +{
   1.238 +    if (isTHIS(i))
   1.239 +        return (InstNOP*) (&i);
   1.240 +    return nullptr;
   1.241 +}
   1.242 +
   1.243 +bool
   1.244 +InstNOP::isTHIS(const Instruction &i)
   1.245 +{
   1.246 +    return (i.encode() & 0x0fffffff) == NopInst;
   1.247 +}
   1.248 +
   1.249 +bool
   1.250 +InstBranchReg::isTHIS(const Instruction &i)
   1.251 +{
   1.252 +    return InstBXReg::isTHIS(i) || InstBLXReg::isTHIS(i);
   1.253 +}
   1.254 +
   1.255 +InstBranchReg *
   1.256 +InstBranchReg::asTHIS(const Instruction &i)
   1.257 +{
   1.258 +    if (isTHIS(i))
   1.259 +        return (InstBranchReg*)&i;
   1.260 +    return nullptr;
   1.261 +}
   1.262 +void
   1.263 +InstBranchReg::extractDest(Register *dest)
   1.264 +{
   1.265 +    *dest = toR(*this);
   1.266 +}
   1.267 +bool
   1.268 +InstBranchReg::checkDest(Register dest)
   1.269 +{
   1.270 +    return dest == toR(*this);
   1.271 +}
   1.272 +
   1.273 +bool
   1.274 +InstBranchImm::isTHIS(const Instruction &i)
   1.275 +{
   1.276 +    return InstBImm::isTHIS(i) || InstBLImm::isTHIS(i);
   1.277 +}
   1.278 +
   1.279 +InstBranchImm *
   1.280 +InstBranchImm::asTHIS(const Instruction &i)
   1.281 +{
   1.282 +    if (isTHIS(i))
   1.283 +        return (InstBranchImm*)&i;
   1.284 +    return nullptr;
   1.285 +}
   1.286 +
   1.287 +void
   1.288 +InstBranchImm::extractImm(BOffImm *dest)
   1.289 +{
   1.290 +    *dest = BOffImm(*this);
   1.291 +}
   1.292 +
   1.293 +bool
   1.294 +InstBXReg::isTHIS(const Instruction &i)
   1.295 +{
   1.296 +    return (i.encode() & IsBRegMask) == IsBX;
   1.297 +}
   1.298 +
   1.299 +InstBXReg *
   1.300 +InstBXReg::asTHIS(const Instruction &i)
   1.301 +{
   1.302 +    if (isTHIS(i))
   1.303 +        return (InstBXReg*)&i;
   1.304 +    return nullptr;
   1.305 +}
   1.306 +
   1.307 +bool
   1.308 +InstBLXReg::isTHIS(const Instruction &i)
   1.309 +{
   1.310 +    return (i.encode() & IsBRegMask) == IsBLX;
   1.311 +
   1.312 +}
   1.313 +InstBLXReg *
   1.314 +InstBLXReg::asTHIS(const Instruction &i)
   1.315 +{
   1.316 +    if (isTHIS(i))
   1.317 +        return (InstBLXReg*)&i;
   1.318 +    return nullptr;
   1.319 +}
   1.320 +
   1.321 +bool
   1.322 +InstBImm::isTHIS(const Instruction &i)
   1.323 +{
   1.324 +    return (i.encode () & IsBImmMask) == IsB;
   1.325 +}
   1.326 +InstBImm *
   1.327 +InstBImm::asTHIS(const Instruction &i)
   1.328 +{
   1.329 +    if (isTHIS(i))
   1.330 +        return (InstBImm*)&i;
   1.331 +    return nullptr;
   1.332 +}
   1.333 +
   1.334 +bool
   1.335 +InstBLImm::isTHIS(const Instruction &i)
   1.336 +{
   1.337 +    return (i.encode () & IsBImmMask) == IsBL;
   1.338 +
   1.339 +}
   1.340 +InstBLImm *
   1.341 +InstBLImm::asTHIS(Instruction &i)
   1.342 +{
   1.343 +    if (isTHIS(i))
   1.344 +        return (InstBLImm*)&i;
   1.345 +    return nullptr;
   1.346 +}
   1.347 +
   1.348 +bool
   1.349 +InstMovWT::isTHIS(Instruction &i)
   1.350 +{
   1.351 +    return  InstMovW::isTHIS(i) || InstMovT::isTHIS(i);
   1.352 +}
   1.353 +InstMovWT *
   1.354 +InstMovWT::asTHIS(Instruction &i)
   1.355 +{
   1.356 +    if (isTHIS(i))
   1.357 +        return (InstMovWT*)&i;
   1.358 +    return nullptr;
   1.359 +}
   1.360 +
   1.361 +void
   1.362 +InstMovWT::extractImm(Imm16 *imm)
   1.363 +{
   1.364 +    *imm = Imm16(*this);
   1.365 +}
   1.366 +bool
   1.367 +InstMovWT::checkImm(Imm16 imm)
   1.368 +{
   1.369 +    return imm.decode() == Imm16(*this).decode();
   1.370 +}
   1.371 +
   1.372 +void
   1.373 +InstMovWT::extractDest(Register *dest)
   1.374 +{
   1.375 +    *dest = toRD(*this);
   1.376 +}
   1.377 +bool
   1.378 +InstMovWT::checkDest(Register dest)
   1.379 +{
   1.380 +    return dest == toRD(*this);
   1.381 +}
   1.382 +
   1.383 +bool
   1.384 +InstMovW::isTHIS(const Instruction &i)
   1.385 +{
   1.386 +    return (i.encode() & IsWTMask) == IsW;
   1.387 +}
   1.388 +
   1.389 +InstMovW *
   1.390 +InstMovW::asTHIS(const Instruction &i)
   1.391 +{
   1.392 +    if (isTHIS(i))
   1.393 +        return (InstMovW*) (&i);
   1.394 +    return nullptr;
   1.395 +}
   1.396 +InstMovT *
   1.397 +InstMovT::asTHIS(const Instruction &i)
   1.398 +{
   1.399 +    if (isTHIS(i))
   1.400 +        return (InstMovT*) (&i);
   1.401 +    return nullptr;
   1.402 +}
   1.403 +
   1.404 +bool
   1.405 +InstMovT::isTHIS(const Instruction &i)
   1.406 +{
   1.407 +    return (i.encode() & IsWTMask) == IsT;
   1.408 +}
   1.409 +
   1.410 +InstALU *
   1.411 +InstALU::asTHIS(const Instruction &i)
   1.412 +{
   1.413 +    if (isTHIS(i))
   1.414 +        return (InstALU*) (&i);
   1.415 +    return nullptr;
   1.416 +}
   1.417 +bool
   1.418 +InstALU::isTHIS(const Instruction &i)
   1.419 +{
   1.420 +    return (i.encode() & ALUMask) == 0;
   1.421 +}
   1.422 +void
   1.423 +InstALU::extractOp(ALUOp *ret)
   1.424 +{
   1.425 +    *ret = ALUOp(encode() & (0xf << 21));
   1.426 +}
   1.427 +bool
   1.428 +InstALU::checkOp(ALUOp op)
   1.429 +{
   1.430 +    ALUOp mine;
   1.431 +    extractOp(&mine);
   1.432 +    return mine == op;
   1.433 +}
   1.434 +void
   1.435 +InstALU::extractDest(Register *ret)
   1.436 +{
   1.437 +    *ret = toRD(*this);
   1.438 +}
   1.439 +bool
   1.440 +InstALU::checkDest(Register rd)
   1.441 +{
   1.442 +    return rd == toRD(*this);
   1.443 +}
   1.444 +void
   1.445 +InstALU::extractOp1(Register *ret)
   1.446 +{
   1.447 +    *ret = toRN(*this);
   1.448 +}
   1.449 +bool
   1.450 +InstALU::checkOp1(Register rn)
   1.451 +{
   1.452 +    return rn == toRN(*this);
   1.453 +}
   1.454 +Operand2
   1.455 +InstALU::extractOp2()
   1.456 +{
   1.457 +    return Operand2(encode());
   1.458 +}
   1.459 +
   1.460 +InstCMP *
   1.461 +InstCMP::asTHIS(const Instruction &i)
   1.462 +{
   1.463 +    if (isTHIS(i))
   1.464 +        return (InstCMP*) (&i);
   1.465 +    return nullptr;
   1.466 +}
   1.467 +
   1.468 +bool
   1.469 +InstCMP::isTHIS(const Instruction &i)
   1.470 +{
   1.471 +    return InstALU::isTHIS(i) && InstALU::asTHIS(i)->checkDest(r0) && InstALU::asTHIS(i)->checkOp(op_cmp);
   1.472 +}
   1.473 +
   1.474 +InstMOV *
   1.475 +InstMOV::asTHIS(const Instruction &i)
   1.476 +{
   1.477 +    if (isTHIS(i))
   1.478 +        return (InstMOV*) (&i);
   1.479 +    return nullptr;
   1.480 +}
   1.481 +
   1.482 +bool
   1.483 +InstMOV::isTHIS(const Instruction &i)
   1.484 +{
   1.485 +    return InstALU::isTHIS(i) && InstALU::asTHIS(i)->checkOp1(r0) && InstALU::asTHIS(i)->checkOp(op_mov);
   1.486 +}
   1.487 +
   1.488 +Op2Reg
   1.489 +Operand2::toOp2Reg() {
   1.490 +    return *(Op2Reg*)this;
   1.491 +}
   1.492 +O2RegImmShift
   1.493 +Op2Reg::toO2RegImmShift() {
   1.494 +    return *(O2RegImmShift*)this;
   1.495 +}
   1.496 +O2RegRegShift
   1.497 +Op2Reg::toO2RegRegShift() {
   1.498 +    return *(O2RegRegShift*)this;
   1.499 +}
   1.500 +
   1.501 +Imm16::Imm16(Instruction &inst)
   1.502 +  : lower(inst.encode() & 0xfff),
   1.503 +    upper(inst.encode() >> 16),
   1.504 +    invalid(0xfff)
   1.505 +{ }
   1.506 +
   1.507 +Imm16::Imm16(uint32_t imm)
   1.508 +  : lower(imm & 0xfff), pad(0),
   1.509 +    upper((imm>>12) & 0xf),
   1.510 +    invalid(0)
   1.511 +{
   1.512 +    JS_ASSERT(decode() == imm);
   1.513 +}
   1.514 +
   1.515 +Imm16::Imm16()
   1.516 +  : invalid(0xfff)
   1.517 +{ }
   1.518 +
   1.519 +void
   1.520 +jit::PatchJump(CodeLocationJump &jump_, CodeLocationLabel label)
   1.521 +{
   1.522 +    // We need to determine if this jump can fit into the standard 24+2 bit address
   1.523 +    // or if we need a larger branch (or just need to use our pool entry)
   1.524 +    Instruction *jump = (Instruction*)jump_.raw();
   1.525 +    Assembler::Condition c;
   1.526 +    jump->extractCond(&c);
   1.527 +    JS_ASSERT(jump->is<InstBranchImm>() || jump->is<InstLDR>());
   1.528 +
   1.529 +    int jumpOffset = label.raw() - jump_.raw();
   1.530 +    if (BOffImm::isInRange(jumpOffset)) {
   1.531 +        // This instruction started off as a branch, and will remain one
   1.532 +        Assembler::retargetNearBranch(jump, jumpOffset, c);
   1.533 +    } else {
   1.534 +        // This instruction started off as a branch, but now needs to be demoted to an ldr.
   1.535 +        uint8_t **slot = reinterpret_cast<uint8_t**>(jump_.jumpTableEntry());
   1.536 +        Assembler::retargetFarBranch(jump, slot, label.raw(), c);
   1.537 +    }
   1.538 +}
   1.539 +
   1.540 +void
   1.541 +Assembler::finish()
   1.542 +{
   1.543 +    flush();
   1.544 +    JS_ASSERT(!isFinished);
   1.545 +    isFinished = true;
   1.546 +
   1.547 +    for (unsigned int i = 0; i < tmpDataRelocations_.length(); i++) {
   1.548 +        int offset = tmpDataRelocations_[i].getOffset();
   1.549 +        int real_offset = offset + m_buffer.poolSizeBefore(offset);
   1.550 +        dataRelocations_.writeUnsigned(real_offset);
   1.551 +    }
   1.552 +
   1.553 +    for (unsigned int i = 0; i < tmpJumpRelocations_.length(); i++) {
   1.554 +        int offset = tmpJumpRelocations_[i].getOffset();
   1.555 +        int real_offset = offset + m_buffer.poolSizeBefore(offset);
   1.556 +        jumpRelocations_.writeUnsigned(real_offset);
   1.557 +    }
   1.558 +
   1.559 +    for (unsigned int i = 0; i < tmpPreBarriers_.length(); i++) {
   1.560 +        int offset = tmpPreBarriers_[i].getOffset();
   1.561 +        int real_offset = offset + m_buffer.poolSizeBefore(offset);
   1.562 +        preBarriers_.writeUnsigned(real_offset);
   1.563 +    }
   1.564 +}
   1.565 +
   1.566 +void
   1.567 +Assembler::executableCopy(uint8_t *buffer)
   1.568 +{
   1.569 +    JS_ASSERT(isFinished);
   1.570 +    m_buffer.executableCopy(buffer);
   1.571 +    AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
   1.572 +}
   1.573 +
   1.574 +void
   1.575 +Assembler::resetCounter()
   1.576 +{
   1.577 +    m_buffer.resetCounter();
   1.578 +}
   1.579 +
   1.580 +uint32_t
   1.581 +Assembler::actualOffset(uint32_t off_) const
   1.582 +{
   1.583 +    return off_ + m_buffer.poolSizeBefore(off_);
   1.584 +}
   1.585 +
   1.586 +uint32_t
   1.587 +Assembler::actualIndex(uint32_t idx_) const
   1.588 +{
   1.589 +    ARMBuffer::PoolEntry pe(idx_);
   1.590 +    return m_buffer.poolEntryOffset(pe);
   1.591 +}
   1.592 +
   1.593 +uint8_t *
   1.594 +Assembler::PatchableJumpAddress(JitCode *code, uint32_t pe_)
   1.595 +{
   1.596 +    return code->raw() + pe_;
   1.597 +}
   1.598 +
   1.599 +BufferOffset
   1.600 +Assembler::actualOffset(BufferOffset off_) const
   1.601 +{
   1.602 +    return BufferOffset(off_.getOffset() + m_buffer.poolSizeBefore(off_.getOffset()));
   1.603 +}
   1.604 +
   1.605 +class RelocationIterator
   1.606 +{
   1.607 +    CompactBufferReader reader_;
   1.608 +    // offset in bytes
   1.609 +    uint32_t offset_;
   1.610 +
   1.611 +  public:
   1.612 +    RelocationIterator(CompactBufferReader &reader)
   1.613 +      : reader_(reader)
   1.614 +    { }
   1.615 +
   1.616 +    bool read() {
   1.617 +        if (!reader_.more())
   1.618 +            return false;
   1.619 +        offset_ = reader_.readUnsigned();
   1.620 +        return true;
   1.621 +    }
   1.622 +
   1.623 +    uint32_t offset() const {
   1.624 +        return offset_;
   1.625 +    }
   1.626 +};
   1.627 +
   1.628 +template<class Iter>
   1.629 +const uint32_t *
   1.630 +Assembler::getCF32Target(Iter *iter)
   1.631 +{
   1.632 +    Instruction *inst1 = iter->cur();
   1.633 +    Instruction *inst2 = iter->next();
   1.634 +    Instruction *inst3 = iter->next();
   1.635 +    Instruction *inst4 = iter->next();
   1.636 +
   1.637 +    if (inst1->is<InstBranchImm>()) {
   1.638 +        // see if we have a simple case, b #offset
   1.639 +        BOffImm imm;
   1.640 +        InstBranchImm *jumpB = inst1->as<InstBranchImm>();
   1.641 +        jumpB->extractImm(&imm);
   1.642 +        return imm.getDest(inst1)->raw();
   1.643 +    }
   1.644 +
   1.645 +    if (inst1->is<InstMovW>() && inst2->is<InstMovT>() &&
   1.646 +        (inst3->is<InstNOP>() || inst3->is<InstBranchReg>() || inst4->is<InstBranchReg>()))
   1.647 +    {
   1.648 +        // see if we have the complex case,
   1.649 +        // movw r_temp, #imm1
   1.650 +        // movt r_temp, #imm2
   1.651 +        // bx r_temp
   1.652 +        // OR
   1.653 +        // movw r_temp, #imm1
   1.654 +        // movt r_temp, #imm2
   1.655 +        // str pc, [sp]
   1.656 +        // bx r_temp
   1.657 +
   1.658 +        Imm16 targ_bot;
   1.659 +        Imm16 targ_top;
   1.660 +        Register temp;
   1.661 +
   1.662 +        // Extract both the temp register and the bottom immediate.
   1.663 +        InstMovW *bottom = inst1->as<InstMovW>();
   1.664 +        bottom->extractImm(&targ_bot);
   1.665 +        bottom->extractDest(&temp);
   1.666 +
   1.667 +        // Extract the top part of the immediate.
   1.668 +        InstMovT *top = inst2->as<InstMovT>();
   1.669 +        top->extractImm(&targ_top);
   1.670 +
   1.671 +        // Make sure they are being loaded into the same register.
   1.672 +        JS_ASSERT(top->checkDest(temp));
   1.673 +
   1.674 +        // Make sure we're branching to the same register.
   1.675 +#ifdef DEBUG
   1.676 +        // A toggled call sometimes has a NOP instead of a branch for the third instruction.
   1.677 +        // No way to assert that it's valid in that situation.
   1.678 +        if (!inst3->is<InstNOP>()) {
   1.679 +            InstBranchReg *realBranch = inst3->is<InstBranchReg>() ? inst3->as<InstBranchReg>()
   1.680 +                                                                   : inst4->as<InstBranchReg>();
   1.681 +            JS_ASSERT(realBranch->checkDest(temp));
   1.682 +        }
   1.683 +#endif
   1.684 +
   1.685 +        uint32_t *dest = (uint32_t*) (targ_bot.decode() | (targ_top.decode() << 16));
   1.686 +        return dest;
   1.687 +    }
   1.688 +
   1.689 +    if (inst1->is<InstLDR>()) {
   1.690 +        InstLDR *load = inst1->as<InstLDR>();
   1.691 +        uint32_t inst = load->encode();
   1.692 +        // get the address of the instruction as a raw pointer
   1.693 +        char *dataInst = reinterpret_cast<char*>(load);
   1.694 +        IsUp_ iu = IsUp_(inst & IsUp);
   1.695 +        int32_t offset = inst & 0xfff;
   1.696 +        if (iu != IsUp) {
   1.697 +            offset = - offset;
   1.698 +        }
   1.699 +        uint32_t **ptr = (uint32_t **)&dataInst[offset + 8];
   1.700 +        return *ptr;
   1.701 +
   1.702 +    }
   1.703 +
   1.704 +    MOZ_ASSUME_UNREACHABLE("unsupported branch relocation");
   1.705 +}
   1.706 +
   1.707 +uintptr_t
   1.708 +Assembler::getPointer(uint8_t *instPtr)
   1.709 +{
   1.710 +    InstructionIterator iter((Instruction*)instPtr);
   1.711 +    uintptr_t ret = (uintptr_t)getPtr32Target(&iter, nullptr, nullptr);
   1.712 +    return ret;
   1.713 +}
   1.714 +
   1.715 +template<class Iter>
   1.716 +const uint32_t *
   1.717 +Assembler::getPtr32Target(Iter *start, Register *dest, RelocStyle *style)
   1.718 +{
   1.719 +    Instruction *load1 = start->cur();
   1.720 +    Instruction *load2 = start->next();
   1.721 +
   1.722 +    if (load1->is<InstMovW>() && load2->is<InstMovT>()) {
   1.723 +        // see if we have the complex case,
   1.724 +        // movw r_temp, #imm1
   1.725 +        // movt r_temp, #imm2
   1.726 +
   1.727 +        Imm16 targ_bot;
   1.728 +        Imm16 targ_top;
   1.729 +        Register temp;
   1.730 +
   1.731 +        // Extract both the temp register and the bottom immediate.
   1.732 +        InstMovW *bottom = load1->as<InstMovW>();
   1.733 +        bottom->extractImm(&targ_bot);
   1.734 +        bottom->extractDest(&temp);
   1.735 +
   1.736 +        // Extract the top part of the immediate.
   1.737 +        InstMovT *top = load2->as<InstMovT>();
   1.738 +        top->extractImm(&targ_top);
   1.739 +
   1.740 +        // Make sure they are being loaded intothe same register.
   1.741 +        JS_ASSERT(top->checkDest(temp));
   1.742 +
   1.743 +        if (dest)
   1.744 +            *dest = temp;
   1.745 +        if (style)
   1.746 +            *style = L_MOVWT;
   1.747 +
   1.748 +        uint32_t *value = (uint32_t*) (targ_bot.decode() | (targ_top.decode() << 16));
   1.749 +        return value;
   1.750 +    }
   1.751 +    if (load1->is<InstLDR>()) {
   1.752 +        InstLDR *load = load1->as<InstLDR>();
   1.753 +        uint32_t inst = load->encode();
   1.754 +        // get the address of the instruction as a raw pointer
   1.755 +        char *dataInst = reinterpret_cast<char*>(load);
   1.756 +        IsUp_ iu = IsUp_(inst & IsUp);
   1.757 +        int32_t offset = inst & 0xfff;
   1.758 +        if (iu == IsDown)
   1.759 +            offset = - offset;
   1.760 +        if (dest)
   1.761 +            *dest = toRD(*load);
   1.762 +        if (style)
   1.763 +            *style = L_LDR;
   1.764 +        uint32_t **ptr = (uint32_t **)&dataInst[offset + 8];
   1.765 +        return *ptr;
   1.766 +    }
   1.767 +    MOZ_ASSUME_UNREACHABLE("unsupported relocation");
   1.768 +}
   1.769 +
   1.770 +static JitCode *
   1.771 +CodeFromJump(InstructionIterator *jump)
   1.772 +{
   1.773 +    uint8_t *target = (uint8_t *)Assembler::getCF32Target(jump);
   1.774 +    return JitCode::FromExecutable(target);
   1.775 +}
   1.776 +
   1.777 +void
   1.778 +Assembler::TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
   1.779 +{
   1.780 +    RelocationIterator iter(reader);
   1.781 +    while (iter.read()) {
   1.782 +        InstructionIterator institer((Instruction *) (code->raw() + iter.offset()));
   1.783 +        JitCode *child = CodeFromJump(&institer);
   1.784 +        MarkJitCodeUnbarriered(trc, &child, "rel32");
   1.785 +    }
   1.786 +}
   1.787 +
   1.788 +static void
   1.789 +TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
   1.790 +{
   1.791 +    while (reader.more()) {
   1.792 +        size_t offset = reader.readUnsigned();
   1.793 +        InstructionIterator iter((Instruction*)(buffer+offset));
   1.794 +        void *ptr = const_cast<uint32_t *>(js::jit::Assembler::getPtr32Target(&iter));
   1.795 +        // No barrier needed since these are constants.
   1.796 +        gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
   1.797 +    }
   1.798 +
   1.799 +}
   1.800 +static void
   1.801 +TraceDataRelocations(JSTracer *trc, ARMBuffer *buffer,
   1.802 +                     js::Vector<BufferOffset, 0, SystemAllocPolicy> *locs)
   1.803 +{
   1.804 +    for (unsigned int idx = 0; idx < locs->length(); idx++) {
   1.805 +        BufferOffset bo = (*locs)[idx];
   1.806 +        ARMBuffer::AssemblerBufferInstIterator iter(bo, buffer);
   1.807 +        void *ptr = const_cast<uint32_t *>(jit::Assembler::getPtr32Target(&iter));
   1.808 +
   1.809 +        // No barrier needed since these are constants.
   1.810 +        gc::MarkGCThingUnbarriered(trc, reinterpret_cast<void **>(&ptr), "ion-masm-ptr");
   1.811 +    }
   1.812 +
   1.813 +}
   1.814 +void
   1.815 +Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
   1.816 +{
   1.817 +    ::TraceDataRelocations(trc, code->raw(), reader);
   1.818 +}
   1.819 +
   1.820 +void
   1.821 +Assembler::copyJumpRelocationTable(uint8_t *dest)
   1.822 +{
   1.823 +    if (jumpRelocations_.length())
   1.824 +        memcpy(dest, jumpRelocations_.buffer(), jumpRelocations_.length());
   1.825 +}
   1.826 +
   1.827 +void
   1.828 +Assembler::copyDataRelocationTable(uint8_t *dest)
   1.829 +{
   1.830 +    if (dataRelocations_.length())
   1.831 +        memcpy(dest, dataRelocations_.buffer(), dataRelocations_.length());
   1.832 +}
   1.833 +
   1.834 +void
   1.835 +Assembler::copyPreBarrierTable(uint8_t *dest)
   1.836 +{
   1.837 +    if (preBarriers_.length())
   1.838 +        memcpy(dest, preBarriers_.buffer(), preBarriers_.length());
   1.839 +}
   1.840 +
   1.841 +void
   1.842 +Assembler::trace(JSTracer *trc)
   1.843 +{
   1.844 +    for (size_t i = 0; i < jumps_.length(); i++) {
   1.845 +        RelativePatch &rp = jumps_[i];
   1.846 +        if (rp.kind == Relocation::JITCODE) {
   1.847 +            JitCode *code = JitCode::FromExecutable((uint8_t*)rp.target);
   1.848 +            MarkJitCodeUnbarriered(trc, &code, "masmrel32");
   1.849 +            JS_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target));
   1.850 +        }
   1.851 +    }
   1.852 +
   1.853 +    if (tmpDataRelocations_.length())
   1.854 +        ::TraceDataRelocations(trc, &m_buffer, &tmpDataRelocations_);
   1.855 +}
   1.856 +
   1.857 +void
   1.858 +Assembler::processCodeLabels(uint8_t *rawCode)
   1.859 +{
   1.860 +    for (size_t i = 0; i < codeLabels_.length(); i++) {
   1.861 +        CodeLabel label = codeLabels_[i];
   1.862 +        Bind(rawCode, label.dest(), rawCode + actualOffset(label.src()->offset()));
   1.863 +    }
   1.864 +}
   1.865 +
   1.866 +void
   1.867 +Assembler::writeCodePointer(AbsoluteLabel *absoluteLabel) {
   1.868 +    JS_ASSERT(!absoluteLabel->bound());
   1.869 +    BufferOffset off = writeInst(LabelBase::INVALID_OFFSET);
   1.870 +
   1.871 +    // x86/x64 makes general use of AbsoluteLabel and weaves a linked list of
   1.872 +    // uses of an AbsoluteLabel through the assembly. ARM only uses labels
   1.873 +    // for the case statements of switch jump tables. Thus, for simplicity, we
   1.874 +    // simply treat the AbsoluteLabel as a label and bind it to the offset of
   1.875 +    // the jump table entry that needs to be patched.
   1.876 +    LabelBase *label = absoluteLabel;
   1.877 +    label->bind(off.getOffset());
   1.878 +}
   1.879 +
   1.880 +void
   1.881 +Assembler::Bind(uint8_t *rawCode, AbsoluteLabel *label, const void *address)
   1.882 +{
   1.883 +    // See writeCodePointer comment.
   1.884 +    uint32_t off = actualOffset(label->offset());
   1.885 +    *reinterpret_cast<const void **>(rawCode + off) = address;
   1.886 +}
   1.887 +
   1.888 +Assembler::Condition
   1.889 +Assembler::InvertCondition(Condition cond)
   1.890 +{
   1.891 +    const uint32_t ConditionInversionBit = 0x10000000;
   1.892 +    return Condition(ConditionInversionBit ^ cond);
   1.893 +}
   1.894 +
   1.895 +Imm8::TwoImm8mData
   1.896 +Imm8::encodeTwoImms(uint32_t imm)
   1.897 +{
   1.898 +    // In the ideal case, we are looking for a number that (in binary) looks like:
   1.899 +    // 0b((00)*)n_1((00)*)n_2((00)*)
   1.900 +    //    left  n1   mid  n2
   1.901 +    // where both n_1 and n_2 fit into 8 bits.
   1.902 +    // since this is being done with rotates, we also need to handle the case
   1.903 +    // that one of these numbers is in fact split between the left and right
   1.904 +    // sides, in which case the constant will look like:
   1.905 +    // 0bn_1a((00)*)n_2((00)*)n_1b
   1.906 +    //   n1a  mid  n2   rgh    n1b
   1.907 +    // also remember, values are rotated by multiples of two, and left,
   1.908 +    // mid or right can have length zero
   1.909 +    uint32_t imm1, imm2;
   1.910 +    int left = CountLeadingZeroes32(imm) & 0x1E;
   1.911 +    uint32_t no_n1 = imm & ~(0xff << (24 - left));
   1.912 +
   1.913 +    // not technically needed: this case only happens if we can encode
   1.914 +    // as a single imm8m.  There is a perfectly reasonable encoding in this
   1.915 +    // case, but we shouldn't encourage people to do things like this.
   1.916 +    if (no_n1 == 0)
   1.917 +        return TwoImm8mData();
   1.918 +
   1.919 +    int mid = CountLeadingZeroes32(no_n1) & 0x1E;
   1.920 +    uint32_t no_n2 = no_n1 & ~((0xff << ((24 - mid) & 0x1f)) | 0xff >> ((8 + mid) & 0x1f));
   1.921 +
   1.922 +    if (no_n2 == 0) {
   1.923 +        // we hit the easy case, no wraparound.
   1.924 +        // note: a single constant *may* look like this.
   1.925 +        int imm1shift = left + 8;
   1.926 +        int imm2shift = mid + 8;
   1.927 +        imm1 = (imm >> (32 - imm1shift)) & 0xff;
   1.928 +        if (imm2shift >= 32) {
   1.929 +            imm2shift = 0;
   1.930 +            // this assert does not always hold
   1.931 +            //assert((imm & 0xff) == no_n1);
   1.932 +            // in fact, this would lead to some incredibly subtle bugs.
   1.933 +            imm2 = no_n1;
   1.934 +        } else {
   1.935 +            imm2 = ((imm >> (32 - imm2shift)) | (imm << imm2shift)) & 0xff;
   1.936 +            JS_ASSERT( ((no_n1 >> (32 - imm2shift)) | (no_n1 << imm2shift)) ==
   1.937 +                       imm2);
   1.938 +        }
   1.939 +        JS_ASSERT((imm1shift & 0x1) == 0);
   1.940 +        JS_ASSERT((imm2shift & 0x1) == 0);
   1.941 +        return TwoImm8mData(datastore::Imm8mData(imm1, imm1shift >> 1),
   1.942 +                            datastore::Imm8mData(imm2, imm2shift >> 1));
   1.943 +    }
   1.944 +
   1.945 +    // either it wraps, or it does not fit.
   1.946 +    // if we initially chopped off more than 8 bits, then it won't fit.
   1.947 +    if (left >= 8)
   1.948 +        return TwoImm8mData();
   1.949 +
   1.950 +    int right = 32 - (CountLeadingZeroes32(no_n2) & 30);
   1.951 +    // all remaining set bits *must* fit into the lower 8 bits
   1.952 +    // the right == 8 case should be handled by the previous case.
   1.953 +    if (right > 8)
   1.954 +        return TwoImm8mData();
   1.955 +
   1.956 +    // make sure the initial bits that we removed for no_n1
   1.957 +    // fit into the 8-(32-right) leftmost bits
   1.958 +    if (((imm & (0xff << (24 - left))) << (8-right)) != 0) {
   1.959 +        // BUT we may have removed more bits than we needed to for no_n1
   1.960 +        // 0x04104001 e.g. we can encode 0x104 with a single op, then
   1.961 +        // 0x04000001 with a second, but we try to encode 0x0410000
   1.962 +        // and find that we need a second op for 0x4000, and 0x1 cannot
   1.963 +        // be included in the encoding of 0x04100000
   1.964 +        no_n1 = imm & ~((0xff >> (8-right)) | (0xff << (24 + right)));
   1.965 +        mid = CountLeadingZeroes32(no_n1) & 30;
   1.966 +        no_n2 =
   1.967 +            no_n1  & ~((0xff << ((24 - mid)&31)) | 0xff >> ((8 + mid)&31));
   1.968 +        if (no_n2 != 0)
   1.969 +            return TwoImm8mData();
   1.970 +    }
   1.971 +
   1.972 +    // now assemble all of this information into a two coherent constants
   1.973 +    // it is a rotate right from the lower 8 bits.
   1.974 +    int imm1shift = 8 - right;
   1.975 +    imm1 = 0xff & ((imm << imm1shift) | (imm >> (32 - imm1shift)));
   1.976 +    JS_ASSERT ((imm1shift&~0x1e) == 0);
   1.977 +    // left + 8 + mid is the position of the leftmost bit of n_2.
   1.978 +    // we needed to rotate 0x000000ab right by 8 in order to get
   1.979 +    // 0xab000000, then shift again by the leftmost bit in order to
   1.980 +    // get the constant that we care about.
   1.981 +    int imm2shift =  mid + 8;
   1.982 +    imm2 = ((imm >> (32 - imm2shift)) | (imm << imm2shift)) & 0xff;
   1.983 +    JS_ASSERT((imm1shift & 0x1) == 0);
   1.984 +    JS_ASSERT((imm2shift & 0x1) == 0);
   1.985 +    return TwoImm8mData(datastore::Imm8mData(imm1, imm1shift >> 1),
   1.986 +                        datastore::Imm8mData(imm2, imm2shift >> 1));
   1.987 +}
   1.988 +
   1.989 +ALUOp
   1.990 +jit::ALUNeg(ALUOp op, Register dest, Imm32 *imm, Register *negDest)
   1.991 +{
   1.992 +    // find an alternate ALUOp to get the job done, and use a different imm.
   1.993 +    *negDest = dest;
   1.994 +    switch (op) {
   1.995 +      case op_mov:
   1.996 +        *imm = Imm32(~imm->value);
   1.997 +        return op_mvn;
   1.998 +      case op_mvn:
   1.999 +        *imm = Imm32(~imm->value);
  1.1000 +        return op_mov;
  1.1001 +      case op_and:
  1.1002 +        *imm = Imm32(~imm->value);
  1.1003 +        return op_bic;
  1.1004 +      case op_bic:
  1.1005 +        *imm = Imm32(~imm->value);
  1.1006 +        return op_and;
  1.1007 +      case op_add:
  1.1008 +        *imm = Imm32(-imm->value);
  1.1009 +        return op_sub;
  1.1010 +      case op_sub:
  1.1011 +        *imm = Imm32(-imm->value);
  1.1012 +        return op_add;
  1.1013 +      case op_cmp:
  1.1014 +        *imm = Imm32(-imm->value);
  1.1015 +        return op_cmn;
  1.1016 +      case op_cmn:
  1.1017 +        *imm = Imm32(-imm->value);
  1.1018 +        return op_cmp;
  1.1019 +      case op_tst:
  1.1020 +        JS_ASSERT(dest == InvalidReg);
  1.1021 +        *imm = Imm32(~imm->value);
  1.1022 +        *negDest = ScratchRegister;
  1.1023 +        return op_bic;
  1.1024 +        // orr has orn on thumb2 only.
  1.1025 +      default:
  1.1026 +        return op_invalid;
  1.1027 +    }
  1.1028 +}
  1.1029 +
  1.1030 +bool
  1.1031 +jit::can_dbl(ALUOp op)
  1.1032 +{
  1.1033 +    // some instructions can't be processed as two separate instructions
  1.1034 +    // such as and, and possibly add (when we're setting ccodes).
  1.1035 +    // there is also some hilarity with *reading* condition codes.
  1.1036 +    // for example, adc dest, src1, 0xfff; (add with carry) can be split up
  1.1037 +    // into adc dest, src1, 0xf00; add dest, dest, 0xff, since "reading" the
  1.1038 +    // condition code increments the result by one conditionally, that only needs
  1.1039 +    // to be done on one of the two instructions.
  1.1040 +    switch (op) {
  1.1041 +      case op_bic:
  1.1042 +      case op_add:
  1.1043 +      case op_sub:
  1.1044 +      case op_eor:
  1.1045 +      case op_orr:
  1.1046 +        return true;
  1.1047 +      default:
  1.1048 +        return false;
  1.1049 +    }
  1.1050 +}
  1.1051 +
  1.1052 +bool
  1.1053 +jit::condsAreSafe(ALUOp op) {
  1.1054 +    // Even when we are setting condition codes, sometimes we can
  1.1055 +    // get away with splitting an operation into two.
  1.1056 +    // for example, if our immediate is 0x00ff00ff, and the operation is eors
  1.1057 +    // we can split this in half, since x ^ 0x00ff0000 ^ 0x000000ff should
  1.1058 +    // set all of its condition codes exactly the same as x ^ 0x00ff00ff.
  1.1059 +    // However, if the operation were adds,
  1.1060 +    // we cannot split this in half.  If the source on the add is
  1.1061 +    // 0xfff00ff0, the result sholud be 0xef10ef, but do we set the overflow bit
  1.1062 +    // or not?  Depending on which half is performed first (0x00ff0000
  1.1063 +    // or 0x000000ff) the V bit will be set differently, and *not* updating
  1.1064 +    // the V bit would be wrong.  Theoretically, the following should work
  1.1065 +    // adds r0, r1, 0x00ff0000;
  1.1066 +    // addsvs r0, r1, 0x000000ff;
  1.1067 +    // addvc r0, r1, 0x000000ff;
  1.1068 +    // but this is 3 instructions, and at that point, we might as well use
  1.1069 +    // something else.
  1.1070 +    switch(op) {
  1.1071 +      case op_bic:
  1.1072 +      case op_orr:
  1.1073 +      case op_eor:
  1.1074 +        return true;
  1.1075 +      default:
  1.1076 +        return false;
  1.1077 +    }
  1.1078 +}
  1.1079 +
  1.1080 +ALUOp
  1.1081 +jit::getDestVariant(ALUOp op)
  1.1082 +{
  1.1083 +    // all of the compare operations are dest-less variants of a standard
  1.1084 +    // operation.  Given the dest-less variant, return the dest-ful variant.
  1.1085 +    switch (op) {
  1.1086 +      case op_cmp:
  1.1087 +        return op_sub;
  1.1088 +      case op_cmn:
  1.1089 +        return op_add;
  1.1090 +      case op_tst:
  1.1091 +        return op_and;
  1.1092 +      case op_teq:
  1.1093 +        return op_eor;
  1.1094 +      default:
  1.1095 +        return op;
  1.1096 +    }
  1.1097 +}
  1.1098 +
  1.1099 +O2RegImmShift
  1.1100 +jit::O2Reg(Register r) {
  1.1101 +    return O2RegImmShift(r, LSL, 0);
  1.1102 +}
  1.1103 +
  1.1104 +O2RegImmShift
  1.1105 +jit::lsl(Register r, int amt)
  1.1106 +{
  1.1107 +    JS_ASSERT(0 <= amt && amt <= 31);
  1.1108 +    return O2RegImmShift(r, LSL, amt);
  1.1109 +}
  1.1110 +
  1.1111 +O2RegImmShift
  1.1112 +jit::lsr(Register r, int amt)
  1.1113 +{
  1.1114 +    JS_ASSERT(1 <= amt && amt <= 32);
  1.1115 +    return O2RegImmShift(r, LSR, amt);
  1.1116 +}
  1.1117 +
  1.1118 +O2RegImmShift
  1.1119 +jit::ror(Register r, int amt)
  1.1120 +{
  1.1121 +    JS_ASSERT(1 <= amt && amt <= 31);
  1.1122 +    return O2RegImmShift(r, ROR, amt);
  1.1123 +}
  1.1124 +O2RegImmShift
  1.1125 +jit::rol(Register r, int amt)
  1.1126 +{
  1.1127 +    JS_ASSERT(1 <= amt && amt <= 31);
  1.1128 +    return O2RegImmShift(r, ROR, 32 - amt);
  1.1129 +}
  1.1130 +
  1.1131 +O2RegImmShift
  1.1132 +jit::asr (Register r, int amt)
  1.1133 +{
  1.1134 +    JS_ASSERT(1 <= amt && amt <= 32);
  1.1135 +    return O2RegImmShift(r, ASR, amt);
  1.1136 +}
  1.1137 +
  1.1138 +
  1.1139 +O2RegRegShift
  1.1140 +jit::lsl(Register r, Register amt)
  1.1141 +{
  1.1142 +    return O2RegRegShift(r, LSL, amt);
  1.1143 +}
  1.1144 +
  1.1145 +O2RegRegShift
  1.1146 +jit::lsr(Register r, Register amt)
  1.1147 +{
  1.1148 +    return O2RegRegShift(r, LSR, amt);
  1.1149 +}
  1.1150 +
  1.1151 +O2RegRegShift
  1.1152 +jit::ror(Register r, Register amt)
  1.1153 +{
  1.1154 +    return O2RegRegShift(r, ROR, amt);
  1.1155 +}
  1.1156 +
  1.1157 +O2RegRegShift
  1.1158 +jit::asr (Register r, Register amt)
  1.1159 +{
  1.1160 +    return O2RegRegShift(r, ASR, amt);
  1.1161 +}
  1.1162 +
  1.1163 +static js::jit::DoubleEncoder doubleEncoder;
  1.1164 +
  1.1165 +/* static */ const js::jit::VFPImm js::jit::VFPImm::one(0x3FF00000);
  1.1166 +
  1.1167 +js::jit::VFPImm::VFPImm(uint32_t top)
  1.1168 +{
  1.1169 +    data = -1;
  1.1170 +    datastore::Imm8VFPImmData tmp;
  1.1171 +    if (doubleEncoder.lookup(top, &tmp))
  1.1172 +        data = tmp.encode();
  1.1173 +}
  1.1174 +
  1.1175 +BOffImm::BOffImm(Instruction &inst)
  1.1176 +  : data(inst.encode() & 0x00ffffff)
  1.1177 +{
  1.1178 +}
  1.1179 +
  1.1180 +Instruction *
  1.1181 +BOffImm::getDest(Instruction *src)
  1.1182 +{
  1.1183 +    // TODO: It is probably worthwhile to verify that src is actually a branch
  1.1184 +    // NOTE: This does not explicitly shift the offset of the destination left by 2,
  1.1185 +    // since it is indexing into an array of instruction sized objects.
  1.1186 +    return &src[(((int32_t)data<<8)>>8) + 2];
  1.1187 +}
  1.1188 +
  1.1189 +//VFPRegister implementation
  1.1190 +VFPRegister
  1.1191 +VFPRegister::doubleOverlay() const
  1.1192 +{
  1.1193 +    JS_ASSERT(!_isInvalid);
  1.1194 +    if (kind != Double) {
  1.1195 +        JS_ASSERT(_code % 2 == 0);
  1.1196 +        return VFPRegister(_code >> 1, Double);
  1.1197 +    }
  1.1198 +    return *this;
  1.1199 +}
  1.1200 +VFPRegister
  1.1201 +VFPRegister::singleOverlay() const
  1.1202 +{
  1.1203 +    JS_ASSERT(!_isInvalid);
  1.1204 +    if (kind == Double) {
  1.1205 +        // There are no corresponding float registers for d16-d31
  1.1206 +        JS_ASSERT(_code < 16);
  1.1207 +        return VFPRegister(_code << 1, Single);
  1.1208 +    }
  1.1209 +
  1.1210 +    JS_ASSERT(_code % 2 == 0);
  1.1211 +    return VFPRegister(_code, Single);
  1.1212 +}
  1.1213 +
  1.1214 +VFPRegister
  1.1215 +VFPRegister::sintOverlay() const
  1.1216 +{
  1.1217 +    JS_ASSERT(!_isInvalid);
  1.1218 +    if (kind == Double) {
  1.1219 +        // There are no corresponding float registers for d16-d31
  1.1220 +        ASSERT(_code < 16);
  1.1221 +        return VFPRegister(_code << 1, Int);
  1.1222 +    }
  1.1223 +
  1.1224 +    JS_ASSERT(_code % 2 == 0);
  1.1225 +    return VFPRegister(_code, Int);
  1.1226 +}
  1.1227 +VFPRegister
  1.1228 +VFPRegister::uintOverlay() const
  1.1229 +{
  1.1230 +    JS_ASSERT(!_isInvalid);
  1.1231 +    if (kind == Double) {
  1.1232 +        // There are no corresponding float registers for d16-d31
  1.1233 +        ASSERT(_code < 16);
  1.1234 +        return VFPRegister(_code << 1, UInt);
  1.1235 +    }
  1.1236 +
  1.1237 +    JS_ASSERT(_code % 2 == 0);
  1.1238 +    return VFPRegister(_code, UInt);
  1.1239 +}
  1.1240 +
  1.1241 +bool
  1.1242 +VFPRegister::isInvalid()
  1.1243 +{
  1.1244 +    return _isInvalid;
  1.1245 +}
  1.1246 +
  1.1247 +bool
  1.1248 +VFPRegister::isMissing()
  1.1249 +{
  1.1250 +    JS_ASSERT(!_isInvalid);
  1.1251 +    return _isMissing;
  1.1252 +}
  1.1253 +
  1.1254 +
  1.1255 +bool
  1.1256 +Assembler::oom() const
  1.1257 +{
  1.1258 +    return m_buffer.oom() ||
  1.1259 +        !enoughMemory_ ||
  1.1260 +        jumpRelocations_.oom() ||
  1.1261 +        dataRelocations_.oom() ||
  1.1262 +        preBarriers_.oom();
  1.1263 +}
  1.1264 +
  1.1265 +bool
  1.1266 +Assembler::addCodeLabel(CodeLabel label)
  1.1267 +{
  1.1268 +    return codeLabels_.append(label);
  1.1269 +}
  1.1270 +
  1.1271 +// Size of the instruction stream, in bytes.  Including pools. This function expects
  1.1272 +// all pools that need to be placed have been placed.  If they haven't then we
  1.1273 +// need to go an flush the pools :(
  1.1274 +size_t
  1.1275 +Assembler::size() const
  1.1276 +{
  1.1277 +    return m_buffer.size();
  1.1278 +}
  1.1279 +// Size of the relocation table, in bytes.
  1.1280 +size_t
  1.1281 +Assembler::jumpRelocationTableBytes() const
  1.1282 +{
  1.1283 +    return jumpRelocations_.length();
  1.1284 +}
  1.1285 +size_t
  1.1286 +Assembler::dataRelocationTableBytes() const
  1.1287 +{
  1.1288 +    return dataRelocations_.length();
  1.1289 +}
  1.1290 +
  1.1291 +size_t
  1.1292 +Assembler::preBarrierTableBytes() const
  1.1293 +{
  1.1294 +    return preBarriers_.length();
  1.1295 +}
  1.1296 +
  1.1297 +// Size of the data table, in bytes.
  1.1298 +size_t
  1.1299 +Assembler::bytesNeeded() const
  1.1300 +{
  1.1301 +    return size() +
  1.1302 +        jumpRelocationTableBytes() +
  1.1303 +        dataRelocationTableBytes() +
  1.1304 +        preBarrierTableBytes();
  1.1305 +}
  1.1306 +
  1.1307 +// write a blob of binary into the instruction stream
  1.1308 +BufferOffset
  1.1309 +Assembler::writeInst(uint32_t x, uint32_t *dest)
  1.1310 +{
  1.1311 +    if (dest == nullptr)
  1.1312 +        return m_buffer.putInt(x);
  1.1313 +
  1.1314 +    writeInstStatic(x, dest);
  1.1315 +    return BufferOffset();
  1.1316 +}
  1.1317 +void
  1.1318 +Assembler::writeInstStatic(uint32_t x, uint32_t *dest)
  1.1319 +{
  1.1320 +    JS_ASSERT(dest != nullptr);
  1.1321 +    *dest = x;
  1.1322 +}
  1.1323 +
  1.1324 +BufferOffset
  1.1325 +Assembler::align(int alignment)
  1.1326 +{
  1.1327 +    BufferOffset ret;
  1.1328 +    if (alignment == 8) {
  1.1329 +        while (!m_buffer.isAligned(alignment)) {
  1.1330 +            BufferOffset tmp = as_nop();
  1.1331 +            if (!ret.assigned())
  1.1332 +                ret = tmp;
  1.1333 +        }
  1.1334 +    } else {
  1.1335 +        flush();
  1.1336 +        JS_ASSERT((alignment & (alignment - 1)) == 0);
  1.1337 +        while (size() & (alignment-1)) {
  1.1338 +            BufferOffset tmp = as_nop();
  1.1339 +            if (!ret.assigned())
  1.1340 +                ret = tmp;
  1.1341 +        }
  1.1342 +    }
  1.1343 +    return ret;
  1.1344 +
  1.1345 +}
  1.1346 +BufferOffset
  1.1347 +Assembler::as_nop()
  1.1348 +{
  1.1349 +    return writeInst(0xe320f000);
  1.1350 +}
  1.1351 +BufferOffset
  1.1352 +Assembler::as_alu(Register dest, Register src1, Operand2 op2,
  1.1353 +                  ALUOp op, SetCond_ sc, Condition c, Instruction *instdest)
  1.1354 +{
  1.1355 +    return writeInst((int)op | (int)sc | (int) c | op2.encode() |
  1.1356 +                     ((dest == InvalidReg) ? 0 : RD(dest)) |
  1.1357 +                     ((src1 == InvalidReg) ? 0 : RN(src1)), (uint32_t*)instdest);
  1.1358 +}
  1.1359 +
  1.1360 +BufferOffset
  1.1361 +Assembler::as_mov(Register dest, Operand2 op2, SetCond_ sc, Condition c, Instruction *instdest)
  1.1362 +{
  1.1363 +    return as_alu(dest, InvalidReg, op2, op_mov, sc, c, instdest);
  1.1364 +}
  1.1365 +
  1.1366 +BufferOffset
  1.1367 +Assembler::as_mvn(Register dest, Operand2 op2, SetCond_ sc, Condition c)
  1.1368 +{
  1.1369 +    return as_alu(dest, InvalidReg, op2, op_mvn, sc, c);
  1.1370 +}
  1.1371 +
  1.1372 +// Logical operations.
  1.1373 +BufferOffset
  1.1374 +Assembler::as_and(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1375 +{
  1.1376 +    return as_alu(dest, src1, op2, op_and, sc, c);
  1.1377 +}
  1.1378 +BufferOffset
  1.1379 +Assembler::as_bic(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1380 +{
  1.1381 +    return as_alu(dest, src1, op2, op_bic, sc, c);
  1.1382 +}
  1.1383 +BufferOffset
  1.1384 +Assembler::as_eor(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1385 +{
  1.1386 +    return as_alu(dest, src1, op2, op_eor, sc, c);
  1.1387 +}
  1.1388 +BufferOffset
  1.1389 +Assembler::as_orr(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1390 +{
  1.1391 +    return as_alu(dest, src1, op2, op_orr, sc, c);
  1.1392 +}
  1.1393 +
  1.1394 +// Mathematical operations.
  1.1395 +BufferOffset
  1.1396 +Assembler::as_adc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1397 +{
  1.1398 +    return as_alu(dest, src1, op2, op_adc, sc, c);
  1.1399 +}
  1.1400 +BufferOffset
  1.1401 +Assembler::as_add(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1402 +{
  1.1403 +    return as_alu(dest, src1, op2, op_add, sc, c);
  1.1404 +}
  1.1405 +BufferOffset
  1.1406 +Assembler::as_sbc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1407 +{
  1.1408 +    return as_alu(dest, src1, op2, op_sbc, sc, c);
  1.1409 +}
  1.1410 +BufferOffset
  1.1411 +Assembler::as_sub(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1412 +{
  1.1413 +    return as_alu(dest, src1, op2, op_sub, sc, c);
  1.1414 +}
  1.1415 +BufferOffset
  1.1416 +Assembler::as_rsb(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1417 +{
  1.1418 +    return as_alu(dest, src1, op2, op_rsb, sc, c);
  1.1419 +}
  1.1420 +BufferOffset
  1.1421 +Assembler::as_rsc(Register dest, Register src1, Operand2 op2, SetCond_ sc, Condition c)
  1.1422 +{
  1.1423 +    return as_alu(dest, src1, op2, op_rsc, sc, c);
  1.1424 +}
  1.1425 +
  1.1426 +// Test operations.
  1.1427 +BufferOffset
  1.1428 +Assembler::as_cmn(Register src1, Operand2 op2, Condition c)
  1.1429 +{
  1.1430 +    return as_alu(InvalidReg, src1, op2, op_cmn, SetCond, c);
  1.1431 +}
  1.1432 +BufferOffset
  1.1433 +Assembler::as_cmp(Register src1, Operand2 op2, Condition c)
  1.1434 +{
  1.1435 +    return as_alu(InvalidReg, src1, op2, op_cmp, SetCond, c);
  1.1436 +}
  1.1437 +BufferOffset
  1.1438 +Assembler::as_teq(Register src1, Operand2 op2, Condition c)
  1.1439 +{
  1.1440 +    return as_alu(InvalidReg, src1, op2, op_teq, SetCond, c);
  1.1441 +}
  1.1442 +BufferOffset
  1.1443 +Assembler::as_tst(Register src1, Operand2 op2, Condition c)
  1.1444 +{
  1.1445 +    return as_alu(InvalidReg, src1, op2, op_tst, SetCond, c);
  1.1446 +}
  1.1447 +
  1.1448 +// Not quite ALU worthy, but useful none the less:
  1.1449 +// These also have the isue of these being formatted
  1.1450 +// completly differently from the standard ALU operations.
  1.1451 +BufferOffset
  1.1452 +Assembler::as_movw(Register dest, Imm16 imm, Condition c, Instruction *pos)
  1.1453 +{
  1.1454 +    JS_ASSERT(hasMOVWT());
  1.1455 +    return writeInst(0x03000000 | c | imm.encode() | RD(dest), (uint32_t*)pos);
  1.1456 +}
  1.1457 +BufferOffset
  1.1458 +Assembler::as_movt(Register dest, Imm16 imm, Condition c, Instruction *pos)
  1.1459 +{
  1.1460 +    JS_ASSERT(hasMOVWT());
  1.1461 +    return writeInst(0x03400000 | c | imm.encode() | RD(dest), (uint32_t*)pos);
  1.1462 +}
  1.1463 +
  1.1464 +static const int mull_tag = 0x90;
  1.1465 +
  1.1466 +BufferOffset
  1.1467 +Assembler::as_genmul(Register dhi, Register dlo, Register rm, Register rn,
  1.1468 +                     MULOp op, SetCond_ sc, Condition c)
  1.1469 +{
  1.1470 +
  1.1471 +    return writeInst(RN(dhi) | maybeRD(dlo) | RM(rm) | rn.code() | op | sc | c | mull_tag);
  1.1472 +}
  1.1473 +BufferOffset
  1.1474 +Assembler::as_mul(Register dest, Register src1, Register src2, SetCond_ sc, Condition c)
  1.1475 +{
  1.1476 +    return as_genmul(dest, InvalidReg, src1, src2, opm_mul, sc, c);
  1.1477 +}
  1.1478 +BufferOffset
  1.1479 +Assembler::as_mla(Register dest, Register acc, Register src1, Register src2,
  1.1480 +                  SetCond_ sc, Condition c)
  1.1481 +{
  1.1482 +    return as_genmul(dest, acc, src1, src2, opm_mla, sc, c);
  1.1483 +}
  1.1484 +BufferOffset
  1.1485 +Assembler::as_umaal(Register destHI, Register destLO, Register src1, Register src2, Condition c)
  1.1486 +{
  1.1487 +    return as_genmul(destHI, destLO, src1, src2, opm_umaal, NoSetCond, c);
  1.1488 +}
  1.1489 +BufferOffset
  1.1490 +Assembler::as_mls(Register dest, Register acc, Register src1, Register src2, Condition c)
  1.1491 +{
  1.1492 +    return as_genmul(dest, acc, src1, src2, opm_mls, NoSetCond, c);
  1.1493 +}
  1.1494 +
  1.1495 +BufferOffset
  1.1496 +Assembler::as_umull(Register destHI, Register destLO, Register src1, Register src2,
  1.1497 +                    SetCond_ sc, Condition c)
  1.1498 +{
  1.1499 +    return as_genmul(destHI, destLO, src1, src2, opm_umull, sc, c);
  1.1500 +}
  1.1501 +
  1.1502 +BufferOffset
  1.1503 +Assembler::as_umlal(Register destHI, Register destLO, Register src1, Register src2,
  1.1504 +                    SetCond_ sc, Condition c)
  1.1505 +{
  1.1506 +    return as_genmul(destHI, destLO, src1, src2, opm_umlal, sc, c);
  1.1507 +}
  1.1508 +
  1.1509 +BufferOffset
  1.1510 +Assembler::as_smull(Register destHI, Register destLO, Register src1, Register src2,
  1.1511 +                    SetCond_ sc, Condition c)
  1.1512 +{
  1.1513 +    return as_genmul(destHI, destLO, src1, src2, opm_smull, sc, c);
  1.1514 +}
  1.1515 +
  1.1516 +BufferOffset
  1.1517 +Assembler::as_smlal(Register destHI, Register destLO, Register src1, Register src2,
  1.1518 +                    SetCond_ sc, Condition c)
  1.1519 +{
  1.1520 +    return as_genmul(destHI, destLO, src1, src2, opm_smlal, sc, c);
  1.1521 +}
  1.1522 +
  1.1523 +BufferOffset
  1.1524 +Assembler::as_sdiv(Register rd, Register rn, Register rm, Condition c)
  1.1525 +{
  1.1526 +    return writeInst(0x0710f010 | c | RN(rd) | RM(rm) | rn.code());
  1.1527 +}
  1.1528 +
  1.1529 +BufferOffset
  1.1530 +Assembler::as_udiv(Register rd, Register rn, Register rm, Condition c)
  1.1531 +{
  1.1532 +    return writeInst(0x0730f010 | c | RN(rd) | RM(rm) | rn.code());
  1.1533 +}
  1.1534 +
  1.1535 +// Data transfer instructions: ldr, str, ldrb, strb.
  1.1536 +// Using an int to differentiate between 8 bits and 32 bits is
  1.1537 +// overkill, but meh
  1.1538 +BufferOffset
  1.1539 +Assembler::as_dtr(LoadStore ls, int size, Index mode,
  1.1540 +                  Register rt, DTRAddr addr, Condition c, uint32_t *dest)
  1.1541 +{
  1.1542 +    JS_ASSERT (mode == Offset ||  (rt != addr.getBase() && pc != addr.getBase()));
  1.1543 +    JS_ASSERT(size == 32 || size == 8);
  1.1544 +    return writeInst( 0x04000000 | ls | (size == 8 ? 0x00400000 : 0) | mode | c |
  1.1545 +                      RT(rt) | addr.encode(), dest);
  1.1546 +
  1.1547 +}
  1.1548 +class PoolHintData {
  1.1549 +  public:
  1.1550 +    enum LoadType {
  1.1551 +        // set 0 to bogus, since that is the value most likely to be
  1.1552 +        // accidentally left somewhere.
  1.1553 +        poolBOGUS  = 0,
  1.1554 +        poolDTR    = 1,
  1.1555 +        poolBranch = 2,
  1.1556 +        poolVDTR   = 3
  1.1557 +    };
  1.1558 +
  1.1559 +  private:
  1.1560 +    uint32_t   index    : 16;
  1.1561 +    uint32_t   cond     : 4;
  1.1562 +    LoadType   loadType : 2;
  1.1563 +    uint32_t   destReg  : 5;
  1.1564 +    uint32_t   destType : 1;
  1.1565 +    uint32_t   ONES     : 4;
  1.1566 +
  1.1567 +    static const uint32_t expectedOnes = 0xfu;
  1.1568 +
  1.1569 +  public:
  1.1570 +    void init(uint32_t index_, Assembler::Condition cond_, LoadType lt, const Register &destReg_) {
  1.1571 +        index = index_;
  1.1572 +        JS_ASSERT(index == index_);
  1.1573 +        cond = cond_ >> 28;
  1.1574 +        JS_ASSERT(cond == cond_ >> 28);
  1.1575 +        loadType = lt;
  1.1576 +        ONES = expectedOnes;
  1.1577 +        destReg = destReg_.code();
  1.1578 +        destType = 0;
  1.1579 +    }
  1.1580 +    void init(uint32_t index_, Assembler::Condition cond_, LoadType lt, const VFPRegister &destReg_) {
  1.1581 +        JS_ASSERT(destReg_.isFloat());
  1.1582 +        index = index_;
  1.1583 +        JS_ASSERT(index == index_);
  1.1584 +        cond = cond_ >> 28;
  1.1585 +        JS_ASSERT(cond == cond_ >> 28);
  1.1586 +        loadType = lt;
  1.1587 +        ONES = expectedOnes;
  1.1588 +        destReg = destReg_.isDouble() ? destReg_.code() : destReg_.doubleOverlay().code();
  1.1589 +        destType = destReg_.isDouble();
  1.1590 +    }
  1.1591 +    Assembler::Condition getCond() {
  1.1592 +        return Assembler::Condition(cond << 28);
  1.1593 +    }
  1.1594 +
  1.1595 +    Register getReg() {
  1.1596 +        return Register::FromCode(destReg);
  1.1597 +    }
  1.1598 +    VFPRegister getVFPReg() {
  1.1599 +        VFPRegister r = VFPRegister(FloatRegister::FromCode(destReg));
  1.1600 +        return destType ? r : r.singleOverlay();
  1.1601 +    }
  1.1602 +
  1.1603 +    int32_t getIndex() {
  1.1604 +        return index;
  1.1605 +    }
  1.1606 +    void setIndex(uint32_t index_) {
  1.1607 +        JS_ASSERT(ONES == expectedOnes && loadType != poolBOGUS);
  1.1608 +        index = index_;
  1.1609 +        JS_ASSERT(index == index_);
  1.1610 +    }
  1.1611 +
  1.1612 +    LoadType getLoadType() {
  1.1613 +        // If this *was* a poolBranch, but the branch has already been bound
  1.1614 +        // then this isn't going to look like a real poolhintdata, but we still
  1.1615 +        // want to lie about it so everyone knows it *used* to be a branch.
  1.1616 +        if (ONES != expectedOnes)
  1.1617 +            return PoolHintData::poolBranch;
  1.1618 +        return loadType;
  1.1619 +    }
  1.1620 +
  1.1621 +    bool isValidPoolHint() {
  1.1622 +        // Most instructions cannot have a condition that is 0xf. Notable exceptions are
  1.1623 +        // blx and the entire NEON instruction set. For the purposes of pool loads, and
  1.1624 +        // possibly patched branches, the possible instructions are ldr and b, neither of
  1.1625 +        // which can have a condition code of 0xf.
  1.1626 +        return ONES == expectedOnes;
  1.1627 +    }
  1.1628 +};
  1.1629 +
  1.1630 +union PoolHintPun {
  1.1631 +    PoolHintData phd;
  1.1632 +    uint32_t raw;
  1.1633 +};
  1.1634 +
  1.1635 +// Handles all of the other integral data transferring functions:
  1.1636 +// ldrsb, ldrsh, ldrd, etc.
  1.1637 +// size is given in bits.
  1.1638 +BufferOffset
  1.1639 +Assembler::as_extdtr(LoadStore ls, int size, bool IsSigned, Index mode,
  1.1640 +                     Register rt, EDtrAddr addr, Condition c, uint32_t *dest)
  1.1641 +{
  1.1642 +    int extra_bits2 = 0;
  1.1643 +    int extra_bits1 = 0;
  1.1644 +    switch(size) {
  1.1645 +      case 8:
  1.1646 +        JS_ASSERT(IsSigned);
  1.1647 +        JS_ASSERT(ls!=IsStore);
  1.1648 +        extra_bits1 = 0x1;
  1.1649 +        extra_bits2 = 0x2;
  1.1650 +        break;
  1.1651 +      case 16:
  1.1652 +        //case 32:
  1.1653 +        // doesn't need to be handled-- it is handled by the default ldr/str
  1.1654 +        extra_bits2 = 0x01;
  1.1655 +        extra_bits1 = (ls == IsStore) ? 0 : 1;
  1.1656 +        if (IsSigned) {
  1.1657 +            JS_ASSERT(ls != IsStore);
  1.1658 +            extra_bits2 |= 0x2;
  1.1659 +        }
  1.1660 +        break;
  1.1661 +      case 64:
  1.1662 +        extra_bits2 = (ls == IsStore) ? 0x3 : 0x2;
  1.1663 +        extra_bits1 = 0;
  1.1664 +        break;
  1.1665 +      default:
  1.1666 +        MOZ_ASSUME_UNREACHABLE("SAY WHAT?");
  1.1667 +    }
  1.1668 +    return writeInst(extra_bits2 << 5 | extra_bits1 << 20 | 0x90 |
  1.1669 +                     addr.encode() | RT(rt) | mode | c, dest);
  1.1670 +}
  1.1671 +
  1.1672 +BufferOffset
  1.1673 +Assembler::as_dtm(LoadStore ls, Register rn, uint32_t mask,
  1.1674 +                DTMMode mode, DTMWriteBack wb, Condition c)
  1.1675 +{
  1.1676 +    return writeInst(0x08000000 | RN(rn) | ls |
  1.1677 +                     mode | mask | c | wb);
  1.1678 +}
  1.1679 +
  1.1680 +BufferOffset
  1.1681 +Assembler::as_Imm32Pool(Register dest, uint32_t value, Condition c)
  1.1682 +{
  1.1683 +    PoolHintPun php;
  1.1684 +    php.phd.init(0, c, PoolHintData::poolDTR, dest);
  1.1685 +    return m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value);
  1.1686 +}
  1.1687 +
  1.1688 +void
  1.1689 +Assembler::as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data)
  1.1690 +{
  1.1691 +    JS_ASSERT(addr->is<InstLDR>());
  1.1692 +    int32_t offset = addr->encode() & 0xfff;
  1.1693 +    if ((addr->encode() & IsUp) != IsUp)
  1.1694 +        offset = -offset;
  1.1695 +    char * rawAddr = reinterpret_cast<char*>(addr);
  1.1696 +    uint32_t * dest = reinterpret_cast<uint32_t*>(&rawAddr[offset + 8]);
  1.1697 +    *dest = data;
  1.1698 +    Condition orig_cond;
  1.1699 +    addr->extractCond(&orig_cond);
  1.1700 +    JS_ASSERT(orig_cond == c);
  1.1701 +}
  1.1702 +
  1.1703 +BufferOffset
  1.1704 +Assembler::as_BranchPool(uint32_t value, RepatchLabel *label, ARMBuffer::PoolEntry *pe, Condition c)
  1.1705 +{
  1.1706 +    PoolHintPun php;
  1.1707 +    php.phd.init(0, c, PoolHintData::poolBranch, pc);
  1.1708 +    m_buffer.markNextAsBranch();
  1.1709 +    BufferOffset ret = m_buffer.insertEntry(4, (uint8_t*)&php.raw, int32Pool, (uint8_t*)&value, pe);
  1.1710 +    // If this label is already bound, then immediately replace the stub load with
  1.1711 +    // a correct branch.
  1.1712 +    if (label->bound()) {
  1.1713 +        BufferOffset dest(label);
  1.1714 +        as_b(dest.diffB<BOffImm>(ret), c, ret);
  1.1715 +    } else {
  1.1716 +        label->use(ret.getOffset());
  1.1717 +    }
  1.1718 +    return ret;
  1.1719 +}
  1.1720 +
  1.1721 +BufferOffset
  1.1722 +Assembler::as_FImm64Pool(VFPRegister dest, double value, Condition c)
  1.1723 +{
  1.1724 +    JS_ASSERT(dest.isDouble());
  1.1725 +    PoolHintPun php;
  1.1726 +    php.phd.init(0, c, PoolHintData::poolVDTR, dest);
  1.1727 +    return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&value);
  1.1728 +}
  1.1729 +
  1.1730 +struct PaddedFloat32
  1.1731 +{
  1.1732 +    float value;
  1.1733 +    uint32_t padding;
  1.1734 +};
  1.1735 +JS_STATIC_ASSERT(sizeof(PaddedFloat32) == sizeof(double));
  1.1736 +
  1.1737 +BufferOffset
  1.1738 +Assembler::as_FImm32Pool(VFPRegister dest, float value, Condition c)
  1.1739 +{
  1.1740 +    /*
  1.1741 +     * Insert floats into the double pool as they have the same limitations on
  1.1742 +     * immediate offset.  This wastes 4 bytes padding per float.  An alternative
  1.1743 +     * would be to have a separate pool for floats.
  1.1744 +     */
  1.1745 +    JS_ASSERT(dest.isSingle());
  1.1746 +    PoolHintPun php;
  1.1747 +    php.phd.init(0, c, PoolHintData::poolVDTR, dest);
  1.1748 +    PaddedFloat32 pf = { value, 0 };
  1.1749 +    return m_buffer.insertEntry(4, (uint8_t*)&php.raw, doublePool, (uint8_t*)&pf);
  1.1750 +}
  1.1751 +
  1.1752 +// Pool callbacks stuff:
  1.1753 +void
  1.1754 +Assembler::insertTokenIntoTag(uint32_t instSize, uint8_t *load_, int32_t token)
  1.1755 +{
  1.1756 +    uint32_t *load = (uint32_t*) load_;
  1.1757 +    PoolHintPun php;
  1.1758 +    php.raw = *load;
  1.1759 +    php.phd.setIndex(token);
  1.1760 +    *load = php.raw;
  1.1761 +}
  1.1762 +// patchConstantPoolLoad takes the address of the instruction that wants to be patched, and
  1.1763 +//the address of the start of the constant pool, and figures things out from there.
  1.1764 +bool
  1.1765 +Assembler::patchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
  1.1766 +{
  1.1767 +    PoolHintData data = *(PoolHintData*)loadAddr;
  1.1768 +    uint32_t *instAddr = (uint32_t*) loadAddr;
  1.1769 +    int offset = (char *)constPoolAddr - (char *)loadAddr;
  1.1770 +    switch(data.getLoadType()) {
  1.1771 +      case PoolHintData::poolBOGUS:
  1.1772 +        MOZ_ASSUME_UNREACHABLE("bogus load type!");
  1.1773 +      case PoolHintData::poolDTR:
  1.1774 +        dummy->as_dtr(IsLoad, 32, Offset, data.getReg(),
  1.1775 +                      DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)), data.getCond(), instAddr);
  1.1776 +        break;
  1.1777 +      case PoolHintData::poolBranch:
  1.1778 +        // Either this used to be a poolBranch, and the label was already bound, so it was
  1.1779 +        // replaced with a real branch, or this may happen in the future.
  1.1780 +        // If this is going to happen in the future, then the actual bits that are written here
  1.1781 +        // don't matter (except the condition code, since that is always preserved across
  1.1782 +        // patchings) but if it does not get bound later,
  1.1783 +        // then we want to make sure this is a load from the pool entry (and the pool entry
  1.1784 +        // should be nullptr so it will crash).
  1.1785 +        if (data.isValidPoolHint()) {
  1.1786 +            dummy->as_dtr(IsLoad, 32, Offset, pc,
  1.1787 +                          DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)),
  1.1788 +                          data.getCond(), instAddr);
  1.1789 +        }
  1.1790 +        break;
  1.1791 +      case PoolHintData::poolVDTR: {
  1.1792 +        VFPRegister dest = data.getVFPReg();
  1.1793 +        int32_t imm = offset + (8 * data.getIndex()) - 8;
  1.1794 +        if (imm < -1023 || imm  > 1023)
  1.1795 +            return false;
  1.1796 +        dummy->as_vdtr(IsLoad, dest, VFPAddr(pc, VFPOffImm(imm)), data.getCond(), instAddr);
  1.1797 +        break;
  1.1798 +      }
  1.1799 +    }
  1.1800 +    return true;
  1.1801 +}
  1.1802 +
  1.1803 +uint32_t
  1.1804 +Assembler::placeConstantPoolBarrier(int offset)
  1.1805 +{
  1.1806 +    // BUG: 700526
  1.1807 +    // this is still an active path, however, we do not hit it in the test
  1.1808 +    // suite at all.
  1.1809 +    MOZ_ASSUME_UNREACHABLE("ARMAssembler holdover");
  1.1810 +}
  1.1811 +
  1.1812 +// Control flow stuff:
  1.1813 +
  1.1814 +// bx can *only* branch to a register
  1.1815 +// never to an immediate.
  1.1816 +BufferOffset
  1.1817 +Assembler::as_bx(Register r, Condition c, bool isPatchable)
  1.1818 +{
  1.1819 +    BufferOffset ret = writeInst(((int) c) | op_bx | r.code());
  1.1820 +    if (c == Always && !isPatchable)
  1.1821 +        m_buffer.markGuard();
  1.1822 +    return ret;
  1.1823 +}
  1.1824 +void
  1.1825 +Assembler::writePoolGuard(BufferOffset branch, Instruction *dest, BufferOffset afterPool)
  1.1826 +{
  1.1827 +    BOffImm off = afterPool.diffB<BOffImm>(branch);
  1.1828 +    *dest = InstBImm(off, Always);
  1.1829 +}
  1.1830 +// Branch can branch to an immediate *or* to a register.
  1.1831 +// Branches to immediates are pc relative, branches to registers
  1.1832 +// are absolute
  1.1833 +BufferOffset
  1.1834 +Assembler::as_b(BOffImm off, Condition c, bool isPatchable)
  1.1835 +{
  1.1836 +    m_buffer.markNextAsBranch();
  1.1837 +    BufferOffset ret =writeInst(((int)c) | op_b | off.encode());
  1.1838 +    if (c == Always && !isPatchable)
  1.1839 +        m_buffer.markGuard();
  1.1840 +    return ret;
  1.1841 +}
  1.1842 +
  1.1843 +BufferOffset
  1.1844 +Assembler::as_b(Label *l, Condition c, bool isPatchable)
  1.1845 +{
  1.1846 +    if (m_buffer.oom()) {
  1.1847 +        BufferOffset ret;
  1.1848 +        return ret;
  1.1849 +    }
  1.1850 +    m_buffer.markNextAsBranch();
  1.1851 +    if (l->bound()) {
  1.1852 +        BufferOffset ret = as_nop();
  1.1853 +        as_b(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
  1.1854 +        return ret;
  1.1855 +    }
  1.1856 +
  1.1857 +    int32_t old;
  1.1858 +    BufferOffset ret;
  1.1859 +    if (l->used()) {
  1.1860 +        old = l->offset();
  1.1861 +        // This will currently throw an assertion if we couldn't actually
  1.1862 +        // encode the offset of the branch.
  1.1863 +        if (!BOffImm::isInRange(old)) {
  1.1864 +            m_buffer.fail_bail();
  1.1865 +            return ret;
  1.1866 +        }
  1.1867 +        ret = as_b(BOffImm(old), c, isPatchable);
  1.1868 +    } else {
  1.1869 +        old = LabelBase::INVALID_OFFSET;
  1.1870 +        BOffImm inv;
  1.1871 +        ret = as_b(inv, c, isPatchable);
  1.1872 +    }
  1.1873 +    DebugOnly<int32_t> check = l->use(ret.getOffset());
  1.1874 +    JS_ASSERT(check == old);
  1.1875 +    return ret;
  1.1876 +}
  1.1877 +BufferOffset
  1.1878 +Assembler::as_b(BOffImm off, Condition c, BufferOffset inst)
  1.1879 +{
  1.1880 +    *editSrc(inst) = InstBImm(off, c);
  1.1881 +    return inst;
  1.1882 +}
  1.1883 +
  1.1884 +// blx can go to either an immediate or a register.
  1.1885 +// When blx'ing to a register, we change processor state
  1.1886 +// depending on the low bit of the register
  1.1887 +// when blx'ing to an immediate, we *always* change processor state.
  1.1888 +
  1.1889 +BufferOffset
  1.1890 +Assembler::as_blx(Register r, Condition c)
  1.1891 +{
  1.1892 +    return writeInst(((int) c) | op_blx | r.code());
  1.1893 +}
  1.1894 +
  1.1895 +// bl can only branch to an pc-relative immediate offset
  1.1896 +// It cannot change the processor state.
  1.1897 +BufferOffset
  1.1898 +Assembler::as_bl(BOffImm off, Condition c)
  1.1899 +{
  1.1900 +    m_buffer.markNextAsBranch();
  1.1901 +    return writeInst(((int)c) | op_bl | off.encode());
  1.1902 +}
  1.1903 +
  1.1904 +BufferOffset
  1.1905 +Assembler::as_bl(Label *l, Condition c)
  1.1906 +{
  1.1907 +    if (m_buffer.oom()) {
  1.1908 +        BufferOffset ret;
  1.1909 +        return ret;
  1.1910 +    }
  1.1911 +    m_buffer.markNextAsBranch();
  1.1912 +    if (l->bound()) {
  1.1913 +        BufferOffset ret = as_nop();
  1.1914 +        as_bl(BufferOffset(l).diffB<BOffImm>(ret), c, ret);
  1.1915 +        return ret;
  1.1916 +    }
  1.1917 +
  1.1918 +    int32_t old;
  1.1919 +    BufferOffset ret;
  1.1920 +    // See if the list was empty :(
  1.1921 +    if (l->used()) {
  1.1922 +        // This will currently throw an assertion if we couldn't actually
  1.1923 +        // encode the offset of the branch.
  1.1924 +        old = l->offset();
  1.1925 +        if (!BOffImm::isInRange(old)) {
  1.1926 +            m_buffer.fail_bail();
  1.1927 +            return ret;
  1.1928 +        }
  1.1929 +        ret = as_bl(BOffImm(old), c);
  1.1930 +    } else {
  1.1931 +        old = LabelBase::INVALID_OFFSET;
  1.1932 +        BOffImm inv;
  1.1933 +        ret = as_bl(inv, c);
  1.1934 +    }
  1.1935 +    DebugOnly<int32_t> check = l->use(ret.getOffset());
  1.1936 +    JS_ASSERT(check == old);
  1.1937 +    return ret;
  1.1938 +}
  1.1939 +BufferOffset
  1.1940 +Assembler::as_bl(BOffImm off, Condition c, BufferOffset inst)
  1.1941 +{
  1.1942 +    *editSrc(inst) = InstBLImm(off, c);
  1.1943 +    return inst;
  1.1944 +}
  1.1945 +
  1.1946 +BufferOffset
  1.1947 +Assembler::as_mrs(Register r, Condition c)
  1.1948 +{
  1.1949 +    return writeInst(0x010f0000 | int(c) | RD(r));
  1.1950 +}
  1.1951 +
  1.1952 +BufferOffset
  1.1953 +Assembler::as_msr(Register r, Condition c)
  1.1954 +{
  1.1955 +    // hardcode the 'mask' field to 0b11 for now.  it is bits 18 and 19, which are the two high bits of the 'c' in this constant.
  1.1956 +    JS_ASSERT((r.code() & ~0xf) == 0);
  1.1957 +    return writeInst(0x012cf000 | int(c) | r.code());
  1.1958 +}
  1.1959 +
  1.1960 +// VFP instructions!
  1.1961 +enum vfp_tags {
  1.1962 +    vfp_tag   = 0x0C000A00,
  1.1963 +    vfp_arith = 0x02000000
  1.1964 +};
  1.1965 +BufferOffset
  1.1966 +Assembler::writeVFPInst(vfp_size sz, uint32_t blob, uint32_t *dest)
  1.1967 +{
  1.1968 +    JS_ASSERT((sz & blob) == 0);
  1.1969 +    JS_ASSERT((vfp_tag & blob) == 0);
  1.1970 +    return writeInst(vfp_tag | sz | blob, dest);
  1.1971 +}
  1.1972 +
  1.1973 +// Unityped variants: all registers hold the same (ieee754 single/double)
  1.1974 +// notably not included are vcvt; vmov vd, #imm; vmov rt, vn.
  1.1975 +BufferOffset
  1.1976 +Assembler::as_vfp_float(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1977 +                  VFPOp op, Condition c)
  1.1978 +{
  1.1979 +    // Make sure we believe that all of our operands are the same kind
  1.1980 +    JS_ASSERT_IF(!vn.isMissing(), vd.equiv(vn));
  1.1981 +    JS_ASSERT_IF(!vm.isMissing(), vd.equiv(vm));
  1.1982 +    vfp_size sz = vd.isDouble() ? isDouble : isSingle;
  1.1983 +    return writeVFPInst(sz, VD(vd) | VN(vn) | VM(vm) | op | vfp_arith | c);
  1.1984 +}
  1.1985 +
  1.1986 +BufferOffset
  1.1987 +Assembler::as_vadd(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1988 +                 Condition c)
  1.1989 +{
  1.1990 +    return as_vfp_float(vd, vn, vm, opv_add, c);
  1.1991 +}
  1.1992 +
  1.1993 +BufferOffset
  1.1994 +Assembler::as_vdiv(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.1995 +                 Condition c)
  1.1996 +{
  1.1997 +    return as_vfp_float(vd, vn, vm, opv_div, c);
  1.1998 +}
  1.1999 +
  1.2000 +BufferOffset
  1.2001 +Assembler::as_vmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.2002 +                 Condition c)
  1.2003 +{
  1.2004 +    return as_vfp_float(vd, vn, vm, opv_mul, c);
  1.2005 +}
  1.2006 +
  1.2007 +BufferOffset
  1.2008 +Assembler::as_vnmul(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.2009 +                  Condition c)
  1.2010 +{
  1.2011 +    return as_vfp_float(vd, vn, vm, opv_mul, c);
  1.2012 +    MOZ_ASSUME_UNREACHABLE("Feature NYI");
  1.2013 +}
  1.2014 +
  1.2015 +BufferOffset
  1.2016 +Assembler::as_vnmla(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.2017 +                  Condition c)
  1.2018 +{
  1.2019 +    MOZ_ASSUME_UNREACHABLE("Feature NYI");
  1.2020 +}
  1.2021 +
  1.2022 +BufferOffset
  1.2023 +Assembler::as_vnmls(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.2024 +                  Condition c)
  1.2025 +{
  1.2026 +    MOZ_ASSUME_UNREACHABLE("Feature NYI");
  1.2027 +    return BufferOffset();
  1.2028 +}
  1.2029 +
  1.2030 +BufferOffset
  1.2031 +Assembler::as_vneg(VFPRegister vd, VFPRegister vm, Condition c)
  1.2032 +{
  1.2033 +    return as_vfp_float(vd, NoVFPRegister, vm, opv_neg, c);
  1.2034 +}
  1.2035 +
  1.2036 +BufferOffset
  1.2037 +Assembler::as_vsqrt(VFPRegister vd, VFPRegister vm, Condition c)
  1.2038 +{
  1.2039 +    return as_vfp_float(vd, NoVFPRegister, vm, opv_sqrt, c);
  1.2040 +}
  1.2041 +
  1.2042 +BufferOffset
  1.2043 +Assembler::as_vabs(VFPRegister vd, VFPRegister vm, Condition c)
  1.2044 +{
  1.2045 +    return as_vfp_float(vd, NoVFPRegister, vm, opv_abs, c);
  1.2046 +}
  1.2047 +
  1.2048 +BufferOffset
  1.2049 +Assembler::as_vsub(VFPRegister vd, VFPRegister vn, VFPRegister vm,
  1.2050 +                 Condition c)
  1.2051 +{
  1.2052 +    return as_vfp_float(vd, vn, vm, opv_sub, c);
  1.2053 +}
  1.2054 +
  1.2055 +BufferOffset
  1.2056 +Assembler::as_vcmp(VFPRegister vd, VFPRegister vm,
  1.2057 +                 Condition c)
  1.2058 +{
  1.2059 +    return as_vfp_float(vd, NoVFPRegister, vm, opv_cmp, c);
  1.2060 +}
  1.2061 +BufferOffset
  1.2062 +Assembler::as_vcmpz(VFPRegister vd, Condition c)
  1.2063 +{
  1.2064 +    return as_vfp_float(vd, NoVFPRegister, NoVFPRegister, opv_cmpz, c);
  1.2065 +}
  1.2066 +
  1.2067 +// Specifically, a move between two same sized-registers.
  1.2068 +BufferOffset
  1.2069 +Assembler::as_vmov(VFPRegister vd, VFPRegister vsrc, Condition c)
  1.2070 +{
  1.2071 +    return as_vfp_float(vd, NoVFPRegister, vsrc, opv_mov, c);
  1.2072 +}
  1.2073 +//xfer between Core and VFP
  1.2074 +
  1.2075 +// Unlike the next function, moving between the core registers and vfp
  1.2076 +// registers can't be *that* properly typed.  Namely, since I don't want to
  1.2077 +// munge the type VFPRegister to also include core registers.  Thus, the core
  1.2078 +// and vfp registers are passed in based on their type, and src/dest is
  1.2079 +// determined by the float2core.
  1.2080 +
  1.2081 +BufferOffset
  1.2082 +Assembler::as_vxfer(Register vt1, Register vt2, VFPRegister vm, FloatToCore_ f2c,
  1.2083 +                    Condition c, int idx)
  1.2084 +{
  1.2085 +    vfp_size sz = isSingle;
  1.2086 +    if (vm.isDouble()) {
  1.2087 +        // Technically, this can be done with a vmov à la ARM ARM under vmov
  1.2088 +        // however, that requires at least an extra bit saying if the
  1.2089 +        // operation should be performed on the lower or upper half of the
  1.2090 +        // double.  Moving a single to/from 2N/2N+1 isn't equivalent,
  1.2091 +        // since there are 32 single registers, and 32 double registers
  1.2092 +        // so there is no way to encode the last 16 double registers.
  1.2093 +        sz = isDouble;
  1.2094 +        JS_ASSERT(idx == 0 || idx == 1);
  1.2095 +        // If we are transferring a single half of the double
  1.2096 +        // then it must be moving a VFP reg to a core reg.
  1.2097 +        if (vt2 == InvalidReg)
  1.2098 +            JS_ASSERT(f2c == FloatToCore);
  1.2099 +        idx = idx << 21;
  1.2100 +    } else {
  1.2101 +        JS_ASSERT(idx == 0);
  1.2102 +    }
  1.2103 +    VFPXferSize xfersz = WordTransfer;
  1.2104 +    uint32_t (*encodeVFP)(VFPRegister) = VN;
  1.2105 +    if (vt2 != InvalidReg) {
  1.2106 +        // We are doing a 64 bit transfer.
  1.2107 +        xfersz = DoubleTransfer;
  1.2108 +        encodeVFP = VM;
  1.2109 +    }
  1.2110 +
  1.2111 +    return writeVFPInst(sz, xfersz | f2c | c |
  1.2112 +                        RT(vt1) | maybeRN(vt2) | encodeVFP(vm) | idx);
  1.2113 +}
  1.2114 +enum vcvt_destFloatness {
  1.2115 +    toInteger = 1 << 18,
  1.2116 +    toFloat  = 0 << 18
  1.2117 +};
  1.2118 +enum vcvt_toZero {
  1.2119 +    toZero = 1 << 7, // use the default rounding mode, which rounds truncates
  1.2120 +    toFPSCR = 0 << 7 // use whatever rounding mode the fpscr specifies
  1.2121 +};
  1.2122 +enum vcvt_Signedness {
  1.2123 +    toSigned   = 1 << 16,
  1.2124 +    toUnsigned = 0 << 16,
  1.2125 +    fromSigned   = 1 << 7,
  1.2126 +    fromUnsigned = 0 << 7
  1.2127 +};
  1.2128 +
  1.2129 +// our encoding actually allows just the src and the dest (and their types)
  1.2130 +// to uniquely specify the encoding that we are going to use.
  1.2131 +BufferOffset
  1.2132 +Assembler::as_vcvt(VFPRegister vd, VFPRegister vm, bool useFPSCR,
  1.2133 +                   Condition c)
  1.2134 +{
  1.2135 +    // Unlike other cases, the source and dest types cannot be the same
  1.2136 +    JS_ASSERT(!vd.equiv(vm));
  1.2137 +    vfp_size sz = isDouble;
  1.2138 +    if (vd.isFloat() && vm.isFloat()) {
  1.2139 +        // Doing a float -> float conversion
  1.2140 +        if (vm.isSingle())
  1.2141 +            sz = isSingle;
  1.2142 +        return writeVFPInst(sz, c | 0x02B700C0 |
  1.2143 +                            VM(vm) | VD(vd));
  1.2144 +    }
  1.2145 +
  1.2146 +    // At least one of the registers should be a float.
  1.2147 +    vcvt_destFloatness destFloat;
  1.2148 +    vcvt_Signedness opSign;
  1.2149 +    vcvt_toZero doToZero = toFPSCR;
  1.2150 +    JS_ASSERT(vd.isFloat() || vm.isFloat());
  1.2151 +    if (vd.isSingle() || vm.isSingle()) {
  1.2152 +        sz = isSingle;
  1.2153 +    }
  1.2154 +    if (vd.isFloat()) {
  1.2155 +        destFloat = toFloat;
  1.2156 +        opSign = (vm.isSInt()) ? fromSigned : fromUnsigned;
  1.2157 +    } else {
  1.2158 +        destFloat = toInteger;
  1.2159 +        opSign = (vd.isSInt()) ? toSigned : toUnsigned;
  1.2160 +        doToZero = useFPSCR ? toFPSCR : toZero;
  1.2161 +    }
  1.2162 +    return writeVFPInst(sz, c | 0x02B80040 | VD(vd) | VM(vm) | destFloat | opSign | doToZero);
  1.2163 +}
  1.2164 +
  1.2165 +BufferOffset
  1.2166 +Assembler::as_vcvtFixed(VFPRegister vd, bool isSigned, uint32_t fixedPoint, bool toFixed, Condition c)
  1.2167 +{
  1.2168 +    JS_ASSERT(vd.isFloat());
  1.2169 +    uint32_t sx = 0x1;
  1.2170 +    vfp_size sf = vd.isDouble() ? isDouble : isSingle;
  1.2171 +    int32_t imm5 = fixedPoint;
  1.2172 +    imm5 = (sx ? 32 : 16) - imm5;
  1.2173 +    JS_ASSERT(imm5 >= 0);
  1.2174 +    imm5 = imm5 >> 1 | (imm5 & 1) << 5;
  1.2175 +    return writeVFPInst(sf, 0x02BA0040 | VD(vd) | toFixed << 18 | sx << 7 |
  1.2176 +                        (!isSigned) << 16 | imm5 | c);
  1.2177 +}
  1.2178 +
  1.2179 +// xfer between VFP and memory
  1.2180 +BufferOffset
  1.2181 +Assembler::as_vdtr(LoadStore ls, VFPRegister vd, VFPAddr addr,
  1.2182 +                   Condition c /* vfp doesn't have a wb option*/,
  1.2183 +                   uint32_t *dest)
  1.2184 +{
  1.2185 +    vfp_size sz = vd.isDouble() ? isDouble : isSingle;
  1.2186 +    return writeVFPInst(sz, ls | 0x01000000 | addr.encode() | VD(vd) | c, dest);
  1.2187 +}
  1.2188 +
  1.2189 +// VFP's ldm/stm work differently from the standard arm ones.
  1.2190 +// You can only transfer a range
  1.2191 +
  1.2192 +BufferOffset
  1.2193 +Assembler::as_vdtm(LoadStore st, Register rn, VFPRegister vd, int length,
  1.2194 +                 /*also has update conditions*/Condition c)
  1.2195 +{
  1.2196 +    JS_ASSERT(length <= 16 && length >= 0);
  1.2197 +    vfp_size sz = vd.isDouble() ? isDouble : isSingle;
  1.2198 +
  1.2199 +    if (vd.isDouble())
  1.2200 +        length *= 2;
  1.2201 +
  1.2202 +    return writeVFPInst(sz, dtmLoadStore | RN(rn) | VD(vd) |
  1.2203 +                        length |
  1.2204 +                        dtmMode | dtmUpdate | dtmCond);
  1.2205 +}
  1.2206 +
  1.2207 +BufferOffset
  1.2208 +Assembler::as_vimm(VFPRegister vd, VFPImm imm, Condition c)
  1.2209 +{
  1.2210 +    JS_ASSERT(imm.isValid());
  1.2211 +    vfp_size sz = vd.isDouble() ? isDouble : isSingle;
  1.2212 +    return writeVFPInst(sz,  c | imm.encode() | VD(vd) | 0x02B00000);
  1.2213 +
  1.2214 +}
  1.2215 +BufferOffset
  1.2216 +Assembler::as_vmrs(Register r, Condition c)
  1.2217 +{
  1.2218 +    return writeInst(c | 0x0ef10a10 | RT(r));
  1.2219 +}
  1.2220 +
  1.2221 +BufferOffset
  1.2222 +Assembler::as_vmsr(Register r, Condition c)
  1.2223 +{
  1.2224 +    return writeInst(c | 0x0ee10a10 | RT(r));
  1.2225 +}
  1.2226 +
  1.2227 +bool
  1.2228 +Assembler::nextLink(BufferOffset b, BufferOffset *next)
  1.2229 +{
  1.2230 +    Instruction branch = *editSrc(b);
  1.2231 +    JS_ASSERT(branch.is<InstBranchImm>());
  1.2232 +
  1.2233 +    BOffImm destOff;
  1.2234 +    branch.as<InstBranchImm>()->extractImm(&destOff);
  1.2235 +    if (destOff.isInvalid())
  1.2236 +        return false;
  1.2237 +
  1.2238 +    // Propagate the next link back to the caller, by
  1.2239 +    // constructing a new BufferOffset into the space they
  1.2240 +    // provided.
  1.2241 +    new (next) BufferOffset(destOff.decode());
  1.2242 +    return true;
  1.2243 +}
  1.2244 +
  1.2245 +void
  1.2246 +Assembler::bind(Label *label, BufferOffset boff)
  1.2247 +{
  1.2248 +    if (label->used()) {
  1.2249 +        bool more;
  1.2250 +        // If our caller didn't give us an explicit target to bind to
  1.2251 +        // then we want to bind to the location of the next instruction
  1.2252 +        BufferOffset dest = boff.assigned() ? boff : nextOffset();
  1.2253 +        BufferOffset b(label);
  1.2254 +        do {
  1.2255 +            BufferOffset next;
  1.2256 +            more = nextLink(b, &next);
  1.2257 +            Instruction branch = *editSrc(b);
  1.2258 +            Condition c;
  1.2259 +            branch.extractCond(&c);
  1.2260 +            if (branch.is<InstBImm>())
  1.2261 +                as_b(dest.diffB<BOffImm>(b), c, b);
  1.2262 +            else if (branch.is<InstBLImm>())
  1.2263 +                as_bl(dest.diffB<BOffImm>(b), c, b);
  1.2264 +            else
  1.2265 +                MOZ_ASSUME_UNREACHABLE("crazy fixup!");
  1.2266 +            b = next;
  1.2267 +        } while (more);
  1.2268 +    }
  1.2269 +    label->bind(nextOffset().getOffset());
  1.2270 +}
  1.2271 +
  1.2272 +void
  1.2273 +Assembler::bind(RepatchLabel *label)
  1.2274 +{
  1.2275 +    BufferOffset dest = nextOffset();
  1.2276 +    if (label->used()) {
  1.2277 +        // If the label has a use, then change this use to refer to
  1.2278 +        // the bound label;
  1.2279 +        BufferOffset branchOff(label->offset());
  1.2280 +        // Since this was created with a RepatchLabel, the value written in the
  1.2281 +        // instruction stream is not branch shaped, it is PoolHintData shaped.
  1.2282 +        Instruction *branch = editSrc(branchOff);
  1.2283 +        PoolHintPun p;
  1.2284 +        p.raw = branch->encode();
  1.2285 +        Condition cond;
  1.2286 +        if (p.phd.isValidPoolHint())
  1.2287 +            cond = p.phd.getCond();
  1.2288 +        else
  1.2289 +            branch->extractCond(&cond);
  1.2290 +        as_b(dest.diffB<BOffImm>(branchOff), cond, branchOff);
  1.2291 +    }
  1.2292 +    label->bind(dest.getOffset());
  1.2293 +}
  1.2294 +
  1.2295 +void
  1.2296 +Assembler::retarget(Label *label, Label *target)
  1.2297 +{
  1.2298 +    if (label->used()) {
  1.2299 +        if (target->bound()) {
  1.2300 +            bind(label, BufferOffset(target));
  1.2301 +        } else if (target->used()) {
  1.2302 +            // The target is not bound but used. Prepend label's branch list
  1.2303 +            // onto target's.
  1.2304 +            BufferOffset labelBranchOffset(label);
  1.2305 +            BufferOffset next;
  1.2306 +
  1.2307 +            // Find the head of the use chain for label.
  1.2308 +            while (nextLink(labelBranchOffset, &next))
  1.2309 +                labelBranchOffset = next;
  1.2310 +
  1.2311 +            // Then patch the head of label's use chain to the tail of
  1.2312 +            // target's use chain, prepending the entire use chain of target.
  1.2313 +            Instruction branch = *editSrc(labelBranchOffset);
  1.2314 +            Condition c;
  1.2315 +            branch.extractCond(&c);
  1.2316 +            int32_t prev = target->use(label->offset());
  1.2317 +            if (branch.is<InstBImm>())
  1.2318 +                as_b(BOffImm(prev), c, labelBranchOffset);
  1.2319 +            else if (branch.is<InstBLImm>())
  1.2320 +                as_bl(BOffImm(prev), c, labelBranchOffset);
  1.2321 +            else
  1.2322 +                MOZ_ASSUME_UNREACHABLE("crazy fixup!");
  1.2323 +        } else {
  1.2324 +            // The target is unbound and unused.  We can just take the head of
  1.2325 +            // the list hanging off of label, and dump that into target.
  1.2326 +            DebugOnly<uint32_t> prev = target->use(label->offset());
  1.2327 +            JS_ASSERT((int32_t)prev == Label::INVALID_OFFSET);
  1.2328 +        }
  1.2329 +    }
  1.2330 +    label->reset();
  1.2331 +
  1.2332 +}
  1.2333 +
  1.2334 +
  1.2335 +void dbg_break() {}
  1.2336 +static int stopBKPT = -1;
  1.2337 +void
  1.2338 +Assembler::as_bkpt()
  1.2339 +{
  1.2340 +    // This is a count of how many times a breakpoint instruction has been generated.
  1.2341 +    // It is embedded into the instruction for debugging purposes.  gdb will print "bkpt xxx"
  1.2342 +    // when you attempt to dissassemble a breakpoint with the number xxx embedded into it.
  1.2343 +    // If this breakpoint is being hit, then you can run (in gdb)
  1.2344 +    // >b dbg_break
  1.2345 +    // >b main
  1.2346 +    // >commands
  1.2347 +    // >set stopBKPT = xxx
  1.2348 +    // >c
  1.2349 +    // >end
  1.2350 +
  1.2351 +    // which will set a breakpoint on the function dbg_break above
  1.2352 +    // set a scripted breakpoint on main that will set the (otherwise unmodified)
  1.2353 +    // value to the number of the breakpoint, so dbg_break will actuall be called
  1.2354 +    // and finally, when you run the executable, execution will halt when that
  1.2355 +    // breakpoint is generated
  1.2356 +    static int hit = 0;
  1.2357 +    if (stopBKPT == hit)
  1.2358 +        dbg_break();
  1.2359 +    writeInst(0xe1200070 | (hit & 0xf) | ((hit & 0xfff0)<<4));
  1.2360 +    hit++;
  1.2361 +}
  1.2362 +
  1.2363 +void
  1.2364 +Assembler::dumpPool()
  1.2365 +{
  1.2366 +    m_buffer.flushPool();
  1.2367 +}
  1.2368 +
  1.2369 +void
  1.2370 +Assembler::flushBuffer()
  1.2371 +{
  1.2372 +    m_buffer.flushPool();
  1.2373 +}
  1.2374 +
  1.2375 +void
  1.2376 +Assembler::enterNoPool()
  1.2377 +{
  1.2378 +    m_buffer.enterNoPool();
  1.2379 +}
  1.2380 +
  1.2381 +void
  1.2382 +Assembler::leaveNoPool()
  1.2383 +{
  1.2384 +    m_buffer.leaveNoPool();
  1.2385 +}
  1.2386 +
  1.2387 +ptrdiff_t
  1.2388 +Assembler::getBranchOffset(const Instruction *i_)
  1.2389 +{
  1.2390 +    if (!i_->is<InstBranchImm>())
  1.2391 +        return 0;
  1.2392 +
  1.2393 +    InstBranchImm *i = i_->as<InstBranchImm>();
  1.2394 +    BOffImm dest;
  1.2395 +    i->extractImm(&dest);
  1.2396 +    return dest.decode();
  1.2397 +}
  1.2398 +void
  1.2399 +Assembler::retargetNearBranch(Instruction *i, int offset, bool final)
  1.2400 +{
  1.2401 +    Assembler::Condition c;
  1.2402 +    i->extractCond(&c);
  1.2403 +    retargetNearBranch(i, offset, c, final);
  1.2404 +}
  1.2405 +
  1.2406 +void
  1.2407 +Assembler::retargetNearBranch(Instruction *i, int offset, Condition cond, bool final)
  1.2408 +{
  1.2409 +    // Retargeting calls is totally unsupported!
  1.2410 +    JS_ASSERT_IF(i->is<InstBranchImm>(), i->is<InstBImm>() || i->is<InstBLImm>());
  1.2411 +    if (i->is<InstBLImm>())
  1.2412 +        new (i) InstBLImm(BOffImm(offset), cond);
  1.2413 +    else
  1.2414 +        new (i) InstBImm(BOffImm(offset), cond);
  1.2415 +
  1.2416 +    // Flush the cache, since an instruction was overwritten
  1.2417 +    if (final)
  1.2418 +        AutoFlushICache::flush(uintptr_t(i), 4);
  1.2419 +}
  1.2420 +
  1.2421 +void
  1.2422 +Assembler::retargetFarBranch(Instruction *i, uint8_t **slot, uint8_t *dest, Condition cond)
  1.2423 +{
  1.2424 +    int32_t offset = reinterpret_cast<uint8_t*>(slot) - reinterpret_cast<uint8_t*>(i);
  1.2425 +    if (!i->is<InstLDR>()) {
  1.2426 +        new (i) InstLDR(Offset, pc, DTRAddr(pc, DtrOffImm(offset - 8)), cond);
  1.2427 +        AutoFlushICache::flush(uintptr_t(i), 4);
  1.2428 +    }
  1.2429 +    *slot = dest;
  1.2430 +
  1.2431 +}
  1.2432 +
  1.2433 +struct PoolHeader : Instruction {
  1.2434 +    struct Header
  1.2435 +    {
  1.2436 +        // size should take into account the pool header.
  1.2437 +        // size is in units of Instruction (4bytes), not byte
  1.2438 +        uint32_t size : 15;
  1.2439 +        bool isNatural : 1;
  1.2440 +        uint32_t ONES : 16;
  1.2441 +
  1.2442 +        Header(int size_, bool isNatural_)
  1.2443 +          : size(size_),
  1.2444 +            isNatural(isNatural_),
  1.2445 +            ONES(0xffff)
  1.2446 +        { }
  1.2447 +
  1.2448 +        Header(const Instruction *i) {
  1.2449 +            JS_STATIC_ASSERT(sizeof(Header) == sizeof(uint32_t));
  1.2450 +            memcpy(this, i, sizeof(Header));
  1.2451 +            JS_ASSERT(ONES == 0xffff);
  1.2452 +        }
  1.2453 +
  1.2454 +        uint32_t raw() const {
  1.2455 +            JS_STATIC_ASSERT(sizeof(Header) == sizeof(uint32_t));
  1.2456 +            uint32_t dest;
  1.2457 +            memcpy(&dest, this, sizeof(Header));
  1.2458 +            return dest;
  1.2459 +        }
  1.2460 +    };
  1.2461 +
  1.2462 +    PoolHeader(int size_, bool isNatural_)
  1.2463 +      : Instruction(Header(size_, isNatural_).raw(), true)
  1.2464 +    { }
  1.2465 +
  1.2466 +    uint32_t size() const {
  1.2467 +        Header tmp(this);
  1.2468 +        return tmp.size;
  1.2469 +    }
  1.2470 +    uint32_t isNatural() const {
  1.2471 +        Header tmp(this);
  1.2472 +        return tmp.isNatural;
  1.2473 +    }
  1.2474 +    static bool isTHIS(const Instruction &i) {
  1.2475 +        return (*i.raw() & 0xffff0000) == 0xffff0000;
  1.2476 +    }
  1.2477 +    static const PoolHeader *asTHIS(const Instruction &i) {
  1.2478 +        if (!isTHIS(i))
  1.2479 +            return nullptr;
  1.2480 +        return static_cast<const PoolHeader*>(&i);
  1.2481 +    }
  1.2482 +};
  1.2483 +
  1.2484 +
  1.2485 +void
  1.2486 +Assembler::writePoolHeader(uint8_t *start, Pool *p, bool isNatural)
  1.2487 +{
  1.2488 +    STATIC_ASSERT(sizeof(PoolHeader) == 4);
  1.2489 +    uint8_t *pool = start+4;
  1.2490 +    // go through the usual rigaramarole to get the size of the pool.
  1.2491 +    pool = p[0].addPoolSize(pool);
  1.2492 +    pool = p[1].addPoolSize(pool);
  1.2493 +    pool = p[1].other->addPoolSize(pool);
  1.2494 +    pool = p[0].other->addPoolSize(pool);
  1.2495 +    uint32_t size = pool - start;
  1.2496 +    JS_ASSERT((size & 3) == 0);
  1.2497 +    size = size >> 2;
  1.2498 +    JS_ASSERT(size < (1 << 15));
  1.2499 +    PoolHeader header(size, isNatural);
  1.2500 +    *(PoolHeader*)start = header;
  1.2501 +}
  1.2502 +
  1.2503 +
  1.2504 +void
  1.2505 +Assembler::writePoolFooter(uint8_t *start, Pool *p, bool isNatural)
  1.2506 +{
  1.2507 +    return;
  1.2508 +}
  1.2509 +
  1.2510 +// The size of an arbitrary 32-bit call in the instruction stream.
  1.2511 +// On ARM this sequence is |pc = ldr pc - 4; imm32| given that we
  1.2512 +// never reach the imm32.
  1.2513 +uint32_t
  1.2514 +Assembler::patchWrite_NearCallSize()
  1.2515 +{
  1.2516 +    return sizeof(uint32_t);
  1.2517 +}
  1.2518 +void
  1.2519 +Assembler::patchWrite_NearCall(CodeLocationLabel start, CodeLocationLabel toCall)
  1.2520 +{
  1.2521 +    Instruction *inst = (Instruction *) start.raw();
  1.2522 +    // Overwrite whatever instruction used to be here with a call.
  1.2523 +    // Since the destination is in the same function, it will be within range of the 24<<2 byte
  1.2524 +    // bl instruction.
  1.2525 +    uint8_t *dest = toCall.raw();
  1.2526 +    new (inst) InstBLImm(BOffImm(dest - (uint8_t*)inst) , Always);
  1.2527 +    // Ensure everyone sees the code that was just written into memory.
  1.2528 +
  1.2529 +    AutoFlushICache::flush(uintptr_t(inst), 4);
  1.2530 +
  1.2531 +}
  1.2532 +void
  1.2533 +Assembler::patchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newValue,
  1.2534 +                                   PatchedImmPtr expectedValue)
  1.2535 +{
  1.2536 +    Instruction *ptr = (Instruction *) label.raw();
  1.2537 +    InstructionIterator iter(ptr);
  1.2538 +    Register dest;
  1.2539 +    Assembler::RelocStyle rs;
  1.2540 +    DebugOnly<const uint32_t *> val = getPtr32Target(&iter, &dest, &rs);
  1.2541 +    JS_ASSERT((uint32_t)(const uint32_t *)val == uint32_t(expectedValue.value));
  1.2542 +    reinterpret_cast<MacroAssemblerARM*>(dummy)->ma_movPatchable(Imm32(int32_t(newValue.value)),
  1.2543 +                                                                 dest, Always, rs, ptr);
  1.2544 +    // L_LDR won't cause any instructions to be updated.
  1.2545 +    if (rs != L_LDR) {
  1.2546 +        AutoFlushICache::flush(uintptr_t(ptr), 4);
  1.2547 +        AutoFlushICache::flush(uintptr_t(ptr->next()), 4);
  1.2548 +    }
  1.2549 +}
  1.2550 +
  1.2551 +void
  1.2552 +Assembler::patchDataWithValueCheck(CodeLocationLabel label, ImmPtr newValue, ImmPtr expectedValue)
  1.2553 +{
  1.2554 +    patchDataWithValueCheck(label, PatchedImmPtr(newValue.value), PatchedImmPtr(expectedValue.value));
  1.2555 +}
  1.2556 +
  1.2557 +// This just stomps over memory with 32 bits of raw data. Its purpose is to
  1.2558 +// overwrite the call of JITed code with 32 bits worth of an offset. This will
  1.2559 +// is only meant to function on code that has been invalidated, so it should
  1.2560 +// be totally safe. Since that instruction will never be executed again, a
  1.2561 +// ICache flush should not be necessary
  1.2562 +void
  1.2563 +Assembler::patchWrite_Imm32(CodeLocationLabel label, Imm32 imm) {
  1.2564 +    // Raw is going to be the return address.
  1.2565 +    uint32_t *raw = (uint32_t*)label.raw();
  1.2566 +    // Overwrite the 4 bytes before the return address, which will
  1.2567 +    // end up being the call instruction.
  1.2568 +    *(raw-1) = imm.value;
  1.2569 +}
  1.2570 +
  1.2571 +
  1.2572 +uint8_t *
  1.2573 +Assembler::nextInstruction(uint8_t *inst_, uint32_t *count)
  1.2574 +{
  1.2575 +    Instruction *inst = reinterpret_cast<Instruction*>(inst_);
  1.2576 +    if (count != nullptr)
  1.2577 +        *count += sizeof(Instruction);
  1.2578 +    return reinterpret_cast<uint8_t*>(inst->next());
  1.2579 +}
  1.2580 +
  1.2581 +static bool
  1.2582 +InstIsGuard(Instruction *inst, const PoolHeader **ph)
  1.2583 +{
  1.2584 +    Assembler::Condition c;
  1.2585 +    inst->extractCond(&c);
  1.2586 +    if (c != Assembler::Always)
  1.2587 +        return false;
  1.2588 +    if (!(inst->is<InstBXReg>() || inst->is<InstBImm>()))
  1.2589 +        return false;
  1.2590 +    // See if the next instruction is a pool header.
  1.2591 +    *ph = (inst+1)->as<const PoolHeader>();
  1.2592 +    return *ph != nullptr;
  1.2593 +}
  1.2594 +
  1.2595 +static bool
  1.2596 +InstIsBNop(Instruction *inst) {
  1.2597 +    // In some special situations, it is necessary to insert a NOP
  1.2598 +    // into the instruction stream that nobody knows about, since nobody should know about
  1.2599 +    // it, make sure it gets skipped when Instruction::next() is called.
  1.2600 +    // this generates a very specific nop, namely a branch to the next instruction.
  1.2601 +    Assembler::Condition c;
  1.2602 +    inst->extractCond(&c);
  1.2603 +    if (c != Assembler::Always)
  1.2604 +        return false;
  1.2605 +    if (!inst->is<InstBImm>())
  1.2606 +        return false;
  1.2607 +    InstBImm *b = inst->as<InstBImm>();
  1.2608 +    BOffImm offset;
  1.2609 +    b->extractImm(&offset);
  1.2610 +    return offset.decode() == 4;
  1.2611 +}
  1.2612 +
  1.2613 +static bool
  1.2614 +InstIsArtificialGuard(Instruction *inst, const PoolHeader **ph)
  1.2615 +{
  1.2616 +    if (!InstIsGuard(inst, ph))
  1.2617 +        return false;
  1.2618 +    return !(*ph)->isNatural();
  1.2619 +}
  1.2620 +
  1.2621 +// Cases to be handled:
  1.2622 +// 1) no pools or branches in sight => return this+1
  1.2623 +// 2) branch to next instruction => return this+2, because a nop needed to be inserted into the stream.
  1.2624 +// 3) this+1 is an artificial guard for a pool => return first instruction after the pool
  1.2625 +// 4) this+1 is a natural guard => return the branch
  1.2626 +// 5) this is a branch, right before a pool => return first instruction after the pool
  1.2627 +// in assembly form:
  1.2628 +// 1) add r0, r0, r0 <= this
  1.2629 +//    add r1, r1, r1 <= returned value
  1.2630 +//    add r2, r2, r2
  1.2631 +//
  1.2632 +// 2) add r0, r0, r0 <= this
  1.2633 +//    b foo
  1.2634 +//    foo:
  1.2635 +//    add r2, r2, r2 <= returned value
  1.2636 +//
  1.2637 +// 3) add r0, r0, r0 <= this
  1.2638 +//    b after_pool;
  1.2639 +//    .word 0xffff0002  # bit 15 being 0 indicates that the branch was not requested by the assembler
  1.2640 +//    0xdeadbeef        # the 2 indicates that there is 1 pool entry, and the pool header
  1.2641 +//    add r4, r4, r4 <= returned value
  1.2642 +// 4) add r0, r0, r0 <= this
  1.2643 +//    b after_pool  <= returned value
  1.2644 +//    .word 0xffff8002  # bit 15 being 1 indicates that the branch was requested by the assembler
  1.2645 +//    0xdeadbeef
  1.2646 +//    add r4, r4, r4
  1.2647 +// 5) b after_pool  <= this
  1.2648 +//    .word 0xffff8002  # bit 15 has no bearing on the returned value
  1.2649 +//    0xdeadbeef
  1.2650 +//    add r4, r4, r4  <= returned value
  1.2651 +
  1.2652 +Instruction *
  1.2653 +Instruction::next()
  1.2654 +{
  1.2655 +    Instruction *ret = this+1;
  1.2656 +    const PoolHeader *ph;
  1.2657 +    // If this is a guard, and the next instruction is a header, always work around the pool
  1.2658 +    // If it isn't a guard, then start looking ahead.
  1.2659 +    if (InstIsGuard(this, &ph))
  1.2660 +        return ret + ph->size();
  1.2661 +    if (InstIsArtificialGuard(ret, &ph))
  1.2662 +        return ret + 1 + ph->size();
  1.2663 +    if (InstIsBNop(ret))
  1.2664 +        return ret + 1;
  1.2665 +    return ret;
  1.2666 +}
  1.2667 +
  1.2668 +void
  1.2669 +Assembler::ToggleToJmp(CodeLocationLabel inst_)
  1.2670 +{
  1.2671 +    uint32_t *ptr = (uint32_t *)inst_.raw();
  1.2672 +
  1.2673 +    DebugOnly<Instruction *> inst = (Instruction *)inst_.raw();
  1.2674 +    JS_ASSERT(inst->is<InstCMP>());
  1.2675 +
  1.2676 +    // Zero bits 20-27, then set 24-27 to be correct for a branch.
  1.2677 +    // 20-23 will be party of the B's immediate, and should be 0.
  1.2678 +    *ptr = (*ptr & ~(0xff << 20)) | (0xa0 << 20);
  1.2679 +    AutoFlushICache::flush(uintptr_t(ptr), 4);
  1.2680 +}
  1.2681 +
  1.2682 +void
  1.2683 +Assembler::ToggleToCmp(CodeLocationLabel inst_)
  1.2684 +{
  1.2685 +    uint32_t *ptr = (uint32_t *)inst_.raw();
  1.2686 +
  1.2687 +    DebugOnly<Instruction *> inst = (Instruction *)inst_.raw();
  1.2688 +    JS_ASSERT(inst->is<InstBImm>());
  1.2689 +
  1.2690 +    // Ensure that this masking operation doesn't affect the offset of the
  1.2691 +    // branch instruction when it gets toggled back.
  1.2692 +    JS_ASSERT((*ptr & (0xf << 20)) == 0);
  1.2693 +
  1.2694 +    // Also make sure that the CMP is valid. Part of having a valid CMP is that
  1.2695 +    // all of the bits describing the destination in most ALU instructions are
  1.2696 +    // all unset (looks like it is encoding r0).
  1.2697 +    JS_ASSERT(toRD(*inst) == r0);
  1.2698 +
  1.2699 +    // Zero out bits 20-27, then set them to be correct for a compare.
  1.2700 +    *ptr = (*ptr & ~(0xff << 20)) | (0x35 << 20);
  1.2701 +
  1.2702 +    AutoFlushICache::flush(uintptr_t(ptr), 4);
  1.2703 +}
  1.2704 +
  1.2705 +void
  1.2706 +Assembler::ToggleCall(CodeLocationLabel inst_, bool enabled)
  1.2707 +{
  1.2708 +    Instruction *inst = (Instruction *)inst_.raw();
  1.2709 +    JS_ASSERT(inst->is<InstMovW>() || inst->is<InstLDR>());
  1.2710 +
  1.2711 +    if (inst->is<InstMovW>()) {
  1.2712 +        // If it looks like the start of a movw/movt sequence,
  1.2713 +        // then make sure we have all of it (and advance the iterator
  1.2714 +        // past the full sequence)
  1.2715 +        inst = inst->next();
  1.2716 +        JS_ASSERT(inst->is<InstMovT>());
  1.2717 +    }
  1.2718 +
  1.2719 +    inst = inst->next();
  1.2720 +    JS_ASSERT(inst->is<InstNOP>() || inst->is<InstBLXReg>());
  1.2721 +
  1.2722 +    if (enabled == inst->is<InstBLXReg>()) {
  1.2723 +        // Nothing to do.
  1.2724 +        return;
  1.2725 +    }
  1.2726 +
  1.2727 +    if (enabled)
  1.2728 +        *inst = InstBLXReg(ScratchRegister, Always);
  1.2729 +    else
  1.2730 +        *inst = InstNOP();
  1.2731 +
  1.2732 +    AutoFlushICache::flush(uintptr_t(inst), 4);
  1.2733 +}
  1.2734 +
  1.2735 +void Assembler::updateBoundsCheck(uint32_t heapSize, Instruction *inst)
  1.2736 +{
  1.2737 +    JS_ASSERT(inst->is<InstCMP>());
  1.2738 +    InstCMP *cmp = inst->as<InstCMP>();
  1.2739 +
  1.2740 +    Register index;
  1.2741 +    cmp->extractOp1(&index);
  1.2742 +
  1.2743 +    Operand2 op = cmp->extractOp2();
  1.2744 +    JS_ASSERT(op.isImm8());
  1.2745 +
  1.2746 +    Imm8 imm8 = Imm8(heapSize);
  1.2747 +    JS_ASSERT(!imm8.invalid);
  1.2748 +
  1.2749 +    *inst = InstALU(InvalidReg, index, imm8, op_cmp, SetCond, Always);
  1.2750 +    // NOTE: we don't update the Auto Flush Cache!  this function is currently only called from
  1.2751 +    // within AsmJSModule::patchHeapAccesses, which does that for us.  Don't call this!
  1.2752 +}
  1.2753 +
  1.2754 +InstructionIterator::InstructionIterator(Instruction *i_) : i(i_) {
  1.2755 +    const PoolHeader *ph;
  1.2756 +    // If this is a guard, and the next instruction is a header, always work around the pool
  1.2757 +    // If it isn't a guard, then start looking ahead.
  1.2758 +    if (InstIsArtificialGuard(i, &ph)) {
  1.2759 +        i = i->next();
  1.2760 +    }
  1.2761 +}
  1.2762 +Assembler *Assembler::dummy = nullptr;

mercurial