Consolidate ContDone into ContRetC

Merge ContDone+ContExit into ContRetC with added support of passing results. This variable passing mechanism is not exposed to the PHP as the ReturnStatements in generators do not contain result expression. However, this is exposed by restored hphp_continuation_done() built-in to allow experimentation.

The idea is that once we introduce ContYield opcode (merge of all opcodes used by YieldExpression), we could change ContRetC and ContYield to leave result and done-status on the stack and leave it up to the caller (ContNext/ContSend/ContRaise) to fill in Continuation fields. This will make these opcodes more generic and useful for other things, while allowing us to move some properties to the VM and kill opcodes like ContCurrent.
Esse commit está contido em:
jan
2013-03-15 13:19:52 -07:00
commit de Sara Golemon
commit 20b8aeea2f
11 arquivos alterados com 74 adições e 38 exclusões
+21 -13
Ver Arquivo
@@ -2180,12 +2180,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
case Statement::KindOfReturnStatement: {
ReturnStatementPtr r(static_pointer_cast<ReturnStatement>(node));
bool retV = false;
if (m_curFunc->isGenerator()) {
assert(m_evalStack.size() == 0);
e.ContDone();
e.ContExit();
return false;
}
if (visit(r->getRetExp())) {
if (r->getRetExp()->getContext() & Expression::RefValue) {
emitConvertToVar(e);
@@ -2199,6 +2193,16 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
emitFreePendingIters(e);
e.Null();
}
if (m_curFunc->isGenerator()) {
assert(!retV);
m_metaInfo.addKnownDataType(
KindOfObject, false, m_ue.bcPos(), false, 1);
assert(m_evalStack.size() == 1);
e.ContRetC();
return false;
}
if (r->isGuarded()) {
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::GuardedThis,
false, 0, 0);
@@ -3163,9 +3167,12 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
e.CreateCont(callGetArgs, nameStr);
return true;
} else if (call->isCompilerCallToFunction("hphp_continuation_done")) {
inputIsAnObject(0);
e.ContDone();
e.ContExit();
assert(params && params->getCount() == 1);
visit((*params)[0]);
emitConvertToCell(e);
inputIsAnObject(1);
assert(m_evalStack.size() == 1);
e.ContRetC();
e.Null();
return true;
} else if ((call->isCallToFunction("class_exists") ||
@@ -5379,12 +5386,13 @@ void EmitterVisitor::emitPostponedMeths() {
// If the current position in the bytecode is reachable, emit code to
// return null
if (currentPositionIsReachable()) {
e.Null();
if (p.m_meth->getFunctionScope()->isGenerator()) {
assert(m_evalStack.size() == 0);
e.ContDone();
e.ContExit();
m_metaInfo.addKnownDataType(
KindOfObject, false, m_ue.bcPos(), false, 1);
assert(m_evalStack.size() == 1);
e.ContRetC();
} else {
e.Null();
if ((p.m_meth->getStmts() && p.m_meth->getStmts()->isGuarded())) {
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::GuardedThis,
false, 0, 0);
+5 -3
Ver Arquivo
@@ -3650,10 +3650,12 @@ ContReceive [] -> [C]
sent to the continuation will be pushed on the stack. The value will be no
longer referenced by the Continuation object.
ContDone [] -> []
ContRetC [C] -> []
Finish continuation. Marks the continuation in local 0 as finished. Further
attempts to iterate it will fail.
Return from continuation. Marks the continuation in local 0 as finished, sets
the result and transfers control flow to the caller of the continuation body,
which must be a non-static method of the Continuation class. Further attempts
to iterate it will fail.
ContNext [] -> []
+8 -2
Ver Arquivo
@@ -6893,11 +6893,17 @@ inline void OPTBLD_INLINE VMExecutionContext::iopContReceive(PC& pc) {
tvWriteUninit(fr);
}
inline void OPTBLD_INLINE VMExecutionContext::iopContDone(PC& pc) {
inline void OPTBLD_INLINE VMExecutionContext::iopContRetC(PC& pc) {
NEXT();
c_Continuation* cont = frame_continuation(m_fp);
cont->m_done = true;
cont->m_value.setNull();
tvSetIgnoreRef(m_stack.topC(), cont->m_value.asTypedValue());
m_stack.popC();
EventHook::FunctionExit(m_fp);
ActRec* prevFp = arGetSfp(m_fp);
pc = prevFp->m_func->getEntry() + m_fp->m_soff;
m_fp = prevFp;
}
inline void OPTBLD_INLINE VMExecutionContext::iopContNext(PC& pc) {
+1 -1
Ver Arquivo
@@ -557,7 +557,7 @@ enum SetOpOp {
O(UnpackCont, NA, NOV, ONE(CV), NF) \
O(PackCont, ONE(IVA), ONE(CV), NOV, NF) \
O(ContReceive, NA, NOV, ONE(CV), NF) \
O(ContDone, NA, NOV, NOV, NF) \
O(ContRetC, NA, ONE(CV), NOV, CF_TF) \
O(ContNext, NA, NOV, NOV, NF) \
O(ContSend, NA, NOV, NOV, NF) \
O(ContRaise, NA, NOV, NOV, NF) \
@@ -714,8 +714,7 @@ void HhbcTranslator::emitContEnter(int32_t returnBcOffset) {
assert(m_stackDeficit == 0);
}
void HhbcTranslator::emitContExit() {
m_tb->genExitWhenSurprised(getExitSlowTrace());
void HhbcTranslator::emitContExitImpl() {
SSATmp* retAddr = m_tb->genLdRetAddr();
// Despite the name, this doesn't actually free the AR; it updates the
// hardware fp and returns the old one
@@ -734,6 +733,11 @@ void HhbcTranslator::emitContExit() {
m_hasExit = true;
}
void HhbcTranslator::emitContExit() {
m_tb->genExitWhenSurprised(getExitSlowTrace());
emitContExitImpl();
}
void HhbcTranslator::emitUnpackCont() {
m_tb->genLinkContVarEnv();
SSATmp* cont = m_tb->genLdAssertedLoc(0, Type::Obj);
@@ -756,10 +760,14 @@ void HhbcTranslator::emitContReceive() {
m_tb->genStProp(cont, valOffset, m_tb->genDefUninit(), true);
}
void HhbcTranslator::emitContDone() {
void HhbcTranslator::emitContRetC() {
SSATmp* cont = m_tb->genLdAssertedLoc(0, Type::Obj);
m_tb->genExitWhenSurprised(getExitSlowTrace());
m_tb->genStRaw(cont, RawMemSlot::ContDone, m_tb->genDefConst(true));
m_tb->genSetPropCell(cont, CONTOFF(m_value), m_tb->genDefInitNull());
m_tb->genSetPropCell(cont, CONTOFF(m_value), popC());
// transfer control
emitContExitImpl();
}
void HhbcTranslator::emitContNext() {
@@ -327,11 +327,12 @@ struct HhbcTranslator {
// continuations
void emitCreateCont(bool getArgs, Id funNameStrId);
void emitContEnter(int32_t returnBcOffset);
void emitContExitImpl();
void emitContExit();
void emitUnpackCont();
void emitPackCont(int64_t labelId);
void emitContReceive();
void emitContDone();
void emitContRetC();
void emitContNext();
void emitContSendImpl(bool raise);
void emitContSend();
@@ -633,9 +633,9 @@ void TranslatorX64::irTranslateContReceive(const Tracelet& t,
HHIR_EMIT(ContReceive);
}
void TranslatorX64::irTranslateContDone(const Tracelet& t,
void TranslatorX64::irTranslateContRetC(const Tracelet& t,
const NormalizedInstruction& i) {
HHIR_EMIT(ContDone);
HHIR_EMIT(ContRetC);
}
void TranslatorX64::irTranslateContNext(const Tracelet& t,
+18 -9
Ver Arquivo
@@ -7565,10 +7565,7 @@ void TranslatorX64::translateContEnter(const Tracelet& t,
a. call (rax);
}
void TranslatorX64::translateContExit(const Tracelet& t,
const NormalizedInstruction& i) {
syncOutputs(i);
void TranslatorX64::emitContExit() {
emitTestSurpriseFlags(a);
{
UnlikelyIfBlock ifTracer(CC_NZ, a, astubs);
@@ -7581,13 +7578,25 @@ void TranslatorX64::translateContExit(const Tracelet& t,
a. ret ();
}
void TranslatorX64::translateContDone(const Tracelet& t,
void TranslatorX64::translateContExit(const Tracelet& t,
const NormalizedInstruction& i) {
PhysReg contReg = getReg(i.inputs[0]->location);
syncOutputs(i);
emitContExit();
}
void TranslatorX64::translateContRetC(const Tracelet& t,
const NormalizedInstruction& i) {
PhysReg valueReg = getReg(i.inputs[0]->location);
PhysReg contReg = getReg(i.inputs[1]->location);
a. store_imm8_disp_reg(0x1, CONTOFF(m_done), contReg);
// m_value.setNull()
emitTvSet(i, InvalidReg, KindOfNull, contReg, CONTOFF(m_value), false);
// m_value = $1
emitTvSet(i, valueReg, i.inputs[0]->outerType(),
contReg, CONTOFF(m_value), false);
// transfer control
syncOutputs(i.stackOff - 1);
emitContExit();
}
static void contPreNextThrowHelper(c_Continuation* c) {
@@ -12429,8 +12438,8 @@ bool TranslatorX64::dumpTCData() {
SUPPORTED_OP(BareThis) \
SUPPORTED_OP(CheckThis) \
SUPPORTED_OP(PackCont) \
SUPPORTED_OP(ContDone) \
SUPPORTED_OP(ContReceive) \
SUPPORTED_OP(ContRetC) \
SUPPORTED_OP(ContNext) \
SUPPORTED_OP(ContSend) \
SUPPORTED_OP(ContRaise) \
+2 -1
Ver Arquivo
@@ -275,6 +275,7 @@ private:
void emitCallFillCont(Asm& a, const Func* orig, const Func* gen);
void emitCallPack(Asm& a, const NormalizedInstruction& i);
void emitContRaiseCheck(Asm& a, const NormalizedInstruction& i);
void emitContExit();
void emitContPreNext(const NormalizedInstruction& i, ScratchReg& rCont);
void emitContStartedCheck(const NormalizedInstruction& i, ScratchReg& rCont);
template<bool raise>
@@ -594,7 +595,7 @@ MINSTRS
CASE(UnpackCont) \
CASE(PackCont) \
CASE(ContReceive) \
CASE(ContDone) \
CASE(ContRetC) \
CASE(ContNext) \
CASE(ContSend) \
CASE(ContRaise) \
+2 -2
Ver Arquivo
@@ -1202,7 +1202,7 @@ static const struct {
{ OpUnpackCont, {Local, Stack1, OutInt64, 1 }},
{ OpPackCont, {Local|Stack1, None, OutNone, -1 }},
{ OpContReceive, {Local, Stack1, OutUnknown, 1 }},
{ OpContDone, {Local, None, OutNone, 0 }},
{ OpContRetC, {Local|Stack1, None, OutNone, -1 }},
{ OpContNext, {None, None, OutNone, 0 }},
{ OpContSend, {Local, None, OutNone, 0 }},
{ OpContRaise, {Local, None, OutNone, 0 }},
@@ -1959,7 +1959,7 @@ void Translator::getInputs(Tracelet& t,
case OpUnpackCont:
case OpPackCont:
case OpContReceive:
case OpContDone:
case OpContRetC:
case OpContSend:
case OpContRaise:
loc = 0;
+1
Ver Arquivo
@@ -1042,6 +1042,7 @@ opcodeControlFlowInfo(const Opcode instr) {
case OpSwitch:
case OpSSwitch:
case OpContExit:
case OpContRetC:
case OpRetC:
case OpRetV:
case OpExit: