interpOne instructions that fail the HHBC->HHIR translation

This diff adds full support for doing general interpOnes in HHIR.
Whenever a bytecode instruction fails (punts) in the HHBC->HHIR
translation, the NormalizedInstruction is marked with an 'interp' flag
and the HHIR translation for the whole tracelet is retried.  This
forces an InterpOne of such instruction, preventing HHIR from
attempting to translate it again, which then allows the HHBC->HHIR
translation to make further progress.  If another instruction in the
sequence punts again, the process is repeat and so on.
Esse commit está contido em:
ottoni
2013-04-09 15:06:39 -07:00
commit de Sara Golemon
commit da37a0ae8f
13 arquivos alterados com 262 adições e 102 exclusões
+12 -6
Ver Arquivo
@@ -1163,14 +1163,20 @@ D:Int LdSwitchObjIndex S0:Obj S1:Int S2:Int
in the range [S1:S1 + S2), and if so return the value S1 - (Int)S0.
Else, they return the target of the default target, S2 + 1.
D:StkPtr InterpOne S0:StkPtr S1:StkPtr S2:ConstInt S3:ConstInt
S4:ConstInt [ -> L ]
D:StkPtr InterpOne<T> S0:StkPtr S1:StkPtr S2:ConstInt S3:ConstInt
Call the interpreter implementation function for one opcode. S0 and
S1 are the VM frame and stack pointers, respectively. S2 is the bytecode
offset. S3 is the number of cells to adjust the stack pointer before
running the interpreter function. S4 is the VM DataType of the return
type for the opcode. Returns the updated VM stack pointer.
S1 are, respectively, the VM frame and stack pointers before this
instruction. S2 is the bytecode offset. S3 is the stack adjustment
performed by this instruction: number of cells popped minus number
of cells pushed. This instruction returns the updated VM stack
pointer.
InterpOneCF S0:StkPtr S1:StkPtr S2:ConstInt S3:ConstInt
Call the interpreter implementation function for one control-flow
opcode. S0 and S1 are, respectively, the VM frame and stack
pointers before this instruction. S2 is the bytecode offset.
15. Register allocation
+20
Ver Arquivo
@@ -486,6 +486,26 @@ StackTransInfo instrStackTransInfo(const Opcode* opcode) {
}
}
bool pushesActRec(Opcode opcode) {
switch (opcode) {
case OpFPushFunc:
case OpFPushFuncD:
case OpFPushObjMethod:
case OpFPushObjMethodD:
case OpFPushClsMethod:
case OpFPushClsMethodF:
case OpFPushClsMethodD:
case OpFPushCtor:
case OpFPushCtorD:
case OpFPushCuf:
case OpFPushCufF:
case OpFPushCufSafe:
return true;
default:
return false;
}
}
static void staticArrayStreamer(ArrayData* ad, std::stringstream& out) {
out << "array(";
if (!ad->empty()) {
+1
Ver Arquivo
@@ -716,6 +716,7 @@ static inline bool isTypePred(const Opcode op) {
int instrLen(const Opcode* opcode);
InstrFlags instrFlags(Opcode opcode);
int numSuccs(const Opcode* opcode);
bool pushesActRec(Opcode opcode);
// The returned struct has normalized variable-sized immediates
ArgUnion getImm(const Opcode* opcode, int idx);
+30 -31
Ver Arquivo
@@ -4749,47 +4749,46 @@ void CodeGenerator::cgInterpOne(IRInstruction* inst) {
SSATmp* pcOffTmp = inst->getSrc(2);
SSATmp* spAdjustmentTmp = inst->getSrc(3);
Type resultType = inst->getTypeParam();
Block* label = inst->getTaken();
assert(pcOffTmp->isConst());
assert(spAdjustmentTmp->isConst());
assert(fp->getType() == Type::StkPtr);
assert(sp->getType() == Type::StkPtr);
int64_t pcOff = pcOffTmp->getValInt();
void* interpOneHelper =
interpOneEntryPoints[*(getCurFunc()->unit()->at(pcOff))];
auto opc = *(getCurFunc()->unit()->at(pcOff));
void* interpOneHelper = interpOneEntryPoints[opc];
auto dstReg = InvalidReg;
if (label) {
dstReg = rScratch;
}
cgCallHelper(m_as, (TCA)interpOneHelper, dstReg, kSyncPoint,
ArgGroup().ssa(fp).ssa(sp).imm(pcOff));
if (label) {
// compare the pc in the returned execution context with the
// bytecode offset of the label
Trace* targetTrace = label->getTrace();
assert(targetTrace);
uint32_t targetBcOff = targetTrace->getBcOff();
// compare the pc with the target bc offset
m_as.cmp_imm64_disp_reg64(targetBcOff,
offsetof(VMExecutionContext, m_pc),
dstReg);
// emitFwdJcc(CC_E, label);
}
auto newSpReg = inst->getDst()->getReg();
DEBUG_ONLY auto spReg = sp->getReg();
int64_t spAdjustment = spAdjustmentTmp->getValInt();
int64_t adjustment =
(spAdjustment - (resultType == Type::None ? 0 : 1)) * sizeof(Cell);
assert(newSpReg == spReg);
if (adjustment != 0) {
m_as.add_imm32_reg64(adjustment, newSpReg);
assert(newSpReg == sp->getReg());
int64_t spAdjustBytes = cellsToBytes(spAdjustmentTmp->getValInt());
if (spAdjustBytes != 0) {
m_as.addq(spAdjustBytes, newSpReg);
}
}
void CodeGenerator::cgInterpOneCF(IRInstruction* inst) {
SSATmp* fp = inst->getSrc(0);
SSATmp* sp = inst->getSrc(1);
int64_t pcOff = inst->getSrc(2)->getValInt();
auto opc = *(getCurFunc()->unit()->at(pcOff));
void* interpOneHelper = interpOneEntryPoints[opc];
auto dstReg = InvalidReg;
cgCallHelper(m_as, (TCA)interpOneHelper, dstReg, kSyncPoint,
ArgGroup().ssa(fp).ssa(sp).imm(pcOff));
// The interpOne method returns a pointer to the current ExecutionContext
// in rax. Use it read the 'm_fp' and 'm_stack.m_top' fields into the
// rVmFp and rVmSp registers.
m_as.loadq(rax[offsetof(VMExecutionContext, m_fp)], rVmFp);
m_as.loadq(rax[offsetof(VMExecutionContext, m_stack) +
Stack::topOfStackOffset()], rVmSp);
m_tx64->emitServiceReq(TranslatorX64::SRFlags::SREmitInA, REQ_RESUME, 0ull);
}
void CodeGenerator::cgDefFunc(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* func = inst->getSrc(0);
+49 -22
Ver Arquivo
@@ -111,7 +111,7 @@ SSATmp* HhbcTranslator::pop(Type type) {
void HhbcTranslator::discard(unsigned n) {
for (unsigned i = 0; i < n; ++i) {
pop(Type::Gen);
pop(Type::Gen | Type::Cls);
}
}
@@ -324,7 +324,7 @@ void HhbcTranslator::emitAddNewElemC() {
}
void HhbcTranslator::emitNewCol(int type, int numElems) {
emitInterpOneOrPunt(Type::Obj);
emitInterpOneOrPunt(Type::Obj, 0);
}
void HhbcTranslator::emitColAddElemC() {
@@ -336,7 +336,7 @@ void HhbcTranslator::emitColAddNewElemC() {
}
void HhbcTranslator::emitCns(uint32_t id) {
emitInterpOneOrPunt(Type::Cell);
emitInterpOneOrPunt(Type::Cell, 0);
}
void HhbcTranslator::emitDefCns(uint32_t id) {
@@ -355,19 +355,19 @@ void HhbcTranslator::emitConcat() {
void HhbcTranslator::emitDefCls(int cid, Offset after) {
// m_tb->genDefCls(lookupPreClassId(cid), getCurUnit()->at(after));
emitInterpOneOrPunt(Type::None);
emitInterpOneOrPunt(Type::None, 0);
}
void HhbcTranslator::emitDefFunc(int fid) {
// m_tb->genDefFunc(lookupFuncId(fid));
emitInterpOneOrPunt(Type::None);
emitInterpOneOrPunt(Type::None, 0);
}
void HhbcTranslator::emitLateBoundCls() {
Class* clss = getCurClass();
if (!clss) {
// no static context class, so this will raise an error
emitInterpOne(Type::Cls);
emitInterpOne(Type::Cls, 0);
return;
}
push(m_tb->gen(LdClsCtx, m_tb->genLdCtx(getCurFunc())));
@@ -376,7 +376,7 @@ void HhbcTranslator::emitLateBoundCls() {
void HhbcTranslator::emitSelf() {
Class* clss = getCurClass();
if (clss == NULL) {
emitInterpOne(Type::Cls);
emitInterpOne(Type::Cls, 0);
} else {
push(m_tb->genDefConst(clss));
}
@@ -385,7 +385,7 @@ void HhbcTranslator::emitSelf() {
void HhbcTranslator::emitParent() {
const Class* clss = getCurClass()->parent();
if (clss == NULL || clss->parent() == NULL) {
emitInterpOne(Type::Cls);
emitInterpOne(Type::Cls, 0);
} else {
push(m_tb->genDefConst(clss->parent()));
}
@@ -853,8 +853,7 @@ void HhbcTranslator::emitContStopped() {
}
void HhbcTranslator::emitContHandle() {
// No reason to punt, translator-x64 does emitInterpOne as well
emitInterpOne(Type::None, 1);
emitInterpOneCF(1);
}
void HhbcTranslator::emitStrlen() {
@@ -1826,7 +1825,16 @@ void HhbcTranslator::checkTypeLocal(uint32_t locId, Type type) {
}
void HhbcTranslator::assertTypeLocal(uint32_t localIndex, Type type) {
m_tb->genAssertLoc(localIndex, type);
m_tb->genAssertLoc(localIndex, type, false);
}
void HhbcTranslator::overrideTypeLocal(uint32_t localIndex, Type type) {
// if changing the inner type of a boxed local, also drop the
// information about inner types for any other boxed local
if (type.isBoxed()) {
m_tb->dropLocalRefsInnerTypes();
}
m_tb->genAssertLoc(localIndex, type, true);
}
Trace* HhbcTranslator::guardTypeStack(uint32_t stackIndex,
@@ -1967,7 +1975,7 @@ void HhbcTranslator::emitVerifyParamType(int32_t paramId) {
* For now we just interp that case.
*/
if (!locType.isObj()) {
emitInterpOneOrPunt(Type::None);
emitInterpOneOrPunt(Type::None, 0);
return;
}
@@ -2544,26 +2552,45 @@ void HhbcTranslator::emitXor() {
m_tb->genDecRef(btr);
}
void HhbcTranslator::emitInterpOne(Type type,
int numDiscard, /* = 0 */
Trace* target /* = NULL */) {
/**
* Emit InterpOne instruction.
* - 'type' is the return type of the value the instruction pushes on
* the stack if any (or Type:None if none)
* - 'numPopped' is the number of cells that this instruction pops
* - 'numExtraPushed' is the number of cells this instruction pushes on
* the stack, in addition to the cell corresponding to 'type'
*/
void HhbcTranslator::emitInterpOne(Type type, int numPopped,
int numExtraPushed) {
spillStack();
// discard the top elements of the stack
discard(numDiscard);
m_tb->genInterpOne(m_bcOff, m_stackDeficit, type, target);
// discard the top elements of the stack, which are consumed by this instr
discard(numPopped);
assert(numPopped == m_stackDeficit);
int numPushed = (type == Type::None ? 0 : 1) + numExtraPushed;
m_tb->genInterpOne(m_bcOff, numPopped - numPushed, type);
m_stackDeficit = 0;
}
void HhbcTranslator::emitInterpOneOrPunt(Type type,
int numDiscard, /* = 0 */
Trace* target /* = NULL */) {
void HhbcTranslator::emitInterpOneCF(int numPopped) {
spillStack();
// discard the top elements of the stack, which are consumed by this instr
discard(numPopped);
assert(numPopped == m_stackDeficit);
m_tb->gen(InterpOneCF, m_tb->getFp(), m_tb->getSp(),
m_tb->genDefConst(m_bcOff));
m_stackDeficit = 0;
m_hasExit = true;
}
void HhbcTranslator::emitInterpOneOrPunt(Type type, int numPopped,
int numExtraPushed) {
if (RuntimeOption::EvalIRPuntDontInterp) {
Op op = *(Op*)(getCurUnit()->entry() + m_bcOff);
const char* name = StringData::GetStaticString(
std::string("PuntDontInterp-") + opcodeToName(op))->data();
SPUNT(name);
} else {
emitInterpOne(type, numDiscard, target);
emitInterpOne(type, numPopped, numExtraPushed);
}
}
@@ -352,8 +352,11 @@ struct HhbcTranslator {
void assertTypeStack(uint32_t stackIndex, Type type);
void checkTypeLocal(uint32_t localIndex, Type type);
void checkTypeTopOfStack(Type type, Offset nextByteCode);
void overrideTypeLocal(uint32_t localIndex, Type type);
void setThisAvailable();
void emitLoadDeps();
void emitInterpOne(Type type, int numPopped, int numExtraPushed = 0);
void emitInterpOneCF(int numPopped);
private:
/*
@@ -534,10 +537,7 @@ private:
Trace* getExitSlowTrace();
Trace* getGuardExit();
SSATmp* emitLdLocWarn(uint32_t id, Trace* target);
void emitInterpOne(Type type, int numDiscard = 0, Trace* target = nullptr);
void emitInterpOneOrPunt(Type type,
int numDiscard = 0,
Trace* target = nullptr);
void emitInterpOneOrPunt(Type type, int numPopped, int numExtraPushed = 0);
void emitBinaryArith(Opcode);
template<class Lambda>
SSATmp* emitIterInitCommon(int offset, Lambda genFunc);
+16 -2
Ver Arquivo
@@ -389,7 +389,10 @@ O(ArrayAdd, D(Arr), SUnk, N|Mem|CRc|PRc) \
O(DefCls, ND, SUnk, C|E|N) \
O(DefFunc, ND, SUnk, C|E|N|Er) \
O(AKExists, D(Bool), S(Cell) S(Cell), C|N) \
O(InterpOne, D(StkPtr), SUnk, E|N|Mem|Refs|Er) \
O(InterpOne, D(StkPtr), S(StkPtr) S(StkPtr) \
C(Int) C(Int), E|N|Mem|Refs|Er) \
O(InterpOneCF, ND, S(StkPtr) S(StkPtr) \
C(Int), T|E|N|Mem|Refs|Er) \
O(Spill, DofS(0), SUnk, Mem) \
O(Reload, DofS(0), SUnk, Mem) \
O(AllocSpill, ND, C(Int), E|Mem) \
@@ -405,7 +408,7 @@ O(FillContLocals, ND, S(StkPtr) \
S(Obj), E|N|Mem) \
O(FillContThis, ND, S(Obj) \
S(PtrToCell) C(Int), E|Mem) \
O(ContEnter, ND, S(StkPtr) \
O(ContEnter, ND, S(StkPtr) \
S(TCA) C(Int) S(StkPtr), E|Mem) \
O(UnlinkContVarEnv, ND, S(StkPtr), E|N|Mem) \
O(LinkContVarEnv, ND, S(StkPtr), E|N|Mem) \
@@ -1391,6 +1394,17 @@ public:
static Type fromRuntimeType(const Transl::RuntimeType& rtt) {
return fromDataType(rtt.outerType(), rtt.innerType());
}
static Type fromDynLocation(const Transl::DynLocation* dynLoc) {
if (!dynLoc) {
return JIT::Type::None;
}
DataType dt = dynLoc->rtt.outerType();
if (dt == KindOfUnknown) {
return JIT::Type::Gen;
}
return JIT::Type::fromDataType(dt, dynLoc->rtt.innerType());
}
}; // class Type
static_assert(sizeof(Type) <= sizeof(uint64_t),
+70 -4
Ver Arquivo
@@ -1389,9 +1389,49 @@ TranslatorX64::irPassPredictedAndInferredTypes(const NormalizedInstruction& i) {
}
}
void
TranslatorX64::irTranslateInstr(const Tracelet& t,
const NormalizedInstruction& i) {
/**
* Returns the number of cells that instruction i pops from the stack.
*/
static int getNumPopped(const NormalizedInstruction& i) {
return -getStackDelta(i)
// getStackDelta includes the output left on the stack, so discount it
+ (i.outStack ? 1 : 0)
// getStackDelta includes ActRec cells pushed on the stack, so discount them
+ (pushesActRec(i.op()) ? kNumActRecCells : 0);
}
/**
* Returns the number of Act-Rec cells that instruction i pushes onto the stack.
*/
static int getNumARCellsPushed(const NormalizedInstruction& i) {
return pushesActRec(i.op()) ? kNumActRecCells : 0;
}
void TranslatorX64::irInterpretInstr(const NormalizedInstruction& i) {
JIT::Type outStkType = JIT::Type::fromDynLocation(i.outStack);
int poppedCells = getNumPopped(i);
int arPushedCells = getNumARCellsPushed(i);
FTRACE(5, "HHIR: BC Instr {} Popped = {} ARCellsPushed = {}\n",
i.toString(), poppedCells, arPushedCells);
if (i.changesPC) {
m_hhbcTrans->emitInterpOneCF(poppedCells);
} else {
m_hhbcTrans->emitInterpOne(outStkType, poppedCells, arPushedCells);
if (i.outLocal) {
// HHIR tracks local values and types, so we should inform it about
// the new local type. This is done via an overriding type assertion.
assert(i.outLocal->isLocal());
int32_t locId = i.outLocal->location.offset;
JIT::Type newType = JIT::Type::fromRuntimeType(i.outLocal->rtt);
m_hhbcTrans->overrideTypeLocal(locId, newType);
}
}
}
void TranslatorX64::irTranslateInstr(const Tracelet& t,
const NormalizedInstruction& i) {
assert(m_useHHIR);
assert(!i.outStack || i.outStack->isStack());
assert(!i.outLocal || i.outLocal->isLocal());
@@ -1423,7 +1463,12 @@ TranslatorX64::irTranslateInstr(const Tracelet& t,
m_hhbcTrans->emitIncStat(Stats::opcodeToIRPostStatCounter(i.op()),
1, true);
}
irTranslateInstrWork(t, i);
if (i.interp) {
irInterpretInstr(i);
} else {
irTranslateInstrWork(t, i);
}
irPassPredictedAndInferredTypes(i);
}
@@ -1474,6 +1519,19 @@ void TranslatorX64::irEmitResolvedDeps(const ChangeMap& resolvedDeps) {
}
}
static bool supportedInterpOne(const NormalizedInstruction* i) {
switch (i->op()) {
// Instructions that do function return are not supported yet
case OpRetC:
case OpRetV:
case OpContRetC:
case OpNativeImpl:
return false;
default:
return true;
}
}
TranslatorX64::TranslateTraceletResult
TranslatorX64::irTranslateTracelet(Tracelet& t,
const TCA start,
@@ -1508,6 +1566,14 @@ TranslatorX64::irTranslateTracelet(Tracelet& t,
m_curNI = ni;
irTranslateInstr(t, *ni);
} catch (JIT::FailedIRGen& fcg) {
// If we haven't tried interpreting ni yet, flag it to be interpreted
// and retry
if (RuntimeOption::EvalHHIRDisableTx64 && !ni->interp &&
supportedInterpOne(ni)) {
ni->interp = true;
transResult = Retry;
break;
}
if (!RuntimeOption::EvalHHIRDisableTx64 || !ni->prev) {
// Let tx64 handle the entire tracelet.
throw;
+23 -10
Ver Arquivo
@@ -461,8 +461,14 @@ void TraceBuilder::genGuardLoc(uint32_t id, Type type, Trace* exitTrace) {
}
}
void TraceBuilder::genAssertLoc(uint32_t id, Type type) {
Type prevType = getLocalType(id);
/**
* Generates an AssertLoc instruction for the given local 'id' and 'type'.
* If the 'override' flag is not set, then 'type' must be a subtype of the
* previous tracked type for this local.
*/
void TraceBuilder::genAssertLoc(uint32_t id, Type type,
bool overrideType /* =false */) {
Type prevType = overrideType ? Type::None : getLocalType(id);
if (prevType == Type::None || type.strictSubtypeOf(prevType)) {
LocalId local(id);
gen(AssertLoc, type, &local, m_fpValue);
@@ -871,15 +877,13 @@ static SSATmp* getStackValue(SSATmp* sp,
case InterpOne: {
// sp = InterpOne(fp, sp, bcOff, stackAdjustment, resultType)
SSATmp* prevSp = inst->getSrc(1);
int64_t numPopped = inst->getSrc(3)->getValInt();
int64_t spAdjustment = inst->getSrc(3)->getValInt(); // # popped - # pushed
Type resultType = inst->getTypeParam();
int64_t numPushed = resultType == Type::None ? 0 : 1;
if (index == 0 && numPushed == 1) {
if (index == 0 && resultType != Type::None) {
type = resultType;
return nullptr;
}
return getStackValue(prevSp, index - (numPushed - numPopped),
spansCall, type);
return getStackValue(prevSp, index + spAdjustment, spansCall, type);
}
case NewObj:
@@ -973,11 +977,9 @@ void TraceBuilder::genNativeImpl() {
SSATmp* TraceBuilder::genInterpOne(uint32_t pcOff,
uint32_t stackAdjustment,
Type resultType,
Trace* target) {
Type resultType) {
return gen(InterpOne,
resultType,
getFirstBlock(target),
m_fpValue,
m_spValue,
genDefConst<int64_t>(pcOff),
@@ -1701,6 +1703,17 @@ void TraceBuilder::updateLocalRefValues(SSATmp* oldRef, SSATmp* newRef) {
}
}
/**
* This method changes any boxed local into a BoxedCell type.
*/
void TraceBuilder::dropLocalRefsInnerTypes() {
for (size_t id = 0; id < m_localTypes.size(); id++) {
if (m_localTypes[id].isBoxed()) {
m_localTypes[id] = Type::BoxedCell;
}
}
}
/**
* Called to clear out the tracked local values at a call site.
* Calls kill all registers, so we don't want to keep locals in
+5 -2
Ver Arquivo
@@ -52,6 +52,7 @@ public:
void setThisAvailable() {
m_thisIsAvailable = true;
}
void dropLocalRefsInnerTypes();
// Run one more pass of simplification on this builder's trace.
void optimizeTrace();
@@ -153,7 +154,9 @@ public:
SSATmp* mask64,
SSATmp* vals64,
Trace* exitTrace);
void genAssertLoc(uint32_t id, Type type);
void genAssertLoc(uint32_t id,
Type type,
bool override = false); // ignores conflict w/ prev type
SSATmp* genUnboxPtr(SSATmp* ptr);
SSATmp* genLdRef(SSATmp* ref, Type type, Trace* exit);
@@ -242,7 +245,7 @@ public:
SSATmp* genIterFree(uint32_t iterId);
SSATmp* genInterpOne(uint32_t pcOff, uint32_t stackAdjustment,
Type resultType, Trace* target);
Type resultType);
Trace* getExitSlowTrace(uint32_t bcOff,
int32_t stackDeficit,
uint32_t numOpnds,
+19 -17
Ver Arquivo
@@ -3561,10 +3561,12 @@ class ConditionalCodeCursor {
TCA
TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
va_list args) {
bool align = bool(flags & SRFlags::SRAlign);
bool inLine = bool(flags & SRFlags::SRInline);
TCA start = getFreeStub(inLine);
ConditionalCodeCursor cg(astubs, start);
bool emitInA = bool(flags & SRFlags::SREmitInA);
bool align = bool(flags & SRFlags::SRAlign) && !emitInA;
bool inLine = bool(flags & SRFlags::SRInline);
Asm& as = emitInA ? a : astubs;
TCA start = emitInA ? a.code.frontier : getFreeStub(inLine);
ConditionalCodeCursor cg(as, start);
/* max space for moving to align, saving VM regs plus emitting args */
static const int kVMRegSpace = 0x14;
static const int kMovSize = 0xa;
@@ -3573,10 +3575,10 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
+ kVMRegSpace
+ kNumServiceRegs * kMovSize;
if (align) {
moveToAlign(astubs);
moveToAlign(as);
}
TCA retval = astubs.code.frontier;
emitEagerVMRegSave(astubs, SaveFP);
TCA retval = as.code.frontier;
emitEagerVMRegSave(as, SaveFP);
/*
* Move args into appropriate regs.
*/
@@ -3584,20 +3586,20 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
for (int i = 0; i < numArgs; i++) {
uint64_t argVal = va_arg(args, uint64_t);
TRACE(3, "%p,", (void*)argVal);
emitImmReg(astubs, argVal, serviceReqArgRegs[i]);
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.
*/
astubs. emitNop(start + kMaxStubSpace - astubs.code.frontier);
emitImmReg(astubs, (uint64_t)start, rScratch);
as.emitNop(start + kMaxStubSpace - as.code.frontier);
emitImmReg(as, (uint64_t)start, rScratch);
} else {
emitImmReg(astubs, 0, rScratch);
emitImmReg(as, 0, rScratch);
}
TRACE(3, ")\n");
emitImmReg(astubs, req, rdi);
emitImmReg(as, req, rdi);
/*
* Weird hand-shaking with enterTC: reverse-call a service routine.
*
@@ -3607,13 +3609,13 @@ TranslatorX64::emitServiceReqVA(SRFlags flags, ServiceRequest req, int numArgs,
* SRJmpInsteadOfRet indicates to fake the return.
*/
if (flags & SRFlags::SRJmpInsteadOfRet) {
astubs. pop (rax);
astubs. jmp (rax);
as.pop(rax);
as.jmp(rax);
} else {
astubs. ret();
as.ret();
}
recordBCInstr(OpServiceRequest, astubs, retval);
translator_not_reached(astubs);
recordBCInstr(OpServiceRequest, as, retval);
translator_not_reached(as);
return retval;
}
+6 -4
Ver Arquivo
@@ -813,6 +813,7 @@ private:
TCA getInterceptHelper();
void translateInstr(const Tracelet& t, const NormalizedInstruction& i);
void translateInstrWork(const Tracelet& t, const NormalizedInstruction& i);
void irInterpretInstr(const NormalizedInstruction& i);
void irTranslateInstr(const Tracelet& t, const NormalizedInstruction& i);
void irTranslateInstrWork(const Tracelet& t, const NormalizedInstruction& i);
void irTranslateInstrDefault(const Tracelet& t,
@@ -926,10 +927,11 @@ private:
SrcRec& fail);
enum SRFlags {
SRNone = 0,
SRAlign = 1,
SRInline = 2,
SRJmpInsteadOfRet = 4
SRNone = 0,
SRAlign = 1,
SRInline = 2,
SRJmpInsteadOfRet = 4,
SREmitInA = 8,
};
TCA emitServiceReq(ServiceRequest, int numArgs, ...);
TCA emitServiceReq(SRFlags flags, ServiceRequest, int numArgs, ...);
+7
Ver Arquivo
@@ -360,6 +360,12 @@ class NormalizedInstruction {
*/
bool noOp:1;
/*
* Used with HHIR. Instruction shoud be interpreted, because previous attempt
* to translate it has failed.
*/
bool interp:1;
/*
* This is an FPush* that will be directly bound to a Func*
*/
@@ -407,6 +413,7 @@ class NormalizedInstruction {
noSurprise(false),
noCtor(false),
noOp(false),
interp(false),
directCall(false),
inlineReturn(false),
m_txFlags(Interp) {