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;