Bug 1127243 - Get rid of the Dummy MacroAssembler* hack in the ARM backend. r=mjrosenb

This commit is contained in:
Jan de Mooij 2015-02-03 11:56:14 +01:00
parent 8f3aaa6e24
commit 2c02896979
4 changed files with 220 additions and 127 deletions

View File

@ -797,7 +797,7 @@ Assembler::TraceJumpRelocations(JSTracer *trc, JitCode *code, CompactBufferReade
template <class Iter>
static void
TraceOneDataRelocation(JSTracer *trc, Iter *iter, MacroAssemblerARM *masm)
TraceOneDataRelocation(JSTracer *trc, Iter *iter)
{
Instruction *ins = iter->cur();
Register dest;
@ -815,7 +815,8 @@ TraceOneDataRelocation(JSTracer *trc, Iter *iter, MacroAssemblerARM *masm)
gc::MarkGCThingUnbarriered(trc, &ptr, "ion-masm-ptr");
if (ptr != prior) {
masm->ma_movPatchable(Imm32(int32_t(ptr)), dest, Assembler::Always, rs, ins);
MacroAssemblerARM::ma_mov_patch(Imm32(int32_t(ptr)), dest, Assembler::Always, rs, ins);
// L_LDR won't cause any instructions to be updated.
if (rs != Assembler::L_LDR) {
AutoFlushICache::flush(uintptr_t(ins), 4);
@ -825,31 +826,30 @@ TraceOneDataRelocation(JSTracer *trc, Iter *iter, MacroAssemblerARM *masm)
}
static void
TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader,
MacroAssemblerARM *masm)
TraceDataRelocations(JSTracer *trc, uint8_t *buffer, CompactBufferReader &reader)
{
while (reader.more()) {
size_t offset = reader.readUnsigned();
InstructionIterator iter((Instruction*)(buffer + offset));
TraceOneDataRelocation(trc, &iter, masm);
TraceOneDataRelocation(trc, &iter);
}
}
static void
TraceDataRelocations(JSTracer *trc, ARMBuffer *buffer,
Vector<BufferOffset, 0, SystemAllocPolicy> *locs, MacroAssemblerARM *masm)
Vector<BufferOffset, 0, SystemAllocPolicy> *locs)
{
for (unsigned int idx = 0; idx < locs->length(); idx++) {
BufferOffset bo = (*locs)[idx];
ARMBuffer::AssemblerBufferInstIterator iter(bo, buffer);
TraceOneDataRelocation(trc, &iter, masm);
TraceOneDataRelocation(trc, &iter);
}
}
void
Assembler::TraceDataRelocations(JSTracer *trc, JitCode *code, CompactBufferReader &reader)
{
::TraceDataRelocations(trc, code->raw(), reader, static_cast<MacroAssemblerARM *>(Dummy));
::TraceDataRelocations(trc, code->raw(), reader);
}
void
@ -860,7 +860,6 @@ Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader
uint8_t *buffer = code->raw();
bool hasNurseryPointers = false;
MacroAssemblerARM *masm = static_cast<MacroAssemblerARM *>(Dummy);
while (reader.more()) {
size_t offset = reader.readUnsigned();
@ -877,7 +876,7 @@ Assembler::FixupNurseryObjects(JSContext *cx, JitCode *code, CompactBufferReader
uint32_t index = word >> 1;
JSObject *obj = nurseryObjects[index];
masm->ma_movPatchable(Imm32(int32_t(obj)), dest, Assembler::Always, rs, ins);
MacroAssembler::ma_mov_patch(Imm32(int32_t(obj)), dest, Assembler::Always, rs, ins);
if (rs != Assembler::L_LDR) {
// L_LDR won't cause any instructions to be updated.
@ -930,10 +929,8 @@ Assembler::trace(JSTracer *trc)
}
}
if (tmpDataRelocations_.length()) {
::TraceDataRelocations(trc, &m_buffer, &tmpDataRelocations_,
static_cast<MacroAssemblerARM *>(this));
}
if (tmpDataRelocations_.length())
::TraceDataRelocations(trc, &m_buffer, &tmpDataRelocations_);
}
void
@ -1390,14 +1387,11 @@ Assembler::bytesNeeded() const
// Write a blob of binary into the instruction stream.
BufferOffset
Assembler::writeInst(uint32_t x, uint32_t *dest)
Assembler::writeInst(uint32_t x)
{
if (dest == nullptr)
return m_buffer.putInt(x);
WriteInstStatic(x, dest);
return BufferOffset();
return m_buffer.putInt(x);
}
BufferOffset
Assembler::writeBranchInst(uint32_t x)
{
@ -1421,19 +1415,40 @@ Assembler::as_nop()
{
return writeInst(0xe320f000);
}
BufferOffset
Assembler::as_alu(Register dest, Register src1, Operand2 op2,
ALUOp op, SetCond_ sc, Condition c, Instruction *instdest)
static uint32_t
EncodeAlu(Register dest, Register src1, Operand2 op2, ALUOp op, SetCond_ sc,
Assembler::Condition c)
{
return writeInst((int)op | (int)sc | (int) c | op2.encode() |
((dest == InvalidReg) ? 0 : RD(dest)) |
((src1 == InvalidReg) ? 0 : RN(src1)), (uint32_t*)instdest);
return (int)op | (int)sc | (int) c | op2.encode() |
((dest == InvalidReg) ? 0 : RD(dest)) |
((src1 == InvalidReg) ? 0 : RN(src1));
}
BufferOffset
Assembler::as_mov(Register dest, Operand2 op2, SetCond_ sc, Condition c, Instruction *instdest)
Assembler::as_alu(Register dest, Register src1, Operand2 op2,
ALUOp op, SetCond_ sc, Condition c)
{
return as_alu(dest, InvalidReg, op2, OpMov, sc, c, instdest);
return writeInst(EncodeAlu(dest, src1, op2, op, sc, c));
}
BufferOffset
Assembler::as_mov(Register dest, Operand2 op2, SetCond_ sc, Condition c)
{
return as_alu(dest, InvalidReg, op2, OpMov, sc, c);
}
/* static */ void
Assembler::as_alu_patch(Register dest, Register src1, Operand2 op2, ALUOp op, SetCond_ sc,
Condition c, uint32_t *pos)
{
WriteInstStatic(EncodeAlu(dest, src1, op2, op, sc, c), pos);
}
/* static */ void
Assembler::as_mov_patch(Register dest, Operand2 op2, SetCond_ sc, Condition c, uint32_t *pos)
{
as_alu_patch(dest, InvalidReg, op2, OpMov, sc, c, pos);
}
BufferOffset
@ -1551,20 +1566,45 @@ Assembler::as_uxth(Register dest, Register src, int rotate, Condition c)
return writeInst((int)c | SignExtend | SxUxth | RN(NoAddend) | RD(dest) | ((rotate & 3) << 10) | src.code());
}
static uint32_t
EncodeMovW(Register dest, Imm16 imm, Assembler::Condition c)
{
MOZ_ASSERT(HasMOVWT());
return 0x03000000 | c | imm.encode() | RD(dest);
}
static uint32_t
EncodeMovT(Register dest, Imm16 imm, Assembler::Condition c)
{
MOZ_ASSERT(HasMOVWT());
return 0x03400000 | c | imm.encode() | RD(dest);
}
// Not quite ALU worthy, but these are useful none the less. These also have
// the isue of these being formatted completly differently from the standard ALU
// operations.
BufferOffset
Assembler::as_movw(Register dest, Imm16 imm, Condition c, Instruction *pos)
Assembler::as_movw(Register dest, Imm16 imm, Condition c)
{
MOZ_ASSERT(HasMOVWT());
return writeInst(0x03000000 | c | imm.encode() | RD(dest), (uint32_t*)pos);
return writeInst(EncodeMovW(dest, imm, c));
}
BufferOffset
Assembler::as_movt(Register dest, Imm16 imm, Condition c, Instruction *pos)
/* static */ void
Assembler::as_movw_patch(Register dest, Imm16 imm, Condition c, Instruction *pos)
{
MOZ_ASSERT(HasMOVWT());
return writeInst(0x03400000 | c | imm.encode() | RD(dest), (uint32_t*)pos);
WriteInstStatic(EncodeMovW(dest, imm, c), (uint32_t*)pos);
}
BufferOffset
Assembler::as_movt(Register dest, Imm16 imm, Condition c)
{
return writeInst(EncodeMovT(dest, imm, c));
}
/* static */ void
Assembler::as_movt_patch(Register dest, Imm16 imm, Condition c, Instruction *pos)
{
WriteInstStatic(EncodeMovT(dest, imm, c), (uint32_t*)pos);
}
static const int mull_tag = 0x90;
@ -1639,24 +1679,35 @@ Assembler::as_udiv(Register rd, Register rn, Register rm, Condition c)
}
BufferOffset
Assembler::as_clz(Register dest, Register src, Condition c, Instruction *instdest)
Assembler::as_clz(Register dest, Register src, Condition c)
{
return writeInst(RD(dest) | src.code() | c | 0x016f0f10, (uint32_t*)instdest);
return writeInst(RD(dest) | src.code() | c | 0x016f0f10);
}
// Data transfer instructions: ldr, str, ldrb, strb. Using an int to
// differentiate between 8 bits and 32 bits is overkill, but meh.
BufferOffset
Assembler::as_dtr(LoadStore ls, int size, Index mode,
Register rt, DTRAddr addr, Condition c, uint32_t *dest)
static uint32_t
EncodeDtr(LoadStore ls, int size, Index mode, Register rt, DTRAddr addr, Assembler::Condition c)
{
MOZ_ASSERT(mode == Offset || (rt != addr.getBase() && pc != addr.getBase()));
MOZ_ASSERT(size == 32 || size == 8);
return writeInst( 0x04000000 | ls | (size == 8 ? 0x00400000 : 0) | mode | c |
RT(rt) | addr.encode(), dest);
return 0x04000000 | ls | (size == 8 ? 0x00400000 : 0) | mode | c | RT(rt) | addr.encode();
}
BufferOffset
Assembler::as_dtr(LoadStore ls, int size, Index mode, Register rt, DTRAddr addr, Condition c)
{
return writeInst(EncodeDtr(ls, size, mode, rt, addr, c));
}
/* static */ void
Assembler::as_dtr_patch(LoadStore ls, int size, Index mode, Register rt, DTRAddr addr, Condition c,
uint32_t *dest)
{
WriteInstStatic(EncodeDtr(ls, size, mode, rt, addr, c), dest);
}
class PoolHintData {
public:
enum LoadType {
@ -1749,7 +1800,7 @@ union PoolHintPun {
// ldrd, etc. The size is given in bits.
BufferOffset
Assembler::as_extdtr(LoadStore ls, int size, bool IsSigned, Index mode,
Register rt, EDtrAddr addr, Condition c, uint32_t *dest)
Register rt, EDtrAddr addr, Condition c)
{
int extra_bits2 = 0;
int extra_bits1 = 0;
@ -1778,7 +1829,7 @@ Assembler::as_extdtr(LoadStore ls, int size, bool IsSigned, Index mode,
MOZ_CRASH("SAY WHAT?");
}
return writeInst(extra_bits2 << 5 | extra_bits1 << 20 | 0x90 |
addr.encode() | RT(rt) | mode | c, dest);
addr.encode() | RT(rt) | mode | c);
}
BufferOffset
@ -1797,8 +1848,8 @@ Assembler::as_Imm32Pool(Register dest, uint32_t value, Condition c)
return m_buffer.allocEntry(1, 1, (uint8_t*)&php.raw, (uint8_t*)&value);
}
void
Assembler::as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data)
/* static */ void
Assembler::WritePoolEntry(Instruction *addr, Condition c, uint32_t data)
{
MOZ_ASSERT(addr->is<InstLDR>());
int32_t offset = addr->encode() & 0xfff;
@ -1865,8 +1916,8 @@ Assembler::InsertIndexIntoTag(uint8_t *load_, uint32_t index)
// patchConstantPoolLoad takes the address of the instruction that wants to be
// patched, and the address of the start of the constant pool, and figures
// things out from there.
bool
Assembler::PatchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
void
Assembler::PatchConstantPoolLoad(void *loadAddr, void *constPoolAddr)
{
PoolHintData data = *(PoolHintData*)loadAddr;
uint32_t *instAddr = (uint32_t*) loadAddr;
@ -1875,8 +1926,9 @@ Assembler::PatchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
case PoolHintData::PoolBOGUS:
MOZ_CRASH("bogus load type!");
case PoolHintData::PoolDTR:
Dummy->as_dtr(IsLoad, 32, Offset, data.getReg(),
DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)), data.getCond(), instAddr);
Assembler::as_dtr_patch(IsLoad, 32, Offset, data.getReg(),
DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)),
data.getCond(), instAddr);
break;
case PoolHintData::PoolBranch:
// Either this used to be a poolBranch, and the label was already bound,
@ -1887,20 +1939,20 @@ Assembler::PatchConstantPoolLoad(void* loadAddr, void* constPoolAddr)
// get bound later, then we want to make sure this is a load from the
// pool entry (and the pool entry should be nullptr so it will crash).
if (data.isValidPoolHint()) {
Dummy->as_dtr(IsLoad, 32, Offset, pc,
DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)),
data.getCond(), instAddr);
Assembler::as_dtr_patch(IsLoad, 32, Offset, pc,
DTRAddr(pc, DtrOffImm(offset+4*data.getIndex() - 8)),
data.getCond(), instAddr);
}
break;
case PoolHintData::PoolVDTR: {
VFPRegister dest = data.getVFPReg();
int32_t imm = offset + (data.getIndex() * 4) - 8;
MOZ_ASSERT(-1024 < imm && imm < 1024);
Dummy->as_vdtr(IsLoad, dest, VFPAddr(pc, VFPOffImm(imm)), data.getCond(), instAddr);
Assembler::as_vdtr_patch(IsLoad, dest, VFPAddr(pc, VFPOffImm(imm)), data.getCond(),
instAddr);
break;
}
}
return true;
}
// Atomic instruction stuff:
@ -2136,11 +2188,19 @@ enum vfp_tags {
VfpArith = 0x02000000
};
BufferOffset
Assembler::writeVFPInst(vfp_size sz, uint32_t blob, uint32_t *dest)
Assembler::writeVFPInst(vfp_size sz, uint32_t blob)
{
MOZ_ASSERT((sz & blob) == 0);
MOZ_ASSERT((VfpTag & blob) == 0);
return writeInst(VfpTag | sz | blob, dest);
return writeInst(VfpTag | sz | blob);
}
/* static */ void
Assembler::WriteVFPInstStatic(vfp_size sz, uint32_t blob, uint32_t *dest)
{
MOZ_ASSERT((sz & blob) == 0);
MOZ_ASSERT((VfpTag & blob) == 0);
WriteInstStatic(VfpTag | sz | blob, dest);
}
// Unityped variants: all registers hold the same (ieee754 single/double)
@ -2345,13 +2405,25 @@ Assembler::as_vcvtFixed(VFPRegister vd, bool isSigned, uint32_t fixedPoint, bool
}
// Transfer between VFP and memory.
static uint32_t
EncodeVdtr(LoadStore ls, VFPRegister vd, VFPAddr addr, Assembler::Condition c)
{
return ls | 0x01000000 | addr.encode() | VD(vd) | c;
}
BufferOffset
Assembler::as_vdtr(LoadStore ls, VFPRegister vd, VFPAddr addr,
Condition c /* vfp doesn't have a wb option */,
uint32_t *dest)
Condition c /* vfp doesn't have a wb option */)
{
vfp_size sz = vd.isDouble() ? IsDouble : IsSingle;
return writeVFPInst(sz, ls | 0x01000000 | addr.encode() | VD(vd) | c, dest);
return writeVFPInst(sz, EncodeVdtr(ls, vd, addr, c));
}
/* static */ void
Assembler::as_vdtr_patch(LoadStore ls, VFPRegister vd, VFPAddr addr, Condition c, uint32_t *dest)
{
vfp_size sz = vd.isDouble() ? IsDouble : IsSingle;
WriteVFPInstStatic(sz, EncodeVdtr(ls, vd, addr, c), dest);
}
// VFP's ldm/stm work differently from the standard arm ones. You can only
@ -2685,8 +2757,9 @@ Assembler::PatchDataWithValueCheck(CodeLocationLabel label, PatchedImmPtr newVal
Assembler::RelocStyle rs;
DebugOnly<const uint32_t *> val = GetPtr32Target(&iter, &dest, &rs);
MOZ_ASSERT((uint32_t)(const uint32_t *)val == uint32_t(expectedValue.value));
reinterpret_cast<MacroAssemblerARM*>(Dummy)->ma_movPatchable(Imm32(int32_t(newValue.value)),
dest, Always, rs, ptr);
MacroAssembler::ma_mov_patch(Imm32(int32_t(newValue.value)), dest, Always, rs, ptr);
// L_LDR won't cause any instructions to be updated.
if (rs != L_LDR) {
AutoFlushICache::flush(uintptr_t(ptr), 4);
@ -2954,7 +3027,6 @@ InstructionIterator::InstructionIterator(Instruction *i_) : i(i_)
i = i->skipPool();
}
Assembler *Assembler::Dummy = nullptr;
uint32_t Assembler::NopFill = 0;
uint32_t

View File

@ -1201,18 +1201,7 @@ class Assembler : public AssemblerShared
ARMBuffer m_buffer;
// There is now a semi-unified interface for instruction generation. During
// assembly, there is an active buffer that instructions are being written
// into, but later, we may wish to modify instructions that have already
// been created. In order to do this, we call the same assembly function,
// but pass it a destination address, which will be overwritten with a new
// instruction. In order to do this very after assembly buffers no longer
// exist, when calling with a third dest parameter, a this object is still
// needed. Dummy always happens to be null, but we shouldn't be looking at
// it in any case.
public:
static Assembler *Dummy;
// For the alignment fill use NOP: 0x0320f000 or (Always | InstNOP::NopInst).
// For the nopFill use a branch to the next instruction: 0xeaffffff.
Assembler()
@ -1303,17 +1292,14 @@ class Assembler : public AssemblerShared
size_t bytesNeeded() const;
// Write a blob of binary into the instruction stream *OR* into a
// destination address. If dest is nullptr (the default), then the
// instruction gets written into the instruction stream. If dest is not null
// it is interpreted as a pointer to the location that we want the
// instruction to be written.
BufferOffset writeInst(uint32_t x, uint32_t *dest = nullptr);
// destination address.
BufferOffset writeInst(uint32_t x);
// As above, but also mark the instruction as a branch.
BufferOffset writeBranchInst(uint32_t x);
// A static variant for the cases where we don't want to have an assembler
// object at all. Normally, you would use the dummy (nullptr) object.
// object.
static void WriteInstStatic(uint32_t x, uint32_t *dest);
public:
@ -1322,12 +1308,17 @@ class Assembler : public AssemblerShared
void align(int alignment);
BufferOffset as_nop();
BufferOffset as_alu(Register dest, Register src1, Operand2 op2,
ALUOp op, SetCond_ sc = NoSetCond, Condition c = Always, Instruction *instdest = nullptr);
ALUOp op, SetCond_ sc = NoSetCond, Condition c = Always);
BufferOffset as_mov(Register dest,
Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always, Instruction *instdest = nullptr);
Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
BufferOffset as_mvn(Register dest, Operand2 op2,
SetCond_ sc = NoSetCond, Condition c = Always);
SetCond_ sc = NoSetCond, Condition c = Always);
static void as_alu_patch(Register dest, Register src1, Operand2 op2,
ALUOp op, SetCond_ sc, Condition c, uint32_t *pos);
static void as_mov_patch(Register dest,
Operand2 op2, SetCond_ sc, Condition c, uint32_t *pos);
// Logical operations:
BufferOffset as_and(Register dest, Register src1,
Operand2 op2, SetCond_ sc = NoSetCond, Condition c = Always);
@ -1368,8 +1359,11 @@ class Assembler : public AssemblerShared
// Not quite ALU worthy, but useful none the less: These also have the issue
// of these being formatted completly differently from the standard ALU
// operations.
BufferOffset as_movw(Register dest, Imm16 imm, Condition c = Always, Instruction *pos = nullptr);
BufferOffset as_movt(Register dest, Imm16 imm, Condition c = Always, Instruction *pos = nullptr);
BufferOffset as_movw(Register dest, Imm16 imm, Condition c = Always);
BufferOffset as_movt(Register dest, Imm16 imm, Condition c = Always);
static void as_movw_patch(Register dest, Imm16 imm, Condition c, Instruction *pos);
static void as_movt_patch(Register dest, Imm16 imm, Condition c, Instruction *pos);
BufferOffset as_genmul(Register d1, Register d2, Register rm, Register rn,
MULOp op, SetCond_ sc, Condition c = Always);
@ -1392,21 +1386,27 @@ class Assembler : public AssemblerShared
BufferOffset as_sdiv(Register dest, Register num, Register div, Condition c = Always);
BufferOffset as_udiv(Register dest, Register num, Register div, Condition c = Always);
BufferOffset as_clz(Register dest, Register src, Condition c = Always, Instruction *instdest = nullptr);
BufferOffset as_clz(Register dest, Register src, Condition c = Always);
// Data transfer instructions: ldr, str, ldrb, strb.
// Using an int to differentiate between 8 bits and 32 bits is overkill.
BufferOffset as_dtr(LoadStore ls, int size, Index mode,
Register rt, DTRAddr addr, Condition c = Always, uint32_t *dest = nullptr);
Register rt, DTRAddr addr, Condition c = Always);
static void as_dtr_patch(LoadStore ls, int size, Index mode,
Register rt, DTRAddr addr, Condition c, uint32_t *dest);
// Handles all of the other integral data transferring functions:
// ldrsb, ldrsh, ldrd, etc. The size is given in bits.
BufferOffset as_extdtr(LoadStore ls, int size, bool IsSigned, Index mode,
Register rt, EDtrAddr addr, Condition c = Always, uint32_t *dest = nullptr);
Register rt, EDtrAddr addr, Condition c = Always);
BufferOffset as_dtm(LoadStore ls, Register rn, uint32_t mask,
DTMMode mode, DTMWriteBack wb, Condition c = Always);
// Overwrite a pool entry with new data.
void as_WritePoolEntry(Instruction *addr, Condition c, uint32_t data);
static void WritePoolEntry(Instruction *addr, Condition c, uint32_t data);
// Load a 32 bit immediate from a pool into a register.
BufferOffset as_Imm32Pool(Register dest, uint32_t value, Condition c = Always);
// Make a patchable jump that can target the entire 32 bit address space.
@ -1485,11 +1485,14 @@ class Assembler : public AssemblerShared
IsSingle = 0 << 8
};
BufferOffset writeVFPInst(vfp_size sz, uint32_t blob, uint32_t *dest=nullptr);
BufferOffset writeVFPInst(vfp_size sz, uint32_t blob);
static void WriteVFPInstStatic(vfp_size sz, uint32_t blob, uint32_t *dest);
// Unityped variants: all registers hold the same (ieee754 single/double)
// notably not included are vcvt; vmov vd, #imm; vmov rt, vn.
BufferOffset as_vfp_float(VFPRegister vd, VFPRegister vn, VFPRegister vm,
VFPOp op, Condition c = Always);
VFPOp op, Condition c = Always);
public:
BufferOffset as_vadd(VFPRegister vd, VFPRegister vn, VFPRegister vm,
@ -1556,8 +1559,10 @@ class Assembler : public AssemblerShared
// Transfer between VFP and memory.
BufferOffset as_vdtr(LoadStore ls, VFPRegister vd, VFPAddr addr,
Condition c = Always /* vfp doesn't have a wb option*/,
uint32_t *dest = nullptr);
Condition c = Always /* vfp doesn't have a wb option*/);
static void as_vdtr_patch(LoadStore ls, VFPRegister vd, VFPAddr addr,
Condition c /* vfp doesn't have a wb option*/, uint32_t *dest);
// VFP's ldm/stm work differently from the standard arm ones. You can only
// transfer a range.
@ -1742,10 +1747,11 @@ class Assembler : public AssemblerShared
// API for speaking with the IonAssemblerBufferWithConstantPools generate an
// initial placeholder instruction that we want to later fix up.
static void InsertIndexIntoTag(uint8_t *load, uint32_t index);
// Take the stub value that was written in before, and write in an actual
// load using the index we'd computed previously as well as the address of
// the pool start.
static bool PatchConstantPoolLoad(void* loadAddr, void* constPoolAddr);
static void PatchConstantPoolLoad(void *loadAddr, void *constPoolAddr);
// END API
// Move our entire pool into the instruction stream. This is to force an

View File

@ -404,52 +404,61 @@ MacroAssemblerARM::ma_nop()
as_nop();
}
Instruction *
NextInst(Instruction *i)
{
if (i == nullptr)
return nullptr;
return i->next();
}
void
MacroAssemblerARM::ma_movPatchable(Imm32 imm_, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i)
RelocStyle rs)
{
int32_t imm = imm_.value;
if (i) {
// Make sure the current instruction is not an artificial guard inserted
// by the assembler buffer.
i = i->skipPool();
}
switch(rs) {
case L_MOVWT:
as_movw(dest, Imm16(imm & 0xffff), c, i);
// 'i' can be nullptr here. That just means "insert in the next in
// sequence." NextInst is special cased to not do anything when it is
// passed nullptr, so two consecutive instructions will be inserted.
i = NextInst(i);
as_movt(dest, Imm16(imm >> 16 & 0xffff), c, i);
as_movw(dest, Imm16(imm & 0xffff), c);
as_movt(dest, Imm16(imm >> 16 & 0xffff), c);
break;
case L_LDR:
if(i == nullptr)
as_Imm32Pool(dest, imm, c);
else
as_WritePoolEntry(i, c, imm);
as_Imm32Pool(dest, imm, c);
break;
}
}
void
MacroAssemblerARM::ma_movPatchable(ImmPtr imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i)
RelocStyle rs)
{
return ma_movPatchable(Imm32(int32_t(imm.value)), dest, c, rs, i);
ma_movPatchable(Imm32(int32_t(imm.value)), dest, c, rs);
}
/* static */ void
MacroAssemblerARM::ma_mov_patch(Imm32 imm_, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i)
{
MOZ_ASSERT(i);
int32_t imm = imm_.value;
// Make sure the current instruction is not an artificial guard inserted
// by the assembler buffer.
i = i->skipPool();
switch(rs) {
case L_MOVWT:
Assembler::as_movw_patch(dest, Imm16(imm & 0xffff), c, i);
i = i->next();
Assembler::as_movt_patch(dest, Imm16(imm >> 16 & 0xffff), c, i);
break;
case L_LDR:
Assembler::WritePoolEntry(i, c, imm);
break;
}
}
/* static */ void
MacroAssemblerARM::ma_mov_patch(ImmPtr imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i)
{
ma_mov_patch(Imm32(int32_t(imm.value)), dest, c, rs, i);
}
void
MacroAssemblerARM::ma_mov(Register src, Register dest,
SetCond_ sc, Assembler::Condition c)
MacroAssemblerARM::ma_mov(Register src, Register dest, SetCond_ sc, Assembler::Condition c)
{
if (sc == SetCond || dest != src)
as_mov(dest, O2Reg(src), sc, c);

View File

@ -108,10 +108,16 @@ class MacroAssemblerARM : public Assembler
void ma_alu(Register src1, Operand op2, Register dest, ALUOp op,
SetCond_ sc = NoSetCond, Condition c = Always);
void ma_nop();
void ma_movPatchable(Imm32 imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i = nullptr);
RelocStyle rs);
void ma_movPatchable(ImmPtr imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i = nullptr);
RelocStyle rs);
static void ma_mov_patch(Imm32 imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i);
static void ma_mov_patch(ImmPtr imm, Register dest, Assembler::Condition c,
RelocStyle rs, Instruction *i);
// These should likely be wrapped up as a set of macros or something like
// that. I cannot think of a good reason to explicitly have all of this