Minor cleanup in srcdb.h

Mainly gets rid of the need to pass Asm& a and astubs
to all the patching functions.
Esse commit está contido em:
jdelong
2013-04-14 11:28:02 -07:00
commit de Sara Golemon
commit dcd704f2f3
6 arquivos alterados com 131 adições e 93 exclusões
+5 -3
Ver Arquivo
@@ -2425,9 +2425,9 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
emitMovRegReg(a, fp->getReg(), rVmFp);
// Get the SrcKey for the dest
SrcKey destSK(func->getValFunc(), pc->getValInt());
SrcKey destSK(func->getValFunc(), pc->getValInt());
switch(exitType) {
switch (exitType) {
case TraceExitType::NormalCc:
if (toSmash) {
TCA smashAddr = toSmash->getTCA();
@@ -2510,10 +2510,12 @@ void CodeGenerator::cgExitTrace(IRInstruction* inst) {
}
}
break;
case TraceExitType::GuardFailure:
case TraceExitType::GuardFailure: {
SrcRec* destSR = m_tx64->getSrcRec(destSK);
m_tx64->emitFallbackUncondJmp(a, *destSR);
break;
}
}
}
+1 -1
Ver Arquivo
@@ -578,7 +578,7 @@ bool cmpOpTypesMayReenter(Opcode op, Type t0, Type t1) {
TraceExitType::ExitType getExitType(Opcode opc) {
assert(opc >= ExitTrace && opc <= ExitGuardFailure);
return (TraceExitType::ExitType)(opc - ExitTrace);
return TraceExitType::ExitType(opc - ExitTrace);
}
Opcode getExitOpcode(TraceExitType::ExitType type) {
+4 -3
Ver Arquivo
@@ -975,12 +975,13 @@ enum ExitType {
NormalCc,
Slow,
SlowNoProgress,
GuardFailure
GuardFailure,
};
}
extern TraceExitType::ExitType getExitType(Opcode opc);
extern Opcode getExitOpcode(TraceExitType::ExitType);
TraceExitType::ExitType getExitType(Opcode opc);
Opcode getExitOpcode(TraceExitType::ExitType);
inline bool isExitSlow(TraceExitType::ExitType t) {
return t == TraceExitType::Slow || t == TraceExitType::SlowNoProgress;
}
+65 -47
Ver Arquivo
@@ -48,35 +48,37 @@ TCA SrcRec::getFallbackTranslation() const {
return m_anchorTranslation;
}
void SrcRec::chainFrom(Asm& a, IncomingBranch br) {
void SrcRec::chainFrom(IncomingBranch br) {
TCA destAddr = getTopTranslation();
m_incomingBranches.push_back(br);
TRACE(1, "SrcRec(%p)::chainFrom %p -> %p; %zd incoming branches\n",
TRACE(1, "SrcRec(%p)::chainFrom %p -> %p (type %d); %zd incoming branches\n",
this,
a.code.frontier, destAddr, m_incomingBranches.size());
patch(&a, br, destAddr);
br.toSmash(), destAddr, br.type(), m_incomingBranches.size());
patch(br, destAddr);
}
void SrcRec::emitFallbackJump(Asm &a, TCA from, int cc /* = -1 */) {
void SrcRec::emitFallbackJump(TCA from, int cc /* = -1 */) {
TCA destAddr = getFallbackTranslation();
IncomingBranch incoming(cc < 0 ? IncomingBranch::JMP : IncomingBranch::JCC,
from);
auto incoming = cc < 0 ? IncomingBranch::jmpFrom(from)
: IncomingBranch::jccFrom(from);
auto& a = tx64->getAsmFor(from);
// emit dummy jump to be smashed via patch()
if (cc < 0) {
a.jmp(a.code.frontier);
} else {
assert(incoming.m_type == IncomingBranch::JCC);
assert(incoming.type() == IncomingBranch::JCC);
a.jcc((ConditionCode)cc, a.code.frontier);
}
patch(&a, incoming, destAddr);
patch(incoming, destAddr);
// We'll need to know the location of this jump later so we can
// patch it to new translations added to the chain.
m_inProgressTailJumps.push_back(incoming);
}
void SrcRec::newTranslation(Asm& a, Asm &astubs, TCA newStart) {
void SrcRec::newTranslation(TCA newStart) {
// When translation punts due to hitting limit, will generate one
// more translation that will call the interpreter.
assert(m_translations.size() <= kMaxTranslations);
@@ -86,7 +88,7 @@ void SrcRec::newTranslation(Asm& a, Asm &astubs, TCA newStart) {
m_translations.push_back(newStart);
if (!m_topTranslation) {
atomic_release_store(&m_topTranslation, newStart);
patchIncomingBranches(a, astubs, newStart);
patchIncomingBranches(newStart);
}
/*
@@ -104,8 +106,7 @@ void SrcRec::newTranslation(Asm& a, Asm &astubs, TCA newStart) {
* translation possibly for this same situation.)
*/
for (size_t i = 0; i < m_tailFallbackJumps.size(); ++i) {
auto& as = asmChoose(m_tailFallbackJumps[i].m_src, a, astubs);
patch(&as, m_tailFallbackJumps[i], newStart);
patch(m_tailFallbackJumps[i], newStart);
}
// This is the new tail translation, so store the fallback jump list
@@ -114,15 +115,14 @@ void SrcRec::newTranslation(Asm& a, Asm &astubs, TCA newStart) {
m_inProgressTailJumps.clear();
}
void SrcRec::addDebuggerGuard(Asm& a, Asm &astubs, TCA dbgGuard,
TCA dbgBranchGuardSrc) {
void SrcRec::addDebuggerGuard(TCA dbgGuard, TCA dbgBranchGuardSrc) {
assert(!m_dbgBranchGuardSrc);
TRACE(1, "SrcRec(%p)::addDebuggerGuard @%p, "
"%zd incoming branches to rechain\n",
this, dbgGuard, m_incomingBranches.size());
patchIncomingBranches(a, astubs, dbgGuard);
patchIncomingBranches(dbgGuard);
// Set m_dbgBranchGuardSrc after patching, so we don't try to patch
// the debug guard.
@@ -130,12 +130,14 @@ void SrcRec::addDebuggerGuard(Asm& a, Asm &astubs, TCA dbgGuard,
atomic_release_store(&m_topTranslation, dbgGuard);
}
void SrcRec::patchIncomingBranches(Asm& a, Asm &astubs, TCA newStart) {
void SrcRec::patchIncomingBranches(TCA newStart) {
if (hasDebuggerGuard()) {
// We have a debugger guard, so all jumps to us funnel through
// this. Just smash m_dbgBranchGuardSrc.
TRACE(1, "smashing m_dbgBranchGuardSrc @%p\n", m_dbgBranchGuardSrc);
TranslatorX64::smashJmp(a, m_dbgBranchGuardSrc, newStart);
TranslatorX64::smashJmp(tx64->getAsmFor(m_dbgBranchGuardSrc),
m_dbgBranchGuardSrc,
newStart);
return;
}
@@ -144,46 +146,62 @@ void SrcRec::patchIncomingBranches(Asm& a, Asm &astubs, TCA newStart) {
vector<IncomingBranch>& change = m_incomingBranches;
for (unsigned i = 0; i < change.size(); ++i) {
TRACE(1, "SrcRec(%p)::newTranslation rechaining @%p -> %p\n",
this, change[i].m_src, newStart);
Asm *as = change[i].m_type == IncomingBranch::ADDR ?
nullptr : &asmChoose(change[i].m_src, a, astubs);
patch(as, change[i], newStart);
this, change[i].toSmash(), newStart);
patch(change[i], newStart);
}
}
void SrcRec::replaceOldTranslations(Asm& a, Asm& astubs) {
void SrcRec::replaceOldTranslations() {
// Everyone needs to give up on old translations; send them to the anchor,
// which is a REQ_RETRANSLATE
// which is a REQ_RETRANSLATE.
m_translations.clear();
m_tailFallbackJumps.clear();
atomic_release_store(&m_topTranslation, static_cast<TCA>(0));
patchIncomingBranches(a, astubs, m_anchorTranslation);
/*
* It may seem a little weird that we're about to point every
* incoming branch at the anchor, since that's going to just
* unconditionally retranslate this SrcKey and never patch the
* incoming branch to do something else.
*
* The reason this is ok is this mechanism is only used in
* non-RepoAuthoritative mode, and the granularity of code
* invalidation there is such that we'll only have incoming branches
* like this basically within the same file since we don't have
* whole program analysis.
*
* This means all these incoming branches are about to go away
* anyway ...
*
* If we ever change that we'll have to change this to patch to
* some sort of rebind requests.
*/
assert(!RuntimeOption::RepoAuthoritative);
patchIncomingBranches(m_anchorTranslation);
}
void SrcRec::patch(Asm* a, IncomingBranch branch, TCA dest) {
if (branch.m_type == IncomingBranch::ADDR) {
// Note that this effectively ignores a
atomic_release_store(branch.m_addr, dest);
return;
void SrcRec::patch(IncomingBranch branch, TCA dest) {
switch (branch.type()) {
case IncomingBranch::JMP: {
auto& a = tx64->getAsmFor(branch.toSmash());
CodeCursor cg(a, branch.toSmash());
TranslatorX64::smashJmp(a, branch.toSmash(), dest);
break;
}
// modifying reachable code
switch(branch.m_type) {
case IncomingBranch::JMP: {
CodeCursor cg(*a, branch.m_src);
TranslatorX64::smashJmp(*a, branch.m_src, dest);
break;
}
case IncomingBranch::JCC: {
// patch destination, but preserve the condition code
int32_t delta = safe_cast<int32_t>((dest - branch.m_src) -
TranslatorX64::kJmpccLen);
int32_t* addr = (int32_t*)(branch.m_src + TranslatorX64::kJmpccLen - 4);
atomic_release_store(addr, delta);
break;
}
default:
not_implemented();
case IncomingBranch::JCC: {
// patch destination, but preserve the condition code
int32_t delta = safe_cast<int32_t>((dest - branch.toSmash()) -
TranslatorX64::kJmpccLen);
int32_t* addr = (int32_t*)(branch.toSmash() +
TranslatorX64::kJmpccLen - 4);
atomic_release_store(addr, delta);
break;
}
case IncomingBranch::ADDR:
// Note that this effectively ignores a
atomic_release_store(reinterpret_cast<TCA*>(branch.toSmash()), dest);
}
}
+40 -19
Ver Arquivo
@@ -28,31 +28,49 @@ namespace HPHP {
namespace VM {
namespace Transl {
/*
* Incoming branches between different translations are tracked using
* this structure.
*
* This allows us to smash them later to point to different things.
* We handle conditional and unconditional jumps, as well as pointers
* to code (via IncomingBranch::ADDR, used for example in a switch
* table).
*
* We don't need to track which condition code a conditional jump used
* because we take care to smash only the address and leave the code
* intact.
*/
struct IncomingBranch {
enum BranchType {
JMP,
JCC,
ADDR,
};
IncomingBranch(BranchType t, TCA src)
: m_type(t), m_src(src) { }
IncomingBranch(TCA src)
: m_type(JMP), m_src(src) { }
IncomingBranch(TCA* addr)
: m_type(ADDR), m_addr(addr) { }
static IncomingBranch jmpFrom(TCA from) { return IncomingBranch(JMP, from); }
static IncomingBranch jccFrom(TCA from) { return IncomingBranch(JCC, from); }
static IncomingBranch addr(TCA* from) {
return IncomingBranch(ADDR, TCA(from));
}
BranchType type() const { return m_type; }
TCA toSmash() const { return m_toSmash; }
private:
explicit IncomingBranch(BranchType type, TCA toSmash)
: m_type(type)
, m_toSmash(toSmash)
{}
BranchType m_type;
union {
TCA m_src;
TCA* m_addr;
};
TCA m_toSmash;
};
/*
* SrcRec: record of translator output for a given source location.
*/
struct SrcRec {
typedef X64Assembler Asm;
static const unsigned int kMaxTranslations = 12;
SrcRec()
@@ -79,12 +97,11 @@ struct SrcRec {
* when holding the translator write lease.
*/
void setFuncInfo(const Func* f);
void chainFrom(Asm& a, IncomingBranch br);
void emitFallbackJump(Asm &a, TCA from, int cc = -1);
void newTranslation(Asm& a, Asm &astubs, TCA newStart);
void replaceOldTranslations(Asm& a, Asm& astubs);
void addDebuggerGuard(Asm& a, Asm &astubs, TCA dbgGuard,
TCA m_dbgBranchGuardSrc);
void chainFrom(IncomingBranch br);
void emitFallbackJump(TCA from, int cc = -1);
void newTranslation(TCA newStart);
void replaceOldTranslations();
void addDebuggerGuard(TCA dbgGuard, TCA m_dbgBranchGuardSrc);
bool hasDebuggerGuard() const { return m_dbgBranchGuardSrc != nullptr; }
const MD5& unitMd5() const { return m_unitMd5; }
@@ -92,6 +109,10 @@ struct SrcRec {
return m_translations;
}
/*
* The anchor translation is a retranslate request for the current
* SrcKey that will continue the tracelet chain.
*/
void setAnchorTranslation(TCA anc) {
assert(!m_anchorTranslation);
assert(m_tailFallbackJumps.empty());
@@ -108,8 +129,8 @@ struct SrcRec {
private:
TCA getFallbackTranslation() const;
void patch(Asm* a, IncomingBranch branch, TCA dest);
void patchIncomingBranches(Asm& a, Asm& astubs, TCA newStart);
void patch(IncomingBranch branch, TCA dest);
void patchIncomingBranches(TCA newStart);
private:
// This either points to the most recent translation in the
+16 -20
Ver Arquivo
@@ -1223,10 +1223,7 @@ asm_label(a, release);
size_t(a.code.frontier - m_dtorGenericStub));
}
/*
* Translation call targets. It is a lot easier, and a bit more
* portable, to use C linkage from assembly.
*/
TCA TranslatorX64::retranslate(SrcKey sk, bool align, bool allowIR) {
if (isDebuggerAttachedProcess() && isSrcKeyInBL(curUnit(), sk)) {
// We are about to translate something known to be blacklisted by
@@ -2560,12 +2557,11 @@ TranslatorX64::bindJmp(TCA toSmash, SrcKey destSk,
smashed = true;
SrcRec* sr = getSrcRec(destSk);
if (req == REQ_BIND_ADDR) {
sr->chainFrom(a, IncomingBranch((TCA*)toSmash));
sr->chainFrom(IncomingBranch::addr(reinterpret_cast<TCA*>(toSmash)));
} else if (req == REQ_BIND_JCC) {
sr->chainFrom(getAsmFor(toSmash),
IncomingBranch(IncomingBranch::JCC, toSmash));
sr->chainFrom(IncomingBranch::jccFrom(toSmash));
} else {
sr->chainFrom(getAsmFor(toSmash), IncomingBranch(toSmash));
sr->chainFrom(IncomingBranch::jmpFrom(toSmash));
}
return tDest;
}
@@ -2616,7 +2612,7 @@ TranslatorX64::bindJmpccFirst(TCA toSmash,
emitServiceReq(SRFlags::SRNone, REQ_BIND_JMPCC_SECOND, 3,
toSmash, uint64_t(offWillDefer), uint64_t(cc));
Asm &as = getAsmFor(toSmash);
Asm& as = getAsmFor(toSmash);
// Its not clear where chainFrom should go to if as is astubs
assert(&as != &astubs);
@@ -2647,7 +2643,7 @@ TranslatorX64::bindJmpccFirst(TCA toSmash,
*/
CodeCursor cg(as, toSmash);
as.jcc(cc, stub);
getSrcRec(dest)->chainFrom(as, IncomingBranch(as.code.frontier));
getSrcRec(dest)->chainFrom(IncomingBranch::jmpFrom(as.code.frontier));
TRACE(5, "bindJmpccFirst: overwrote with cc%02x taken %d\n", cc, taken);
return tDest;
}
@@ -2663,8 +2659,7 @@ TranslatorX64::bindJmpccSecond(TCA toSmash, const Offset off,
if (branch && writer.acquire()) {
smashed = true;
SrcRec* destRec = getSrcRec(dest);
destRec->chainFrom(getAsmFor(toSmash),
IncomingBranch(IncomingBranch::JCC, toSmash));
destRec->chainFrom(IncomingBranch::jccFrom(toSmash));
}
return branch;
}
@@ -2824,19 +2819,19 @@ void
TranslatorX64::emitFallbackJmp(Asm& as, SrcRec& dest,
ConditionCode cc /* = CC_NZ */) {
prepareForSmash(as, kJmpccLen);
dest.emitFallbackJump(as, as.code.frontier, cc);
dest.emitFallbackJump(as.code.frontier, cc);
}
void
TranslatorX64::emitFallbackUncondJmp(Asm& as, SrcRec& dest) {
prepareForSmash(as, kJmpLen);
dest.emitFallbackJump(as, as.code.frontier);
dest.emitFallbackJump(as.code.frontier);
}
void
TranslatorX64::emitFallbackCondJmp(Asm& as, SrcRec& dest, ConditionCode cc) {
prepareForSmash(as, kJmpccLen);
dest.emitFallbackJump(as, as.code.frontier, cc);
dest.emitFallbackJump(as.code.frontier, cc);
}
void TranslatorX64::emitReqRetransNoIR(Asm& as, SrcKey& sk) {
@@ -3257,7 +3252,8 @@ bool TranslatorX64::handleServiceRequest(TReqInfo& info,
case REQ_BIND_JMP:
case REQ_BIND_JCC:
case REQ_BIND_JMP_NO_IR:
case REQ_BIND_ADDR: {
case REQ_BIND_ADDR:
{
TCA toSmash = (TCA)args[0];
Offset off = args[1];
sk = SrcKey(curFunc(), off);
@@ -3296,7 +3292,7 @@ bool TranslatorX64::handleServiceRequest(TReqInfo& info,
if (writer) {
smashed = true;
SrcRec* sr = getSrcRec(sk);
sr->chainFrom(a, IncomingBranch(&rlsa->m_pseudoMain));
sr->chainFrom(IncomingBranch::addr(&rlsa->m_pseudoMain));
}
}
} break;
@@ -11406,7 +11402,7 @@ TranslatorX64::translateTracelet(SrcKey sk, bool considerHHIR/*=true*/,
// metadata is not yet visible.
TRACE(1, "newTranslation: %p sk: (func %d, bcOff %d)\n",
start, sk.getFuncId(), sk.m_offset);
srcRec.newTranslation(a, astubs, start);
srcRec.newTranslation(start);
TRACE(1, "tx64: %zd-byte tracelet\n", a.code.frontier - start);
if (Trace::moduleEnabledRelease(Trace::tcspace, 1)) {
Trace::traceRelease(getUsage().c_str());
@@ -12177,7 +12173,7 @@ void TranslatorX64::addDbgGuardImpl(SrcKey sk, SrcRec& srcRec) {
TCA dbgBranchGuardSrc = a.code.frontier;
a. jmp(realCode);
// Add it to srcRec
srcRec.addDebuggerGuard(a, astubs, dbgGuard, dbgBranchGuardSrc);
srcRec.addDebuggerGuard(dbgGuard, dbgBranchGuardSrc);
}
bool TranslatorX64::dumpTCCode(const char* filename) {
@@ -12367,7 +12363,7 @@ void TranslatorX64::invalidateSrcKey(SrcKey sk) {
* just created some garbage in the TC. We currently have no mechanism
* to reclaim this.
*/
sr->replaceOldTranslations(a, astubs);
sr->replaceOldTranslations();
}
void TranslatorX64::invalidateFileWork(Eval::PhpFile* f) {