Bug 1271010 - Baldr: refactor nop-jump patching code (r=bbouvier)

MozReview-Commit-ID: 92hS8F1U9vO

--HG--
extra : rebase_source : b48ddbbd799a24ecd13fabfb4ec316e64ac2cfa7
This commit is contained in:
Luke Wagner 2016-05-28 16:51:07 -05:00
Родитель 79a52254e6
Коммит cee42a48aa
8 изменённых файлов: 123 добавлений и 53 удалений

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

@ -334,18 +334,7 @@ wasm::GenerateFunctionEpilogue(MacroAssembler& masm, unsigned framePushed, FuncO
// the nop since we need the location of the actual nop to patch it.
AutoForbidPools afp(&masm, 1);
#endif
// The exact form of this instruction must be kept consistent with the
// patching in Module::setProfilingEnabled.
offsets->profilingJump = masm.currentOffset();
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
masm.twoByteNop();
#elif defined(JS_CODEGEN_ARM)
masm.nop();
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
masm.nop();
masm.nop();
#endif
offsets->profilingJump = masm.nopPatchableToNearJump().offset();
}
// Normal epilogue:
@ -769,47 +758,11 @@ wasm::EnableProfilingEpilogue(const Module& module, const CodeRange& codeRange,
if (!codeRange.isFunction())
return;
uint8_t* jump = module.code() + codeRange.funcProfilingJump();
uint8_t* profilingJump = module.code() + codeRange.funcProfilingJump();
uint8_t* profilingEpilogue = module.code() + codeRange.funcProfilingEpilogue();
#if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64)
// An unconditional jump with a 1 byte offset immediate has the opcode
// 0x90. The offset is relative to the address of the instruction after
// the jump. 0x66 0x90 is the canonical two-byte nop.
ptrdiff_t jumpImmediate = profilingEpilogue - jump - 2;
MOZ_ASSERT(jumpImmediate > 0 && jumpImmediate <= 127);
if (enabled) {
MOZ_ASSERT(jump[0] == 0x66);
MOZ_ASSERT(jump[1] == 0x90);
jump[0] = 0xeb;
jump[1] = jumpImmediate;
} else {
MOZ_ASSERT(jump[0] == 0xeb);
MOZ_ASSERT(jump[1] == jumpImmediate);
jump[0] = 0x66;
jump[1] = 0x90;
}
#elif defined(JS_CODEGEN_ARM)
if (enabled) {
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
new (jump) InstBImm(BOffImm(profilingEpilogue - jump), Assembler::Always);
} else {
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
new (jump) InstNOP();
}
#elif defined(JS_CODEGEN_ARM64)
(void)jump;
(void)profilingEpilogue;
MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
InstImm* instr = (InstImm*)jump;
if (enabled)
instr->setBOffImm16(BOffImm16(profilingEpilogue - jump));
MacroAssembler::patchNopToNearJump(profilingJump, profilingEpilogue);
else
instr->makeNop();
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();
#else
# error "Missing architecture"
#endif
MacroAssembler::patchNearJumpToNop(profilingJump);
}

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

@ -493,6 +493,12 @@ class MacroAssembler : public MacroAssemblerSpecific
void patchThunk(uint32_t thunkOffset, uint32_t targetOffset) PER_SHARED_ARCH;
static void repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targetOffset) PER_SHARED_ARCH;
// Emit a nop that can be patched to and from a nop and a jump with an int8
// relative displacement.
CodeOffset nopPatchableToNearJump() PER_SHARED_ARCH;
static void patchNopToNearJump(uint8_t* jump, uint8_t* target) PER_SHARED_ARCH;
static void patchNearJumpToNop(uint8_t* jump) PER_SHARED_ARCH;
// Push the return address and make a call. On platforms where this function
// is not defined, push the link register (pushReturnAddress) at the entry
// point of the callee.

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

@ -4834,6 +4834,28 @@ MacroAssembler::repatchThunk(uint8_t* code, uint32_t u32Offset, uint32_t targetO
*u32 = (targetOffset - addOffset) - 8;
}
CodeOffset
MacroAssembler::nopPatchableToNearJump()
{
CodeOffset offset(currentOffset());
ma_nop();
return offset;
}
void
MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
{
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstNOP>());
new (jump) InstBImm(BOffImm(target - jump), Assembler::Always);
}
void
MacroAssembler::patchNearJumpToNop(uint8_t* jump)
{
MOZ_ASSERT(reinterpret_cast<Instruction*>(jump)->is<InstBImm>());
new (jump) InstNOP();
}
void
MacroAssembler::pushReturnAddress()
{

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

@ -557,6 +557,24 @@ MacroAssembler::repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targe
MOZ_CRASH("NYI");
}
CodeOffset
MacroAssembler::nopPatchableToNearJump()
{
MOZ_CRASH("NYI");
}
void
MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
{
MOZ_CRASH("NYI");
}
void
MacroAssembler::patchNearJumpToNop(uint8_t* jump)
{
MOZ_CRASH("NYI");
}
void
MacroAssembler::pushReturnAddress()
{

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

@ -1235,6 +1235,27 @@ MacroAssembler::repatchThunk(uint8_t* code, uint32_t u32Offset, uint32_t targetO
*u32 = targetOffset - u32Offset;
}
CodeOffset
MacroAssembler::nopPatchableToNearJump()
{
CodeOffset offset(currentOffset());
masm.nop();
masm.nop();
return offset;
}
void
MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
{
((InstImm*)jump)->setBOffImm16(BOffImm16(target - jump));
}
void
MacroAssembler::patchNearJumpToNop(uint8_t* jump)
{
((InstImm*)jump)->makeNop();
}
void
MacroAssembler::call(wasm::SymbolicAddress target)
{

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

@ -911,7 +911,6 @@ class AssemblerX86Shared : public AssemblerShared
public:
void nop() { masm.nop(); }
void twoByteNop() { masm.twoByteNop(); }
void j(Condition cond, Label* label) { jSrc(cond, label); }
void jmp(Label* label) { jmpSrc(label); }
void j(Condition cond, RepatchLabel* label) { jSrc(cond, label); }
@ -1070,6 +1069,16 @@ class AssemblerX86Shared : public AssemblerShared
X86Encoding::SetRel32(code + thunkOffset, code + targetOffset);
}
CodeOffset twoByteNop() {
return CodeOffset(masm.twoByteNop().offset());
}
static void patchTwoByteNopToJump(uint8_t* jump, uint8_t* target) {
X86Encoding::BaseAssembler::patchTwoByteNopToJump(jump, target);
}
static void patchJumpToTwoByteNop(uint8_t* jump) {
X86Encoding::BaseAssembler::patchJumpToTwoByteNop(jump);
}
void breakpoint() {
masm.int3();
}

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

@ -75,11 +75,34 @@ public:
m_formatter.oneByteOp(OP_NOP);
}
void twoByteNop()
MOZ_MUST_USE JmpSrc
twoByteNop()
{
spew("nop (2 byte)");
JmpSrc r(m_formatter.size());
m_formatter.prefix(PRE_OPERAND_SIZE);
m_formatter.oneByteOp(OP_NOP);
return r;
}
static void patchTwoByteNopToJump(uint8_t* jump, uint8_t* target)
{
// Note: the offset is relative to the address of the instruction after
// the jump which is two bytes.
ptrdiff_t rel8 = target - jump - 2;
MOZ_RELEASE_ASSERT(rel8 >= INT8_MIN && rel8 <= INT8_MAX);
MOZ_RELEASE_ASSERT(jump[0] == PRE_OPERAND_SIZE);
MOZ_RELEASE_ASSERT(jump[1] == OP_NOP);
jump[0] = OP_JMP_rel8;
jump[1] = rel8;
}
static void patchJumpToTwoByteNop(uint8_t* jump)
{
// See twoByteNop.
MOZ_RELEASE_ASSERT(jump[0] == OP_JMP_rel8);
jump[0] = PRE_OPERAND_SIZE;
jump[1] = OP_NOP;
}
/*

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

@ -570,6 +570,24 @@ MacroAssembler::repatchThunk(uint8_t* code, uint32_t thunkOffset, uint32_t targe
Assembler::repatchThunk(code, thunkOffset, targetOffset);
}
CodeOffset
MacroAssembler::nopPatchableToNearJump()
{
return Assembler::twoByteNop();
}
void
MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target)
{
Assembler::patchTwoByteNopToJump(jump, target);
}
void
MacroAssembler::patchNearJumpToNop(uint8_t* jump)
{
Assembler::patchJumpToTwoByteNop(jump);
}
void
MacroAssembler::callAndPushReturnAddress(Register reg)
{