Remove Continuation from local 0
No emitted bytecode relies on Continuation being stored in local 0 anymore. Stop using local 0 for this purpose and compute offset to the Continuation at JIT time. 16 bytes of memory freed. At this point all locals of Continuation construction wrapper share the same indices with their respective locals of Continuation body, which should allow further optimizations.
Esse commit está contido em:
Arquivo normal → Arquivo executável
+1
-15
@@ -2243,8 +2243,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
|
||||
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;
|
||||
@@ -3147,10 +3145,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
SimpleFunctionCallPtr call(
|
||||
static_pointer_cast<SimpleFunctionCall>(node));
|
||||
ExpressionListPtr params = call->getParams();
|
||||
auto inputIsAnObject = [&](int inputIndex) {
|
||||
m_metaInfo.addKnownDataType(KindOfObject, /* predicted */ false,
|
||||
m_ue.bcPos(), false, inputIndex);
|
||||
};
|
||||
|
||||
if (call->isFatalFunction()) {
|
||||
if (params && params->getCount() == 1) {
|
||||
@@ -3241,7 +3235,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
} else if (call->isCompilerCallToFunction("hphp_unpack_continuation")) {
|
||||
assert(!params || params->getCount() == 0);
|
||||
int yieldLabelCount = call->getFunctionScope()->getYieldLabelCount();
|
||||
inputIsAnObject(0);
|
||||
emitContinuationSwitch(e, yieldLabelCount);
|
||||
return false;
|
||||
} else if (call->isCompilerCallToFunction("hphp_create_continuation")) {
|
||||
@@ -3273,7 +3266,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
assert(params && params->getCount() == 1);
|
||||
visit((*params)[0]);
|
||||
emitConvertToCell(e);
|
||||
inputIsAnObject(1);
|
||||
assert(m_evalStack.size() == 1);
|
||||
e.ContRetC();
|
||||
e.Null();
|
||||
@@ -3971,16 +3963,12 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
int64_t normalLabel = 2 * y->getLabel();
|
||||
int64_t exceptLabel = normalLabel - 1;
|
||||
|
||||
// pack continuation and set the return label
|
||||
// suspend continuation and set the return label
|
||||
if (keyExp) {
|
||||
assert(m_evalStack.size() == 2);
|
||||
m_metaInfo.addKnownDataType(
|
||||
KindOfObject, false, m_ue.bcPos(), false, 2);
|
||||
e.ContSuspendK(normalLabel);
|
||||
} else {
|
||||
assert(m_evalStack.size() == 1);
|
||||
m_metaInfo.addKnownDataType(
|
||||
KindOfObject, false, m_ue.bcPos(), false, 1);
|
||||
e.ContSuspend(normalLabel);
|
||||
}
|
||||
|
||||
@@ -5620,8 +5608,6 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
if (currentPositionIsReachable()) {
|
||||
e.Null();
|
||||
if (p.m_meth->getFunctionScope()->isGenerator()) {
|
||||
m_metaInfo.addKnownDataType(
|
||||
KindOfObject, false, m_ue.bcPos(), false, 1);
|
||||
assert(m_evalStack.size() == 1);
|
||||
e.ContRetC();
|
||||
} else {
|
||||
|
||||
@@ -344,10 +344,7 @@ bool FunctionScope::isClosure() const {
|
||||
}
|
||||
|
||||
bool FunctionScope::isGenerator() const {
|
||||
assert(!getOrigGenStmt() ||
|
||||
(ParserBase::IsContinuationName(name()) &&
|
||||
m_paramNames.size() == 1 &&
|
||||
m_paramNames[0] == CONTINUATION_OBJECT_NAME));
|
||||
assert(!getOrigGenStmt() || ParserBase::IsContinuationName(name()));
|
||||
return !!getOrigGenStmt();
|
||||
}
|
||||
|
||||
|
||||
@@ -105,15 +105,6 @@ void SimpleVariable::coalesce(SimpleVariablePtr other) {
|
||||
m_name = m_sym->getName();
|
||||
}
|
||||
|
||||
string SimpleVariable::getNamePrefix() const {
|
||||
bool needsCont = getFunctionScope()->isGenerator();
|
||||
bool isHidden = m_sym && m_sym->isHidden();
|
||||
return (needsCont &&
|
||||
m_name != CONTINUATION_OBJECT_NAME &&
|
||||
!isHidden) ?
|
||||
string(TYPED_CONTINUATION_OBJECT_NAME) + "->" : string("");
|
||||
}
|
||||
|
||||
/*
|
||||
This simple variable is about to go out of scope.
|
||||
Is it ok to kill the last assignment?
|
||||
|
||||
@@ -59,8 +59,6 @@ public:
|
||||
void updateSymbol(SimpleVariablePtr src);
|
||||
void coalesce(SimpleVariablePtr other);
|
||||
private:
|
||||
std::string getNamePrefix() const;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_docComment;
|
||||
|
||||
|
||||
+805
-814
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -113,7 +113,7 @@
|
||||
|
||||
using namespace HPHP::Compiler;
|
||||
|
||||
extern void prepare_generator(Parser *_p, Token &stmt, Token ¶ms);
|
||||
extern void prepare_generator(Parser *_p, Token &stmt);
|
||||
extern void create_generator(Parser *_p, Token &out, Token ¶ms,
|
||||
Token &name, const std::string &genName,
|
||||
const char *clsname, Token *modifiers,
|
||||
@@ -844,12 +844,10 @@ void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
|
||||
if (funcContext.isGenerator) {
|
||||
string genName = newContinuationName(funcName);
|
||||
|
||||
Token new_params;
|
||||
prepare_generator(this, stmt, new_params);
|
||||
prepare_generator(this, stmt);
|
||||
|
||||
func = NEW_STMT(FunctionStatement, exp, ref->num(), genName,
|
||||
dynamic_pointer_cast<ExpressionList>(new_params->exp),
|
||||
ret.typeAnnotationName(),
|
||||
ExpressionListPtr(), ret.typeAnnotationName(),
|
||||
dynamic_pointer_cast<StatementList>(stmt->stmt),
|
||||
attribute, comment, ExpressionListPtr());
|
||||
out->stmt = func;
|
||||
@@ -1225,12 +1223,10 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
||||
genName = newContinuationName(funcName + "@" + m_clsName);
|
||||
}
|
||||
|
||||
Token new_params;
|
||||
prepare_generator(this, stmt, new_params);
|
||||
prepare_generator(this, stmt);
|
||||
ModifierExpressionPtr exp2 = Construct::Clone(exp);
|
||||
mth = NEW_STMT(MethodStatement, exp2, ref->num(), genName,
|
||||
dynamic_pointer_cast<ExpressionList>(new_params->exp),
|
||||
ret.typeAnnotationName(),
|
||||
ExpressionListPtr(), ret.typeAnnotationName(),
|
||||
dynamic_pointer_cast<StatementList>(stmt->stmt),
|
||||
attribute, comment, ExpressionListPtr());
|
||||
out->stmt = mth;
|
||||
|
||||
@@ -380,9 +380,6 @@ void MethodStatement::analyzeProgram(AnalysisResultPtr ar) {
|
||||
MethodStatementRawPtr orig = getOrigGeneratorFunc();
|
||||
VariableTablePtr variables = funcScope->getVariables();
|
||||
|
||||
Symbol *cont = variables->getSymbol(CONTINUATION_OBJECT_NAME);
|
||||
cont->setHidden();
|
||||
|
||||
orig->getFunctionScope()->addUse(funcScope, BlockScope::UseKindClosure);
|
||||
orig->getFunctionScope()->setContainsBareThis(
|
||||
funcScope->containsBareThis(), funcScope->containsRefThis());
|
||||
|
||||
@@ -245,10 +245,7 @@ void CmdNext::cleanupStepCont() {
|
||||
// continuation, or we'll stop when we get back into it, we know the object
|
||||
// will remain alive.
|
||||
void* CmdNext::getContinuationTag(ActRec* fp) {
|
||||
TypedValue* tv = frame_local(fp, 0);
|
||||
assert(tv->m_type == HPHP::KindOfObject);
|
||||
assert(dynamic_cast<c_Continuation*>(tv->m_data.pobj));
|
||||
c_Continuation* cont = static_cast<c_Continuation*>(tv->m_data.pobj);
|
||||
c_Continuation* cont = frame_continuation(fp);
|
||||
TRACE(2, "CmdNext: continuation tag %p for %s\n", cont,
|
||||
cont->t_getorigfuncname()->data());
|
||||
return cont;
|
||||
|
||||
Arquivo normal → Arquivo executável
+1
-14
@@ -42,8 +42,6 @@ p_Continuation f_hphp_create_continuation(CStrRef clsname,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static StaticString s___cont__("__cont__");
|
||||
|
||||
c_Continuation::c_Continuation(Class* cb)
|
||||
: ExtObjectData(cb)
|
||||
, m_label(0)
|
||||
@@ -57,13 +55,6 @@ c_Continuation::c_Continuation(Class* cb)
|
||||
c_Continuation::~c_Continuation() {
|
||||
ActRec* ar = actRec();
|
||||
|
||||
// The first local is the object itself, and it wasn't increffed at creation
|
||||
// time (see createContinuation()). Overwrite its type to exempt it from
|
||||
// refcounting here.
|
||||
TypedValue* contLocal = frame_local(ar, 0);
|
||||
assert(contLocal->m_data.pobj == this);
|
||||
contLocal->m_type = KindOfNull;
|
||||
|
||||
if (ar->hasVarEnv()) {
|
||||
ar->getVarEnv()->detach(ar);
|
||||
} else {
|
||||
@@ -191,17 +182,13 @@ void c_Continuation::copyContinuationVars(ActRec* fp) {
|
||||
skipThis = definedVariables.exists(s_this, true);
|
||||
|
||||
for (ArrayIter iter(definedVariables); !iter.end(); iter.next()) {
|
||||
if (iter.first().getStringData()->same(s___cont__.get())) {
|
||||
continue;
|
||||
}
|
||||
dupContVar(iter.first().getStringData(),
|
||||
const_cast<TypedValue *>(iter.secondRef().asTypedValue()));
|
||||
}
|
||||
} else {
|
||||
const Func *genFunc = actRec()->m_func;
|
||||
skipThis = genFunc->lookupVarId(thisStr) != kInvalidId;
|
||||
// skip local 0 because that's the old continuation
|
||||
for (Id i = 1; i < genFunc->numNamedLocals(); ++i) {
|
||||
for (Id i = 0; i < genFunc->numNamedLocals(); ++i) {
|
||||
dupContVar(genFunc->localVarName(i), frame_local(fp, i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2067,10 +2067,7 @@ Array VMExecutionContext::debugBacktrace(bool skip /* = false */,
|
||||
String funcname = const_cast<StringData*>(fp->m_func->name());
|
||||
if (fp->m_func->isGenerator()) {
|
||||
// retrieve the original function name from the inner continuation
|
||||
TypedValue* tv = frame_local(fp, 0);
|
||||
assert(tv->m_type == HPHP::KindOfObject);
|
||||
funcname = static_cast<c_Continuation*>(
|
||||
tv->m_data.pobj)->t_getorigfuncname();
|
||||
funcname = frame_continuation(fp)->t_getorigfuncname();
|
||||
}
|
||||
|
||||
if (fp->m_func->isClosureBody()) {
|
||||
@@ -6605,17 +6602,9 @@ static inline c_Continuation* createCont(const Func* origFunc,
|
||||
// we enter the generator body.
|
||||
ActRec* ar = cont->actRec();
|
||||
ar->m_func = genFunc;
|
||||
ar->initNumArgs(1);
|
||||
ar->initNumArgs(0);
|
||||
ar->setVarEnv(nullptr);
|
||||
|
||||
TypedValue* contLocal = frame_local(ar, 0);
|
||||
contLocal->m_type = KindOfObject;
|
||||
contLocal->m_data.pobj = cont;
|
||||
// Do not incref the continuation here! Doing so will create a reference
|
||||
// cycle, since this reference is a local in the continuation frame and thus
|
||||
// will be decreffed when the continuation is destroyed. The corresponding
|
||||
// non-decref is in ~c_Continuation.
|
||||
|
||||
return cont;
|
||||
}
|
||||
|
||||
@@ -6728,13 +6717,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCreateCont(PC& pc) {
|
||||
ret->m_data.pobj = cont;
|
||||
}
|
||||
|
||||
static inline c_Continuation* frame_continuation(ActRec* fp) {
|
||||
ObjectData* obj = frame_local(fp, 0)->m_data.pobj;
|
||||
assert(dynamic_cast<c_Continuation*>(obj));
|
||||
return static_cast<c_Continuation*>(obj);
|
||||
}
|
||||
|
||||
static inline c_Continuation* this_continuation(ActRec* fp) {
|
||||
static inline c_Continuation* this_continuation(const ActRec* fp) {
|
||||
ObjectData* obj = fp->getThis();
|
||||
assert(dynamic_cast<c_Continuation*>(obj));
|
||||
return static_cast<c_Continuation*>(obj);
|
||||
|
||||
Arquivo normal → Arquivo executável
@@ -899,7 +899,7 @@ class RawMemSlot {
|
||||
}
|
||||
static RawMemSlot& GetContEntry() {
|
||||
static RawMemSlot m(
|
||||
Func::prologueTableOff() + sizeof(HPHP::Transl::TCA),
|
||||
Func::prologueTableOff(),
|
||||
Transl::sz::qword, Type::TCA);
|
||||
return m;
|
||||
}
|
||||
|
||||
Arquivo normal → Arquivo executável
+6
-14
@@ -1266,10 +1266,10 @@ static const struct {
|
||||
|
||||
{ OpCreateCont, {None, Stack1, OutObject, 1 }},
|
||||
{ OpContEnter, {Stack1, None, OutNone, -1 }},
|
||||
{ OpUnpackCont, {Local, StackTop2, OutInt64, 2 }},
|
||||
{ OpContSuspend, {Local|Stack1, None, OutNone, -1 }},
|
||||
{ OpContSuspendK,{Local|StackTop2, None, OutNone, -2 }},
|
||||
{ OpContRetC, {Local|Stack1, None, OutNone, -1 }},
|
||||
{ OpUnpackCont, {None, StackTop2, OutInt64, 2 }},
|
||||
{ OpContSuspend, {Stack1, None, OutNone, -1 }},
|
||||
{ OpContSuspendK,{StackTop2, None, OutNone, -2 }},
|
||||
{ OpContRetC, {Stack1, None, OutNone, -1 }},
|
||||
{ OpContCheck, {None, None, OutNone, 0 }},
|
||||
{ OpContRaise, {None, None, OutNone, 0 }},
|
||||
{ OpContValid, {None, Stack1, OutBoolean, 1 }},
|
||||
@@ -1862,19 +1862,11 @@ void getInputsImpl(SrcKey startSk,
|
||||
addMVectorInputs(*ni, currentStackOffset, inputs);
|
||||
}
|
||||
if (input & Local) {
|
||||
// Many of the continuation instructions read local 0. All other
|
||||
// instructions that take a Local have its index at their first
|
||||
// All instructions that take a Local have its index at their first
|
||||
// immediate.
|
||||
int loc;
|
||||
auto insertAt = inputs.end();
|
||||
switch (ni->op()) {
|
||||
case OpUnpackCont:
|
||||
case OpContSuspend:
|
||||
case OpContSuspendK:
|
||||
case OpContRetC:
|
||||
loc = 0;
|
||||
break;
|
||||
|
||||
case OpSetWithRefLM:
|
||||
insertAt = inputs.begin();
|
||||
// fallthrough
|
||||
@@ -2751,7 +2743,7 @@ Translator::getOperandConstraintCategory(NormalizedInstruction* instr,
|
||||
case OpContSuspendK:
|
||||
case OpContRetC:
|
||||
// The stack input is teleported to the continuation's m_value field
|
||||
return opndIdx == 0 ? DataTypeGeneric : DataTypeSpecific;
|
||||
return DataTypeGeneric;
|
||||
|
||||
case OpContHandle:
|
||||
// This always calls the interpreter
|
||||
|
||||
@@ -360,11 +360,8 @@ HphpArray* get_static_locals(const ActRec* ar) {
|
||||
assert(dynamic_cast<c_Closure*>(closureLoc->m_data.pobj));
|
||||
return static_cast<c_Closure*>(closureLoc->m_data.pobj)->getStaticLocals();
|
||||
} else if (ar->m_func->isGeneratorFromClosure()) {
|
||||
TypedValue* contLoc = frame_local(ar, 0);
|
||||
assert(dynamic_cast<c_Continuation*>(contLoc->m_data.pobj));
|
||||
c_Continuation* cont = static_cast<c_Continuation*>(contLoc->m_data.pobj);
|
||||
|
||||
TypedValue* closureLoc = frame_local(ar, cont->m_origFunc->numParams() + 1);
|
||||
c_Continuation* cont = frame_continuation(ar);
|
||||
TypedValue* closureLoc = frame_local(ar, cont->m_origFunc->numParams());
|
||||
assert(dynamic_cast<c_Closure*>(closureLoc->m_data.pobj));
|
||||
return static_cast<c_Closure*>(closureLoc->m_data.pobj)->getStaticLocals();
|
||||
} else {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#ifndef incl_HPHP_VM_RUNTIME_H_
|
||||
#define incl_HPHP_VM_RUNTIME_H_
|
||||
|
||||
#include "hphp/runtime/ext/ext_continuation.h"
|
||||
#include "hphp/runtime/vm/event_hook.h"
|
||||
#include "hphp/runtime/vm/func.h"
|
||||
#include "hphp/runtime/vm/funcdict.h"
|
||||
@@ -80,6 +81,14 @@ frame_local_inner(const ActRec* fp, int n) {
|
||||
return ret->m_type == KindOfRef ? ret->m_data.pref->tv() : ret;
|
||||
}
|
||||
|
||||
inline c_Continuation*
|
||||
frame_continuation(const ActRec* fp) {
|
||||
size_t arOffset = c_Continuation::getArOffset(fp->m_func);
|
||||
ObjectData* obj = (ObjectData*)((char*)fp - arOffset);
|
||||
assert(dynamic_cast<c_Continuation*>(obj));
|
||||
return static_cast<c_Continuation*>(obj);
|
||||
}
|
||||
|
||||
/*
|
||||
* 'Unwinding' versions of the below frame_free_locals_* functions
|
||||
* zero locals and the $this pointer.
|
||||
|
||||
@@ -660,7 +660,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
WithOpt w1(Option::EnableHipHopSyntax);
|
||||
|
||||
V("<?php function foo() { yield break;}",
|
||||
"function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"function () {\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"return;\n"
|
||||
"}\n"
|
||||
@@ -670,7 +670,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
"}\n");
|
||||
|
||||
V("<?php function foo() { yield 123;}",
|
||||
"function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"function () {\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"yield 123;\n"
|
||||
"}\n"
|
||||
@@ -685,7 +685,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
"return hphp_create_continuation"
|
||||
"(__CLASS__, 'foo$continuation', __METHOD__);\n"
|
||||
"}\n"
|
||||
"public function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"public function () {\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"yield 123;\n"
|
||||
"yield 456;\n"
|
||||
|
||||
@@ -574,10 +574,7 @@ array(3) {
|
||||
[2]=>
|
||||
array(1) {
|
||||
["args"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(Continuation)#2 (0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -674,10 +671,7 @@ array(3) {
|
||||
[2]=>
|
||||
array(1) {
|
||||
["args"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(Continuation)#2 (0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -766,10 +760,7 @@ array(3) {
|
||||
[2]=>
|
||||
array(1) {
|
||||
["args"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(Continuation)#2 (0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,7 @@ array(3) {
|
||||
["function"]=>
|
||||
string(12) "my_generator"
|
||||
["args"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(Continuation)#1 (0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
@@ -54,10 +51,7 @@ array(3) {
|
||||
["type"]=>
|
||||
string(2) "::"
|
||||
["args"]=>
|
||||
array(1) {
|
||||
[0]=>
|
||||
object(Continuation)#1 (0) {
|
||||
}
|
||||
array(0) {
|
||||
}
|
||||
}
|
||||
[1]=>
|
||||
|
||||
@@ -48,7 +48,7 @@ array(5) {
|
||||
}
|
||||
int(4)
|
||||
string(32) "Continuation is already finished"
|
||||
array(13) {
|
||||
array(12) {
|
||||
["b"]=>
|
||||
int(2)
|
||||
["g"]=>
|
||||
@@ -61,23 +61,20 @@ array(13) {
|
||||
int(4)
|
||||
["e"]=>
|
||||
int(5)
|
||||
["__cont__"]=>
|
||||
object(Continuation)#5 (0) {
|
||||
}
|
||||
["c"]=>
|
||||
int(3)
|
||||
["j"]=>
|
||||
int(10)
|
||||
["k"]=>
|
||||
int(11)
|
||||
["h"]=>
|
||||
int(8)
|
||||
["a"]=>
|
||||
int(1)
|
||||
["k"]=>
|
||||
int(11)
|
||||
["l"]=>
|
||||
int(12)
|
||||
}
|
||||
array(13) {
|
||||
array(12) {
|
||||
["b"]=>
|
||||
int(3735928559)
|
||||
["g"]=>
|
||||
@@ -90,24 +87,21 @@ array(13) {
|
||||
int(4)
|
||||
["e"]=>
|
||||
int(5)
|
||||
["__cont__"]=>
|
||||
object(Continuation)#5 (0) {
|
||||
}
|
||||
["c"]=>
|
||||
int(3)
|
||||
["j"]=>
|
||||
int(10)
|
||||
["k"]=>
|
||||
int(11)
|
||||
["h"]=>
|
||||
int(8)
|
||||
["a"]=>
|
||||
object(stdClass)#6 (0) {
|
||||
}
|
||||
["k"]=>
|
||||
int(11)
|
||||
["l"]=>
|
||||
int(12)
|
||||
}
|
||||
array(13) {
|
||||
array(12) {
|
||||
["b"]=>
|
||||
int(3735928559)
|
||||
["g"]=>
|
||||
@@ -120,21 +114,18 @@ array(13) {
|
||||
int(3126047761)
|
||||
["e"]=>
|
||||
int(3126047761)
|
||||
["__cont__"]=>
|
||||
object(Continuation)#5 (0) {
|
||||
}
|
||||
["c"]=>
|
||||
object(Continuation)#5 (0) {
|
||||
}
|
||||
["j"]=>
|
||||
int(10)
|
||||
["k"]=>
|
||||
int(11)
|
||||
["h"]=>
|
||||
int(8)
|
||||
["a"]=>
|
||||
object(stdClass)#6 (0) {
|
||||
}
|
||||
["k"]=>
|
||||
int(11)
|
||||
["l"]=>
|
||||
int(12)
|
||||
}
|
||||
|
||||
Arquivo normal → Arquivo executável
+1
-10
@@ -142,7 +142,7 @@ static void on_constant(Parser *_p, Token &out, Token &name, Token &value) {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// continuation transformations
|
||||
|
||||
void prepare_generator(Parser *_p, Token &stmt, Token ¶ms) {
|
||||
void prepare_generator(Parser *_p, Token &stmt) {
|
||||
// 1. add prologue and epilogue to original body and store it back to "stmt"
|
||||
{
|
||||
// hphp_unpack_continuation()
|
||||
@@ -158,15 +158,6 @@ void prepare_generator(Parser *_p, Token &stmt, Token ¶ms) {
|
||||
stmt.reset();
|
||||
_p->finishStatement(stmt, stmts2); stmt = 1;
|
||||
}
|
||||
|
||||
// 2. prepare a single continuation parameter list and store it in "params"
|
||||
{
|
||||
Token type; type.setText("Continuation");
|
||||
Token var; var.setText(CONTINUATION_OBJECT_NAME);
|
||||
params.reset();
|
||||
type.reset();
|
||||
_p->onParam(params, NULL, type, var, false, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// create a generator function with original name and parameters
|
||||
|
||||
@@ -37,9 +37,6 @@
|
||||
m_xhpAttributes.reset(); \
|
||||
} \
|
||||
|
||||
#define CONTINUATION_OBJECT_NAME "__cont__"
|
||||
#define TYPED_CONTINUATION_OBJECT_NAME "__typedCont__"
|
||||
#define FOREACH_VAR_PREFIX "__foreach__"
|
||||
#define NAMESPACE_SEP '\\'
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário