Fix some bugs when we fail to get a translation
If we failed to get the translation for a cloned closure, we didnt clean the registers. VMRegAnchor::VMRegAncor(ActRec*,bool) didnt know how to set things up for continuations, and had an unused bool parameter. RetFromInterpretedFrame isnt suitable for returning from a generator - so just preserve m_savedRip across the doFCall.
Esse commit está contido em:
@@ -1790,7 +1790,14 @@ bool VMExecutionContext::prepareFuncEntry(ActRec *ar,
|
||||
func = ar->m_func;
|
||||
}
|
||||
|
||||
pushLocalsAndIterators(func, nlocals);
|
||||
if (LIKELY(!func->isGenerator())) {
|
||||
/*
|
||||
* we only get here from callAndResume
|
||||
* if we failed to get a translation for
|
||||
* a generator's prologue
|
||||
*/
|
||||
pushLocalsAndIterators(func, nlocals);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're reentering, make sure to finalize the ActRec before
|
||||
|
||||
@@ -90,27 +90,21 @@ struct VMRegAnchor : private boost::noncopyable {
|
||||
m_old = tl_regState;
|
||||
Translator::Get()->sync();
|
||||
}
|
||||
VMRegAnchor(ActRec* ar, bool atFCall=false) {
|
||||
VMRegAnchor(ActRec* ar) {
|
||||
// Some C++ entry points have an ActRec prepared from after a call
|
||||
// instruction. This syncs us to right after the call instruction.
|
||||
assert(tl_regState == REGSTATE_DIRTY);
|
||||
m_old = REGSTATE_DIRTY;
|
||||
tl_regState = REGSTATE_CLEAN;
|
||||
int numArgs = ar->numArgs();
|
||||
|
||||
const Func* prevF = ((ActRec*)(ar->m_savedRbp))->m_func;
|
||||
vmsp() = (TypedValue*)ar - numArgs;
|
||||
auto prevAr = (ActRec*)ar->m_savedRbp;
|
||||
const Func* prevF = prevAr->m_func;
|
||||
vmsp() = ar->m_func->isGenerator() ?
|
||||
Stack::generatorStackBase(ar) :
|
||||
(TypedValue*)ar - ar->numArgs();
|
||||
assert(g_vmContext->m_stack.isValidAddress((uintptr_t)vmsp()));
|
||||
vmpc() = prevF->unit()->at(prevF->base() + ar->m_soff);
|
||||
if (atFCall) {
|
||||
// VMExecutionContext::doFCall expects vmfp to be the caller's
|
||||
// ActRec, but if we call VMRegAnchor while executing the FCall
|
||||
// sequence (in TargetCache::callAndResume), we actually have the
|
||||
// callee's ActRec.
|
||||
vmfp() = (TypedValue*)ar->m_savedRbp;
|
||||
} else {
|
||||
vmfp() = (TypedValue*)ar;
|
||||
}
|
||||
vmfp() = (TypedValue*)prevAr;
|
||||
}
|
||||
~VMRegAnchor() {
|
||||
tl_regState = m_old;
|
||||
|
||||
@@ -78,6 +78,29 @@ void TranslatorX64::reqLitHelper(const ReqLitStaticArgs* args) {
|
||||
framePtr->m_savedRbp = (uint64_t)ec->m_fp;
|
||||
}
|
||||
|
||||
static void setupAfterProlog(ActRec* fp) {
|
||||
g_vmContext->m_fp = fp;
|
||||
g_vmContext->m_stack.top() = sp;
|
||||
int nargs = fp->numArgs();
|
||||
int nparams = fp->m_func->numParams();
|
||||
Offset firstDVInitializer = InvalidAbsoluteOffset;
|
||||
if (nargs < nparams) {
|
||||
const Func::ParamInfoVec& paramInfo = fp->m_func->params();
|
||||
for (int i = nargs; i < nparams; ++i) {
|
||||
Offset dvInitializer = paramInfo[i].funcletOff();
|
||||
if (dvInitializer != InvalidAbsoluteOffset) {
|
||||
firstDVInitializer = dvInitializer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstDVInitializer != InvalidAbsoluteOffset) {
|
||||
g_vmContext->m_pc = fp->m_func->unit()->entry() + firstDVInitializer;
|
||||
} else {
|
||||
g_vmContext->m_pc = fp->m_func->getEntry();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fcallHelperThunk--
|
||||
*
|
||||
@@ -93,10 +116,13 @@ static TCA callAndResume(ActRec *ar) {
|
||||
* array is just being used as entry points for the
|
||||
* dv funclets. Dont run the prolog again.
|
||||
*/
|
||||
VMRegAnchor _(ar, true);
|
||||
VMRegAnchor _(ar);
|
||||
uint64_t rip = ar->m_savedRip;
|
||||
g_vmContext->doFCall<true>(ar, g_vmContext->m_pc);
|
||||
ar->m_savedRip = rip;
|
||||
return Translator::Get()->getResumeHelperRet();
|
||||
}
|
||||
setupAfterProlog(ar);
|
||||
return Translator::Get()->getResumeHelper();
|
||||
}
|
||||
|
||||
@@ -218,34 +244,14 @@ asm (
|
||||
* neither requires different entry points for different callsite arities.
|
||||
*/
|
||||
TCA funcBodyHelper(ActRec* fp) {
|
||||
g_vmContext->m_fp = fp;
|
||||
g_vmContext->m_stack.top() = sp;
|
||||
int nargs = fp->numArgs();
|
||||
int nparams = fp->m_func->numParams();
|
||||
Offset firstDVInitializer = InvalidAbsoluteOffset;
|
||||
if (nargs < nparams) {
|
||||
const Func::ParamInfoVec& paramInfo = fp->m_func->params();
|
||||
for (int i = nargs; i < nparams; ++i) {
|
||||
Offset dvInitializer = paramInfo[i].funcletOff();
|
||||
if (dvInitializer != InvalidAbsoluteOffset) {
|
||||
firstDVInitializer = dvInitializer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (firstDVInitializer != InvalidAbsoluteOffset) {
|
||||
g_vmContext->m_pc = fp->m_func->unit()->entry() + firstDVInitializer;
|
||||
} else {
|
||||
g_vmContext->m_pc = fp->m_func->getEntry();
|
||||
}
|
||||
setupAfterProlog(fp);
|
||||
tl_regState = REGSTATE_CLEAN;
|
||||
Func* func = const_cast<Func*>(fp->m_func);
|
||||
SrcKey sk(func, func->base());
|
||||
|
||||
TCA tca;
|
||||
if (func->isGenerator()) {
|
||||
assert(nargs == 1);
|
||||
tca = tx64->funcPrologue(func, nargs);
|
||||
assert(fp->numArgs() == 1);
|
||||
tca = tx64->funcPrologue(func, 1);
|
||||
} else {
|
||||
tca = tx64->getCallArrayProlog(func);
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário