Bug 1415931 - [MIPS] Make long jumps visible to Wasm module code linking and caching. r=bbouvier

--HG--
extra : rebase_source : 30f424703d9420a149db98a21befb805bde33806
This commit is contained in:
Dragan Mladjenovic 2017-11-13 15:26:09 -05:00
Родитель 00ee6fdea3
Коммит f17743cf65
5 изменённых файлов: 55 добавлений и 88 удалений

Просмотреть файл

@ -877,7 +877,6 @@ class AssemblerMIPSShared : public AssemblerShared
};
js::Vector<RelativePatch, 8, SystemAllocPolicy> jumps_;
js::Vector<uint32_t, 8, SystemAllocPolicy> longJumps_;
CompactBufferWriter jumpRelocations_;
CompactBufferWriter dataRelocations_;
@ -1280,18 +1279,13 @@ class AssemblerMIPSShared : public AssemblerShared
writeRelocation(src);
}
void addLongJump(BufferOffset src) {
enoughMemory_ &= longJumps_.append(src.getOffset());
void addLongJump(BufferOffset src, BufferOffset dst) {
CodeOffset patchAt(src.getOffset());
CodeOffset target(dst.getOffset());
addCodeLabel(CodeLabel(patchAt, target));
}
public:
size_t numLongJumps() const {
return longJumps_.length();
}
uint32_t longJump(size_t i) {
return longJumps_[i];
}
void flushBuffer() {
}

Просмотреть файл

@ -163,14 +163,6 @@ Assembler::executableCopy(uint8_t* buffer, bool flushICache)
MOZ_ASSERT(isFinished);
m_buffer.executableCopy(buffer);
// Patch all long jumps during code copy.
for (size_t i = 0; i < longJumps_.length(); i++) {
Instruction* inst1 = (Instruction*) ((uint32_t)buffer + longJumps_[i]);
uint32_t value = Assembler::ExtractLuiOriValue(inst1, inst1->next());
AssemblerMIPSShared::UpdateLuiOriValue(inst1, inst1->next(), (uint32_t)buffer + value);
}
if (flushICache)
AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
}
@ -329,8 +321,9 @@ Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
// Generate the long jump for calls because return address has to be the
// address after the reserved block.
if (inst[0].encode() == inst_bgezal.encode()) {
addLongJump(BufferOffset(branch));
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
addLongJump(BufferOffset(branch), BufferOffset(target));
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister,
LabelBase::INVALID_OFFSET);
inst[2] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
// There is 1 nop after this.
return;
@ -353,16 +346,18 @@ Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
if (inst[0].encode() == inst_beq.encode()) {
// Handle long unconditional jump.
addLongJump(BufferOffset(branch));
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, target);
addLongJump(BufferOffset(branch), BufferOffset(target));
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister,
LabelBase::INVALID_OFFSET);
inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
} else {
// Handle long conditional jump.
inst[0] = invertBranch(inst[0], BOffImm16(5 * sizeof(void*)));
// No need for a "nop" here because we can clobber scratch.
addLongJump(BufferOffset(branch + sizeof(void*)));
Assembler::WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, target);
addLongJump(BufferOffset(branch + sizeof(void*)), BufferOffset(target));
Assembler::WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister,
LabelBase::INVALID_OFFSET);
inst[3] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
}
@ -386,7 +381,7 @@ Assembler::bind(RepatchLabel* label)
// For unconditional long branches generated by ma_liPatchable,
// such as under:
// jumpWithpatch
AssemblerMIPSShared::UpdateLuiOriValue(inst, inst->next(), dest.getOffset());
addLongJump(BufferOffset(label->offset()), dest);
} else if (inst[1].extractOpcode() == (uint32_t(op_lui) >> OpcodeShift) ||
BOffImm16::IsInRange(offset))
{
@ -407,8 +402,9 @@ Assembler::bind(RepatchLabel* label)
MOZ_ASSERT(inst[1].encode() == NopInst);
MOZ_ASSERT(inst[2].encode() == NopInst);
MOZ_ASSERT(inst[3].encode() == NopInst);
addLongJump(BufferOffset(label->offset()));
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister, dest.getOffset());
addLongJump(BufferOffset(label->offset()), dest);
Assembler::WriteLuiOriInstructions(inst, &inst[1], ScratchRegister,
LabelBase::INVALID_OFFSET);
inst[2] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
} else {
// Handle open long conditional jumps created by
@ -421,8 +417,9 @@ Assembler::bind(RepatchLabel* label)
MOZ_ASSERT(inst[2].encode() == NopInst);
MOZ_ASSERT(inst[3].encode() == NopInst);
MOZ_ASSERT(inst[4].encode() == NopInst);
addLongJump(BufferOffset(label->offset() + sizeof(void*)));
Assembler::WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister, dest.getOffset());
addLongJump(BufferOffset(label->offset() + sizeof(void*)), dest);
Assembler::WriteLuiOriInstructions(&inst[1], &inst[2], ScratchRegister,
LabelBase::INVALID_OFFSET);
inst[3] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
}
}

Просмотреть файл

@ -510,8 +510,8 @@ MacroAssemblerMIPS::ma_bal(Label* label, DelaySlotFill delaySlotFill)
if (label->bound()) {
// Generate the long jump for calls because return address has to be
// the address after the reserved block.
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, Imm32(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
as_jalr(ScratchRegister);
if (delaySlotFill == FillDelaySlot)
as_nop();
@ -561,8 +561,8 @@ MacroAssemblerMIPS::branchWithCode(InstImm code, Label* label, JumpKind jumpKind
if (code.encode() == inst_beq.encode()) {
// Handle long jump
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, Imm32(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return;
@ -577,8 +577,8 @@ MacroAssemblerMIPS::branchWithCode(InstImm code, Label* label, JumpKind jumpKind
writeInst(code_r.encode());
// No need for a "nop" here because we can clobber scratch.
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, Imm32(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return;
@ -1549,26 +1549,20 @@ MacroAssemblerMIPSCompat::backedgeJump(RepatchLabel* label, Label* documentation
{
// Only one branch per label.
MOZ_ASSERT(!label->used());
uint32_t dest = label->bound() ? label->offset() : LabelBase::INVALID_OFFSET;
BufferOffset bo = nextOffset();
label->use(bo.getOffset());
// Backedges are short jumps when bound, but can become long when patched.
m_buffer.ensureSpace(8 * sizeof(uint32_t));
if (label->bound()) {
int32_t offset = label->offset() - bo.getOffset();
MOZ_ASSERT(BOffImm16::IsInRange(offset));
as_b(BOffImm16(offset));
} else {
// Jump to "label1" by default to jump to the loop header.
as_b(BOffImm16(2 * sizeof(uint32_t)));
}
// Jump to "label1" by default to jump to the loop header.
as_b(BOffImm16(2 * sizeof(uint32_t)));
// No need for nop here. We can safely put next instruction in delay slot.
ma_liPatchable(ScratchRegister, Imm32(dest));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
MOZ_ASSERT(nextOffset().getOffset() - bo.getOffset() == 3 * sizeof(uint32_t));
as_jr(ScratchRegister);
// No need for nop here. We can safely put next instruction in delay slot.
ma_liPatchable(ScratchRegister, Imm32(dest));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
MOZ_ASSERT(nextOffset().getOffset() - bo.getOffset() == 8 * sizeof(uint32_t));
@ -1580,12 +1574,10 @@ MacroAssemblerMIPSCompat::jumpWithPatch(RepatchLabel* label, Label* documentatio
{
// Only one branch per label.
MOZ_ASSERT(!label->used());
uint32_t dest = label->bound() ? label->offset() : LabelBase::INVALID_OFFSET;
BufferOffset bo = nextOffset();
label->use(bo.getOffset());
addLongJump(bo);
ma_liPatchable(ScratchRegister, Imm32(dest));
ma_liPatchable(ScratchRegister, Imm32(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return CodeOffsetJump(bo.getOffset());

Просмотреть файл

@ -131,14 +131,6 @@ Assembler::executableCopy(uint8_t* buffer, bool flushICache)
MOZ_ASSERT(isFinished);
m_buffer.executableCopy(buffer);
// Patch all long jumps during code copy.
for (size_t i = 0; i < longJumps_.length(); i++) {
Instruction* inst = (Instruction*) ((uintptr_t)buffer + longJumps_[i]);
uint64_t value = Assembler::ExtractLoad64Value(inst);
Assembler::UpdateLoad64Value(inst, (uint64_t)buffer + value);
}
if (flushICache)
AutoFlushICache::setRange(uintptr_t(buffer), m_buffer.size());
}
@ -262,8 +254,8 @@ Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
// Generate the long jump for calls because return address has to be the
// address after the reserved block.
if (inst[0].encode() == inst_bgezal.encode()) {
addLongJump(BufferOffset(branch));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
addLongJump(BufferOffset(branch), BufferOffset(target));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, LabelBase::INVALID_OFFSET);
inst[4] = InstReg(op_special, ScratchRegister, zero, ra, ff_jalr).encode();
// There is 1 nop after this.
return;
@ -287,16 +279,16 @@ Assembler::bind(InstImm* inst, uintptr_t branch, uintptr_t target)
if (inst[0].encode() == inst_beq.encode()) {
// Handle long unconditional jump.
addLongJump(BufferOffset(branch));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, target);
addLongJump(BufferOffset(branch), BufferOffset(target));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, LabelBase::INVALID_OFFSET);
inst[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
} else {
// Handle long conditional jump.
inst[0] = invertBranch(inst[0], BOffImm16(7 * sizeof(uint32_t)));
// No need for a "nop" here because we can clobber scratch.
addLongJump(BufferOffset(branch + sizeof(uint32_t)));
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, target);
addLongJump(BufferOffset(branch + sizeof(uint32_t)), BufferOffset(target));
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, LabelBase::INVALID_OFFSET);
inst[5] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
// There is 1 nop after this.
}
@ -320,7 +312,7 @@ Assembler::bind(RepatchLabel* label)
// For unconditional long branches generated by ma_liPatchable,
// such as under:
// jumpWithpatch
Assembler::UpdateLoad64Value(inst, dest.getOffset());
addLongJump(BufferOffset(label->offset()), dest);
} else if (inst[1].extractOpcode() == (uint32_t(op_lui) >> OpcodeShift) ||
BOffImm16::IsInRange(offset))
{
@ -343,8 +335,8 @@ Assembler::bind(RepatchLabel* label)
MOZ_ASSERT(inst[3].encode() == NopInst);
MOZ_ASSERT(inst[4].encode() == NopInst);
MOZ_ASSERT(inst[5].encode() == NopInst);
addLongJump(BufferOffset(label->offset()));
Assembler::WriteLoad64Instructions(inst, ScratchRegister, dest.getOffset());
addLongJump(BufferOffset(label->offset()), dest);
Assembler::WriteLoad64Instructions(inst, ScratchRegister, LabelBase::INVALID_OFFSET);
inst[4] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
} else {
// Handle open long conditional jumps created by
@ -359,8 +351,8 @@ Assembler::bind(RepatchLabel* label)
MOZ_ASSERT(inst[4].encode() == NopInst);
MOZ_ASSERT(inst[5].encode() == NopInst);
MOZ_ASSERT(inst[6].encode() == NopInst);
addLongJump(BufferOffset(label->offset() + sizeof(uint32_t)));
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, dest.getOffset());
addLongJump(BufferOffset(label->offset() + sizeof(uint32_t)), dest);
Assembler::WriteLoad64Instructions(&inst[1], ScratchRegister, LabelBase::INVALID_OFFSET);
inst[5] = InstReg(op_special, ScratchRegister, zero, zero, ff_jr).encode();
}
}

Просмотреть файл

@ -763,8 +763,8 @@ MacroAssemblerMIPS64::ma_bal(Label* label, DelaySlotFill delaySlotFill)
if (label->bound()) {
// Generate the long jump for calls because return address has to be
// the address after the reserved block.
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, ImmWord(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
as_jalr(ScratchRegister);
if (delaySlotFill == FillDelaySlot)
as_nop();
@ -819,8 +819,8 @@ MacroAssemblerMIPS64::branchWithCode(InstImm code, Label* label, JumpKind jumpKi
if (code.encode() == inst_beq.encode()) {
// Handle long jump
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, ImmWord(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return;
@ -835,8 +835,8 @@ MacroAssemblerMIPS64::branchWithCode(InstImm code, Label* label, JumpKind jumpKi
#endif
writeInst(code_r.encode());
// No need for a "nop" here because we can clobber scratch.
addLongJump(nextOffset());
ma_liPatchable(ScratchRegister, ImmWord(label->offset()));
addLongJump(nextOffset(), BufferOffset(label->offset()));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return;
@ -1795,26 +1795,20 @@ MacroAssemblerMIPS64Compat::backedgeJump(RepatchLabel* label, Label* documentati
{
// Only one branch per label.
MOZ_ASSERT(!label->used());
uint32_t dest = label->bound() ? label->offset() : LabelBase::INVALID_OFFSET;
BufferOffset bo = nextOffset();
label->use(bo.getOffset());
// Backedges are short jumps when bound, but can become long when patched.
m_buffer.ensureSpace(16 * sizeof(uint32_t));
if (label->bound()) {
int32_t offset = label->offset() - bo.getOffset();
MOZ_ASSERT(BOffImm16::IsInRange(offset));
as_b(BOffImm16(offset));
} else {
// Jump to "label1" by default to jump to the loop header.
as_b(BOffImm16(2 * sizeof(uint32_t)));
}
// Jump to "label1" by default to jump to the loop header.
as_b(BOffImm16(2 * sizeof(uint32_t)));
// No need for nop here. We can safely put next instruction in delay slot.
ma_liPatchable(ScratchRegister, ImmWord(dest));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
MOZ_ASSERT(nextOffset().getOffset() - bo.getOffset() == 5 * sizeof(uint32_t));
as_jr(ScratchRegister);
// No need for nop here. We can safely put next instruction in delay slot.
ma_liPatchable(ScratchRegister, ImmWord(dest));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
MOZ_ASSERT(nextOffset().getOffset() - bo.getOffset() == 12 * sizeof(uint32_t));
@ -1826,12 +1820,10 @@ MacroAssemblerMIPS64Compat::jumpWithPatch(RepatchLabel* label, Label* documentat
{
// Only one branch per label.
MOZ_ASSERT(!label->used());
uint32_t dest = label->bound() ? label->offset() : LabelBase::INVALID_OFFSET;
BufferOffset bo = nextOffset();
label->use(bo.getOffset());
addLongJump(bo);
ma_liPatchable(ScratchRegister, ImmWord(dest));
ma_liPatchable(ScratchRegister, ImmWord(LabelBase::INVALID_OFFSET));
as_jr(ScratchRegister);
as_nop();
return CodeOffsetJump(bo.getOffset());