Clean up and document SRFlags
Make it part of abi-x64.h and explain what the flags mean.
Esse commit está contido em:
@@ -226,6 +226,51 @@ enum ServiceRequest {
|
||||
#undef REQ
|
||||
};
|
||||
|
||||
/*
|
||||
* Various flags that are passed to emitServiceReq. May be or'd
|
||||
* together.
|
||||
*/
|
||||
enum class SRFlags {
|
||||
None = 0,
|
||||
|
||||
/*
|
||||
* Indicates the service request should be aligned.
|
||||
*/
|
||||
Align = 1,
|
||||
|
||||
/*
|
||||
* Indicates the service request is not a one-time use stub, so it's
|
||||
* ineligable for service request reclamation.
|
||||
*
|
||||
* The service request also will not reuse an existing service
|
||||
* request---i.e. it will be emitted at the current astubs frontier.
|
||||
*/
|
||||
Persistent = 2,
|
||||
|
||||
/*
|
||||
* For some service requests (returning from interpreted frames),
|
||||
* using a ret instruction to get back to enterTCHelper will
|
||||
* unbalance the return stack buffer---in these cases use a jmp.
|
||||
*/
|
||||
JmpInsteadOfRet = 4,
|
||||
|
||||
/*
|
||||
* The service request should be emitted on a instead of astubs.
|
||||
*
|
||||
* Overrides whatever the bits for Align and Persistent are and
|
||||
* implies !Align and !Persistent.
|
||||
*/
|
||||
EmitInA = 8,
|
||||
};
|
||||
|
||||
inline bool operator&(SRFlags a, SRFlags b) {
|
||||
return int(a) & int(b);
|
||||
}
|
||||
|
||||
inline SRFlags operator|(SRFlags a, SRFlags b) {
|
||||
return SRFlags(int(a) | int(b));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Set of all the x64 registers.
|
||||
|
||||
@@ -2153,7 +2153,7 @@ void CodeGenerator::cgRetCtrl(IRInstruction* inst) {
|
||||
void CodeGenerator::emitReqBindAddr(const Func* func,
|
||||
TCA& dest,
|
||||
Offset offset) {
|
||||
dest = m_tx64->emitServiceReq(TranslatorX64::SRFlags::SRNone,
|
||||
dest = m_tx64->emitServiceReq(SRFlags::None,
|
||||
REQ_BIND_ADDR,
|
||||
2ull,
|
||||
&dest,
|
||||
@@ -2496,7 +2496,7 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
|
||||
uint64_t notTaken = notTakenPC->getValInt();
|
||||
|
||||
m_astubs.setcc(cc, rbyte(serviceReqArgRegs[4]));
|
||||
m_tx64->emitServiceReq(TranslatorX64::SRFlags::SRInline,
|
||||
m_tx64->emitServiceReq(SRFlags::Persistent,
|
||||
REQ_BIND_JMPCC_FIRST,
|
||||
4ull,
|
||||
smashAddr,
|
||||
@@ -2516,7 +2516,7 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
|
||||
if (smashAddr != kIRDirectJccJmpActive) {
|
||||
// kIRDirectJccJmpActive only needs NormalCc exit in astubs
|
||||
|
||||
m_tx64->emitServiceReq(TranslatorX64::SRFlags::SRInline,
|
||||
m_tx64->emitServiceReq(SRFlags::Persistent,
|
||||
REQ_BIND_JMP, 2,
|
||||
smashAddr,
|
||||
uint64_t(destSK.offset()));
|
||||
@@ -2551,7 +2551,7 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
|
||||
if (RuntimeOption::EvalHHIRDisableTx64) {
|
||||
// Emit a service request to interpret a single instruction before
|
||||
// creating a new translation
|
||||
m_tx64->emitServiceReq(TranslatorX64::SRFlags::SRInline,
|
||||
m_tx64->emitServiceReq(SRFlags::Persistent,
|
||||
REQ_INTERPRET,
|
||||
2ull, uint64_t(destSK.offset()), 1);
|
||||
} else {
|
||||
@@ -4834,7 +4834,7 @@ void CodeGenerator::cgInterpOneCF(IRInstruction* inst) {
|
||||
m_as.loadq(rax[offsetof(VMExecutionContext, m_stack) +
|
||||
Stack::topOfStackOffset()], rVmSp);
|
||||
|
||||
m_tx64->emitServiceReq(TranslatorX64::SRFlags::SREmitInA, REQ_RESUME, 0ull);
|
||||
m_tx64->emitServiceReq(SRFlags::EmitInA, REQ_RESUME, 0ull);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgDefFunc(IRInstruction* inst) {
|
||||
|
||||
@@ -1389,7 +1389,7 @@ TranslatorX64::createTranslation(SrcKey sk, bool align,
|
||||
|
||||
TCA astart = a.code.frontier;
|
||||
TCA stubstart = astubs.code.frontier;
|
||||
TCA req = emitServiceReq(SRFlags::SRNone, REQ_RETRANSLATE,
|
||||
TCA req = emitServiceReq(SRFlags::None, REQ_RETRANSLATE,
|
||||
1, uint64_t(sk.offset()));
|
||||
SKTRACE(1, sk, "inserting anchor translation for (%p,%d) at %p\n",
|
||||
curUnit(), sk.offset(), req);
|
||||
@@ -2499,7 +2499,7 @@ TranslatorX64::emitBindCallHelper(SrcKey srcKey,
|
||||
|
||||
astubs. mov_reg64_reg64(rStashedAR, serviceReqArgRegs[1]);
|
||||
emitPopRetIntoActRec(astubs);
|
||||
emitServiceReq(SRFlags::SRInline, REQ_BIND_CALL, 1ull, req);
|
||||
emitServiceReq(SRFlags::Persistent, REQ_BIND_CALL, 1ull, req);
|
||||
|
||||
TRACE(1, "will bind static call: tca %p, this %p, funcd %p, astubs %p\n",
|
||||
toSmash, this, funcd, astubs.code.frontier);
|
||||
@@ -2531,7 +2531,7 @@ TranslatorX64::emitCondJmp(SrcKey skTaken, SrcKey skNotTaken,
|
||||
// emitServiceReq because that only supports constants/immediates, so
|
||||
// compute the last argument via setcc.
|
||||
astubs.setcc(cc, rbyte(serviceReqArgRegs[4]));
|
||||
emitServiceReq(SRFlags::SRInline, REQ_BIND_JMPCC_FIRST, 4ull,
|
||||
emitServiceReq(SRFlags::Persistent, REQ_BIND_JMPCC_FIRST, 4ull,
|
||||
old,
|
||||
uint64_t(skTaken.offset()),
|
||||
uint64_t(skNotTaken.offset()),
|
||||
@@ -2609,7 +2609,7 @@ TranslatorX64::bindJmpccFirst(TCA toSmash,
|
||||
// yet.
|
||||
if (taken) cc = ccNegate(cc);
|
||||
TCA stub =
|
||||
emitServiceReq(SRFlags::SRNone, REQ_BIND_JMPCC_SECOND, 3,
|
||||
emitServiceReq(SRFlags::None, REQ_BIND_JMPCC_SECOND, 3,
|
||||
toSmash, uint64_t(offWillDefer), uint64_t(cc));
|
||||
|
||||
Asm& as = getAsmFor(toSmash);
|
||||
@@ -2688,7 +2688,7 @@ TranslatorX64::emitBindJ(X64Assembler& _a, ConditionCode cc,
|
||||
emitJmpOrJcc(_a, cc, toSmash);
|
||||
}
|
||||
|
||||
TCA sr = emitServiceReq(SRFlags::SRNone, req, 2,
|
||||
TCA sr = emitServiceReq(SRFlags::None, req, 2,
|
||||
toSmash, uint64_t(dest.offset()));
|
||||
|
||||
if (&_a == &astubs) {
|
||||
@@ -2996,7 +2996,7 @@ TranslatorX64::emitRetFromInterpretedFrame() {
|
||||
// Marshall our own args by hand here.
|
||||
astubs. lea (rVmSp[-arBase], serviceReqArgRegs[0]);
|
||||
astubs. movq (rVmFp, serviceReqArgRegs[1]);
|
||||
(void) emitServiceReq(SRFlags(SRInline | SRJmpInsteadOfRet),
|
||||
(void) emitServiceReq(SRFlags::Persistent | SRFlags::JmpInsteadOfRet,
|
||||
REQ_POST_INTERP_RET, 0ull);
|
||||
return stub;
|
||||
}
|
||||
@@ -3016,7 +3016,7 @@ TranslatorX64::emitRetFromInterpretedGeneratorFrame() {
|
||||
astubs. loadq (rVmFp[AROFF(m_this)], rContAR);
|
||||
astubs. loadq (rContAR[CONTOFF(m_arPtr)], rContAR);
|
||||
astubs. movq (rVmFp, serviceReqArgRegs[1]);
|
||||
(void) emitServiceReq(SRFlags(SRInline | SRJmpInsteadOfRet),
|
||||
(void) emitServiceReq(SRFlags::Persistent | SRFlags::JmpInsteadOfRet,
|
||||
REQ_POST_INTERP_RET, 0ull);
|
||||
return stub;
|
||||
}
|
||||
@@ -3417,11 +3417,7 @@ TranslatorX64::freeRequestStub(TCA stub) {
|
||||
return true;
|
||||
}
|
||||
|
||||
TCA
|
||||
TranslatorX64::getFreeStub(bool inLine) {
|
||||
if (inLine) {
|
||||
return astubs.code.frontier;
|
||||
}
|
||||
TCA TranslatorX64::getFreeStub() {
|
||||
TCA ret = m_freeStubs.maybePop();
|
||||
if (ret) {
|
||||
Stats::inc(Stats::Astubs_Reused);
|
||||
@@ -3474,11 +3470,13 @@ class ConditionalCodeCursor {
|
||||
TCA
|
||||
TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
|
||||
va_list args) {
|
||||
bool emitInA = bool(flags & SRFlags::SREmitInA);
|
||||
bool align = bool(flags & SRFlags::SRAlign) && !emitInA;
|
||||
bool inLine = bool(flags & SRFlags::SRInline);
|
||||
bool emitInA = flags & SRFlags::EmitInA;
|
||||
bool align = (flags & SRFlags::Align) && !emitInA;
|
||||
bool notReusable = flags & SRFlags::Persistent;
|
||||
Asm& as = emitInA ? a : astubs;
|
||||
TCA start = emitInA ? a.code.frontier : getFreeStub(inLine);
|
||||
TCA start = emitInA ? a.code.frontier :
|
||||
notReusable ? astubs.code.frontier :
|
||||
getFreeStub();
|
||||
ConditionalCodeCursor cg(as, start);
|
||||
/* max space for moving to align, saving VM regs plus emitting args */
|
||||
static const int kVMRegSpace = 0x14;
|
||||
@@ -3501,18 +3499,21 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
|
||||
TRACE(3, "%p,", (void*)argVal);
|
||||
emitImmReg(as, argVal, serviceReqArgRegs[i]);
|
||||
}
|
||||
if (!inLine) {
|
||||
/* make sure that the stub has enough space that it can be
|
||||
* reused for other service requests, with different number of
|
||||
* arguments, alignment, etc.
|
||||
|
||||
if (notReusable) {
|
||||
emitImmReg(as, 0, rScratch);
|
||||
} else {
|
||||
/*
|
||||
* Make sure that the stub has enough space so it can be reused
|
||||
* for other service requests, with different number of arguments,
|
||||
* alignment, etc.
|
||||
*/
|
||||
as.emitNop(start + kMaxStubSpace - as.code.frontier);
|
||||
emitImmReg(as, (uint64_t)start, rScratch);
|
||||
} else {
|
||||
emitImmReg(as, 0, rScratch);
|
||||
}
|
||||
TRACE(3, ")\n");
|
||||
emitImmReg(as, req, rdi);
|
||||
|
||||
/*
|
||||
* Weird hand-shaking with enterTC: reverse-call a service routine.
|
||||
*
|
||||
@@ -3521,7 +3522,7 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
|
||||
* something other than enterTCHelper. In that case
|
||||
* SRJmpInsteadOfRet indicates to fake the return.
|
||||
*/
|
||||
if (flags & SRFlags::SRJmpInsteadOfRet) {
|
||||
if (flags & SRFlags::JmpInsteadOfRet) {
|
||||
as.pop(rax);
|
||||
as.jmp(rax);
|
||||
} else {
|
||||
@@ -3536,7 +3537,7 @@ TCA
|
||||
TranslatorX64::emitServiceReq(ServiceRequest req, int numArgs, ...) {
|
||||
va_list args;
|
||||
va_start(args, numArgs);
|
||||
TCA retval = emitServiceReqVA(SRFlags::SRAlign, req, numArgs, args);
|
||||
TCA retval = emitServiceReqVA(SRFlags::Align, req, numArgs, args);
|
||||
va_end(args);
|
||||
return retval;
|
||||
}
|
||||
@@ -6349,7 +6350,7 @@ TranslatorX64::translateSwitch(const Tracelet& t,
|
||||
|
||||
for (int idx = 0; idx < jmptabSize; ++idx) {
|
||||
SrcKey sk(curFunc(), i.offset() + iv.vec32()[idx]);
|
||||
jmptab[idx] = emitServiceReq(SRFlags::SRNone, REQ_BIND_ADDR, 2ull,
|
||||
jmptab[idx] = emitServiceReq(SRFlags::None, REQ_BIND_ADDR, 2ull,
|
||||
&jmptab[idx], uint64_t(sk.offset()));
|
||||
}
|
||||
}
|
||||
@@ -6411,7 +6412,7 @@ TranslatorX64::translateSSwitch(const Tracelet& t,
|
||||
|
||||
auto bindAddr = [&](TCA& dest, Offset o) {
|
||||
SrcKey sk(curFunc(), ni.offset() + o);
|
||||
dest = emitServiceReq(SRFlags::SRNone, REQ_BIND_ADDR, 2ull,
|
||||
dest = emitServiceReq(SRFlags::None, REQ_BIND_ADDR, 2ull,
|
||||
&dest, uint64_t(sk.offset()));
|
||||
};
|
||||
if (fastPath) {
|
||||
@@ -8502,7 +8503,7 @@ TranslatorX64::translateReqLit(const Tracelet& t,
|
||||
emitCall(a, (TCA)reqLitHelper, true);
|
||||
|
||||
args->m_efile = efile;
|
||||
args->m_pseudoMain = emitServiceReq(SRFlags::SRNone, REQ_BIND_REQUIRE, 3,
|
||||
args->m_pseudoMain = emitServiceReq(SRFlags::None, REQ_BIND_REQUIRE, 3,
|
||||
uint64_t(args),
|
||||
uint64_t(func), uint64_t(func->base()));
|
||||
args->m_pcOff = after;
|
||||
@@ -11284,6 +11285,10 @@ TranslatorX64::translateTracelet(SrcKey sk, bool considerHHIR/*=true*/,
|
||||
hhirTraceStart(sk.offset());
|
||||
SKTRACE(1, sk, "retrying irTranslateTracelet\n");
|
||||
result = irTranslateTracelet(t, start, stubStart, &bcMapping);
|
||||
if (result == Retry) {
|
||||
assert(a.code.frontier == start);
|
||||
assert(astubs.code.frontier == stubStart);
|
||||
}
|
||||
} while (result == Retry);
|
||||
m_useHHIR = false;
|
||||
if (result == Success) {
|
||||
@@ -11647,7 +11652,7 @@ TranslatorX64::TranslatorX64()
|
||||
|
||||
// Call to exit with whatever value the program leaves on
|
||||
// the return stack.
|
||||
m_callToExit = emitServiceReq(SRFlags(SRAlign | SRJmpInsteadOfRet),
|
||||
m_callToExit = emitServiceReq(SRFlags::Align | SRFlags::JmpInsteadOfRet,
|
||||
REQ_EXIT, 0ull);
|
||||
|
||||
/*
|
||||
@@ -11674,7 +11679,7 @@ TranslatorX64::TranslatorX64()
|
||||
rVmFp);
|
||||
astubs. load_reg64_disp_reg64(rax, offsetof(VMExecutionContext, m_stack) +
|
||||
Stack::topOfStackOffset(), rVmSp);
|
||||
emitServiceReq(SRFlags::SRInline, REQ_RESUME, 0ull);
|
||||
emitServiceReq(SRFlags::Persistent, REQ_RESUME, 0ull);
|
||||
|
||||
// Helper for DefCls, in astubs.
|
||||
{
|
||||
@@ -11743,7 +11748,7 @@ TranslatorX64::TranslatorX64()
|
||||
astubs. load_reg64_disp_reg32(rax, Func::sharedBaseOffset(), rax);
|
||||
astubs. add_reg32_reg32(rax, rdi);
|
||||
emitEagerVMRegSave(astubs, SaveFP | SavePC);
|
||||
emitServiceReq(SRFlags::SRInline, REQ_STACK_OVERFLOW, 0ull);
|
||||
emitServiceReq(SRFlags::Persistent, REQ_STACK_OVERFLOW, 0ull);
|
||||
}
|
||||
|
||||
// do gdb specific initialization. This has to happen after
|
||||
|
||||
@@ -813,7 +813,7 @@ public:
|
||||
|
||||
FreeStubList m_freeStubs;
|
||||
bool freeRequestStub(TCA stub);
|
||||
TCA getFreeStub(bool inLine);
|
||||
TCA getFreeStub();
|
||||
private:
|
||||
TCA getInterceptHelper();
|
||||
void translateInstr(const Tracelet& t, const NormalizedInstruction& i);
|
||||
@@ -931,13 +931,6 @@ private:
|
||||
int offset,
|
||||
SrcRec& fail);
|
||||
|
||||
enum SRFlags {
|
||||
SRNone = 0,
|
||||
SRAlign = 1,
|
||||
SRInline = 2,
|
||||
SRJmpInsteadOfRet = 4,
|
||||
SREmitInA = 8,
|
||||
};
|
||||
TCA emitServiceReq(ServiceRequest, int numArgs, ...);
|
||||
TCA emitServiceReq(SRFlags flags, ServiceRequest, int numArgs, ...);
|
||||
TCA emitServiceReqVA(SRFlags flags, ServiceRequest, int numArgs,
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário