Move Continuation state check to ContCheck opcode
Add ContCheck opcode that moves away responsibility of checking
Continuation status from Cont{Next,Send,Raise} opcodes.
This check needs to run outside of try/catch in next()/send()/raise()
methods and moving it to a separate opcode lets us merge
Cont{Next,Send,Raise} with ContEnter.
Esse commit está contido em:
@@ -7010,13 +7010,17 @@ static void emitContinuationMethod(UnitEmitter& ue, FuncEmitter* fe,
|
||||
// translations
|
||||
fe->setAttrs(Attr(fe->attrs() | AttrClone));
|
||||
|
||||
// check continuation status; send()/raise() also checks started
|
||||
ue.emitOp(OpContCheck);
|
||||
ue.emitIVA(m == METH_SEND || m == METH_RAISE);
|
||||
|
||||
const Offset ehStart = ue.bcPos();
|
||||
static Op mOps[] = {
|
||||
OpContNext,
|
||||
OpContSend,
|
||||
OpContRaise,
|
||||
};
|
||||
ue.emitOp(mOps[m]);
|
||||
const Offset ehStart = ue.bcPos();
|
||||
ue.emitOp(OpContEnter);
|
||||
ue.emitOp(OpContStopped);
|
||||
ue.emitOp(OpNull);
|
||||
|
||||
@@ -3720,24 +3720,28 @@ ContRetC [C] -> []
|
||||
which must be a non-static method of the Continuation class. Further attempts
|
||||
to iterate it will fail.
|
||||
|
||||
ContCheck <check started> [] -> []
|
||||
|
||||
Check whether continuation can be iterated. $this must be a Continuation
|
||||
object. If the continuation is finished, already running, or not yet started
|
||||
and <check started> is enabled, an exception will be thrown.
|
||||
|
||||
ContNext [] -> []
|
||||
|
||||
Prepare continuation for iteration. $this must be a Continuation
|
||||
object. If the continuation is finished or already running, an exception
|
||||
will be thrown.
|
||||
Prepare continuation for iteration. $this must be a Continuation object
|
||||
that passed ContCheck<false> check.
|
||||
|
||||
ContSend [] -> []
|
||||
|
||||
Prepare continuation to receive a value. $this must be a Continuation
|
||||
object. If the continuation is finished or already running, an exception will
|
||||
be thrown. Otherwise, the value in local 0 is stored in the continuation.
|
||||
Prepare continuation to receive a value. $this must be a Continuation object
|
||||
that passed ContCheck<true> check. The value in local 0 is stored in the
|
||||
continuation.
|
||||
|
||||
ContRaise [] -> []
|
||||
|
||||
Prepare continuation to receive a thrown exception. $this must be a
|
||||
Continuation object. If the continuation is finished or already running, an
|
||||
exception will be thrown. Otherwise, the exception in local 0 is stored in
|
||||
the continuation.
|
||||
Continuation object that passed ContCheck<true> check. The exception in
|
||||
local 0 is stored in the continuation.
|
||||
|
||||
ContValid [] -> [C:Bool]
|
||||
|
||||
|
||||
@@ -492,8 +492,6 @@ private:
|
||||
OPCODES
|
||||
#undef O
|
||||
|
||||
template<bool raise>
|
||||
void contSendImpl();
|
||||
void classExistsImpl(PC& pc, Attr typeAttr);
|
||||
void fPushObjMethodImpl(
|
||||
Class* cls, StringData* name, ObjectData* obj, int numArgs);
|
||||
|
||||
@@ -6853,33 +6853,34 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContRetC(PC& pc) {
|
||||
m_fp = prevFp;
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopContCheck(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IVA(check_started);
|
||||
c_Continuation* cont = this_continuation(m_fp);
|
||||
if (check_started) {
|
||||
cont->startedCheck();
|
||||
}
|
||||
cont->preNext();
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopContNext(PC& pc) {
|
||||
NEXT();
|
||||
c_Continuation* cont = this_continuation(m_fp);
|
||||
cont->preNext();
|
||||
cont->m_received.setNull();
|
||||
}
|
||||
|
||||
template<bool raise>
|
||||
inline void VMExecutionContext::contSendImpl() {
|
||||
c_Continuation* cont = this_continuation(m_fp);
|
||||
cont->startedCheck();
|
||||
cont->preNext();
|
||||
cont->m_received.assignVal(tvAsVariant(frame_local(m_fp, 0)));
|
||||
if (raise) {
|
||||
assert(cont->m_label);
|
||||
--cont->m_label;
|
||||
}
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopContSend(PC& pc) {
|
||||
NEXT();
|
||||
contSendImpl<false>();
|
||||
c_Continuation* cont = this_continuation(m_fp);
|
||||
cont->m_received.assignVal(tvAsVariant(frame_local(m_fp, 0)));
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopContRaise(PC& pc) {
|
||||
NEXT();
|
||||
contSendImpl<true>();
|
||||
c_Continuation* cont = this_continuation(m_fp);
|
||||
cont->m_received.assignVal(tvAsVariant(frame_local(m_fp, 0)));
|
||||
assert(cont->m_label);
|
||||
--cont->m_label;
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopContValid(PC& pc) {
|
||||
|
||||
@@ -552,6 +552,7 @@ enum SetOpOp {
|
||||
O(UnpackCont, NA, NOV, TWO(CV,CV), NF) \
|
||||
O(PackCont, ONE(IVA), ONE(CV), NOV, NF) \
|
||||
O(ContRetC, NA, ONE(CV), NOV, CF_TF) \
|
||||
O(ContCheck, ONE(IVA), NOV, NOV, NF) \
|
||||
O(ContNext, NA, NOV, NOV, NF) \
|
||||
O(ContSend, NA, NOV, NOV, NF) \
|
||||
O(ContRaise, NA, NOV, NOV, NF) \
|
||||
|
||||
@@ -1155,10 +1155,18 @@ void HhbcTranslator::emitContRetC() {
|
||||
emitContExitImpl();
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitContCheck(bool checkStarted) {
|
||||
assert(curClass());
|
||||
SSATmp* cont = gen(LdThis, m_tb->fp());
|
||||
if (checkStarted) {
|
||||
gen(ContStartedCheck, getExitSlowTrace(), cont);
|
||||
}
|
||||
gen(ContPreNext, getExitSlowTrace(), cont);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitContNext() {
|
||||
assert(curClass());
|
||||
SSATmp* cont = gen(LdThis, m_tb->fp());
|
||||
gen(ContPreNext, getExitSlowTrace(), cont);
|
||||
if (RuntimeOption::EvalHHIRGenerateAsserts) {
|
||||
// We're guaranteed to have a Null in m_received at this point
|
||||
auto const oldVal = gen(LdProp, Type::Cell, cont, cns(CONTOFF(m_received)));
|
||||
@@ -1169,8 +1177,6 @@ void HhbcTranslator::emitContNext() {
|
||||
void HhbcTranslator::emitContSendImpl(bool raise) {
|
||||
assert(curClass());
|
||||
SSATmp* cont = gen(LdThis, m_tb->fp());
|
||||
gen(ContStartedCheck, getExitSlowTrace(), cont);
|
||||
gen(ContPreNext, getExitSlowTrace(), cont);
|
||||
gen(AssertLoc, Type::Cell, LocalId(0), m_tb->fp());
|
||||
auto const newVal = gen(IncRef, ldLoc(0));
|
||||
if (RuntimeOption::EvalHHIRGenerateAsserts) {
|
||||
|
||||
@@ -380,6 +380,7 @@ struct HhbcTranslator {
|
||||
void emitUnpackCont();
|
||||
void emitPackCont(int64_t labelId);
|
||||
void emitContRetC();
|
||||
void emitContCheck(bool checkStarted);
|
||||
void emitContNext();
|
||||
void emitContSendImpl(bool raise);
|
||||
void emitContSend();
|
||||
|
||||
@@ -564,6 +564,10 @@ void Translator::translateContRetC(const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(ContRetC);
|
||||
}
|
||||
|
||||
void Translator::translateContCheck(const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(ContCheck, i.imm[0].u_IVA);
|
||||
}
|
||||
|
||||
void Translator::translateContNext(const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(ContNext);
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
CASE(UnpackCont) \
|
||||
CASE(PackCont) \
|
||||
CASE(ContRetC) \
|
||||
CASE(ContCheck) \
|
||||
CASE(ContNext) \
|
||||
CASE(ContSend) \
|
||||
CASE(ContRaise) \
|
||||
|
||||
@@ -1269,6 +1269,7 @@ static const struct {
|
||||
{ OpUnpackCont, {Local, StackTop2, OutInt64, 2 }},
|
||||
{ OpPackCont, {Local|Stack1, None, OutNone, -1 }},
|
||||
{ OpContRetC, {Local|Stack1, None, OutNone, -1 }},
|
||||
{ OpContCheck, {None, None, OutNone, 0 }},
|
||||
{ OpContNext, {None, None, OutNone, 0 }},
|
||||
{ OpContSend, {Local, None, OutNone, 0 }},
|
||||
{ OpContRaise, {Local, None, OutNone, 0 }},
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário