Simplify hphp_unpack_continuation
Do not generate yield labels as normal goto labels in the parser. Create them at YieldExpression and use m_yieldLabels array in emitter.
Esse commit está contido em:
@@ -2294,12 +2294,6 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
bool enabled = RuntimeOption::EnableEmitSwitch;
|
||||
SimpleFunctionCallPtr
|
||||
call(dynamic_pointer_cast<SimpleFunctionCall>(subject));
|
||||
bool isGenerator = call &&
|
||||
call->isCompilerCallToFunction("hphp_unpack_continuation");
|
||||
if (enabled && isGenerator) {
|
||||
emitContinuationSwitch(e, sw);
|
||||
return false;
|
||||
}
|
||||
|
||||
SwitchState state;
|
||||
bool didSwitch = false;
|
||||
@@ -3151,10 +3145,11 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
}
|
||||
}
|
||||
} else if (call->isCompilerCallToFunction("hphp_unpack_continuation")) {
|
||||
assert(params && params->getCount() == 1);
|
||||
assert(!params || params->getCount() == 0);
|
||||
int yieldLabelCount = call->getFunctionScope()->getYieldLabelCount();
|
||||
inputIsAnObject(0);
|
||||
e.UnpackCont();
|
||||
return true;
|
||||
emitContinuationSwitch(e, yieldLabelCount);
|
||||
return false;
|
||||
} else if (call->isCompilerCallToFunction("hphp_create_continuation")) {
|
||||
assert(params && (params->getCount() == 3 ||
|
||||
params->getCount() == 4));
|
||||
@@ -3839,10 +3834,7 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
e.ContExit();
|
||||
|
||||
// emit return label
|
||||
StringData* nName = StringData::GetStaticString(
|
||||
YIELD_LABEL_PREFIX + boost::lexical_cast<std::string>(y->getLabel()));
|
||||
Label& lab = m_gotoLabels[nName];
|
||||
lab.set(e);
|
||||
m_yieldLabels[y->getLabel()].set(e);
|
||||
|
||||
// check for exception and retrieve result
|
||||
assert(m_evalStack.size() == 0);
|
||||
@@ -4805,58 +4797,35 @@ void EmitterVisitor::emitClsIfSPropBase(Emitter& e) {
|
||||
m_evalStack.get(m_evalStack.size() - 1) | StackSym::M);
|
||||
}
|
||||
|
||||
Label* EmitterVisitor::getContinuationGotoLabel(StatementPtr s) {
|
||||
Label* label = nullptr;
|
||||
StatementListPtr stmts(static_pointer_cast<StatementList>(s));
|
||||
for (int i = 0; i < stmts->getCount(); i++) {
|
||||
StatementPtr s((*stmts)[i]);
|
||||
if (s->is(Statement::KindOfFunctionStatement)) {
|
||||
FunctionStatementPtr f(static_pointer_cast<FunctionStatement>(s));
|
||||
always_assert(f->getFunctionScope()->isGenerator());
|
||||
visit(f);
|
||||
} else if (s->is(Statement::KindOfGotoStatement)) {
|
||||
GotoStatementPtr g(static_pointer_cast<GotoStatement>(s));
|
||||
always_assert(label == nullptr);
|
||||
label = &m_gotoLabels[StringData::GetStaticString(g->label())];
|
||||
} else {
|
||||
not_implemented();
|
||||
}
|
||||
}
|
||||
always_assert(label);
|
||||
return label;
|
||||
}
|
||||
|
||||
void EmitterVisitor::emitContinuationSwitch(Emitter& e,
|
||||
SwitchStatementPtr sw) {
|
||||
StatementListPtr cases(sw->getCases());
|
||||
assert(cases);
|
||||
const int ncase = cases->getCount();
|
||||
|
||||
void EmitterVisitor::emitContinuationSwitch(Emitter& e, int ncase) {
|
||||
// There's an implicit fall-through "label 0" case in the switch
|
||||
// statement generated by the parser, so ncase is equal to the
|
||||
// number of yields in the body of the php function, which is one
|
||||
// less than the number of __yield__ labels.
|
||||
if (ncase == 0) {
|
||||
// fall-through to the label 0
|
||||
e.UnpackCont();
|
||||
e.PopC();
|
||||
return;
|
||||
}
|
||||
|
||||
// make sure the labels are available
|
||||
m_yieldLabels.resize(ncase + 1);
|
||||
|
||||
if (ncase == 1) {
|
||||
// Don't bother with the jump table when there are only two targets
|
||||
CaseStatementPtr c1(static_pointer_cast<CaseStatement>((*cases)[0]));
|
||||
visit(sw->getExp());
|
||||
e.JmpNZ(*getContinuationGotoLabel(c1->getStatement()));
|
||||
} else {
|
||||
Label case0;
|
||||
std::vector<Label*> targets(ncase + 1);
|
||||
targets[0] = &case0;
|
||||
for (int i = 0; i < ncase; ++i) {
|
||||
CaseStatementPtr c(static_pointer_cast<CaseStatement>((*cases)[i]));
|
||||
Variant v;
|
||||
c->getCondition()->getScalarValue(v);
|
||||
int caseIdx = v.asInt64Val();
|
||||
assert(caseIdx > 0 && caseIdx <= ncase);
|
||||
targets[caseIdx] = getContinuationGotoLabel(c->getStatement());
|
||||
}
|
||||
visit(sw->getExp());
|
||||
e.Switch(targets, 0, 0);
|
||||
case0.set(e);
|
||||
e.UnpackCont();
|
||||
e.JmpNZ(m_yieldLabels[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Label*> targets(ncase + 1);
|
||||
for (int i = 0; i <= ncase; ++i) {
|
||||
targets[i] = &m_yieldLabels[i];
|
||||
}
|
||||
e.UnpackCont();
|
||||
e.Switch(targets, 0, 0);
|
||||
m_yieldLabels[0].set(e);
|
||||
}
|
||||
|
||||
DataType EmitterVisitor::analyzeSwitch(SwitchStatementPtr sw,
|
||||
@@ -6697,6 +6666,7 @@ void EmitterVisitor::finishFunc(Emitter& e, FuncEmitter* fe) {
|
||||
copyOverExnHandlers(fe);
|
||||
copyOverFPIRegions(fe);
|
||||
m_gotoLabels.clear();
|
||||
m_yieldLabels.clear();
|
||||
Offset past = e.getUnitEmitter().bcPos();
|
||||
fe->finish(past, false);
|
||||
e.getUnitEmitter().recordFunction(fe);
|
||||
|
||||
@@ -533,6 +533,7 @@ private:
|
||||
std::set<std::string,stdltistr> m_hoistables;
|
||||
LocationPtr m_tempLoc;
|
||||
std::map<StringData*, Label, string_data_lt> m_gotoLabels;
|
||||
std::vector<Label> m_yieldLabels;
|
||||
MetaInfoBuilder m_metaInfo;
|
||||
public:
|
||||
Label& topBreakHandler() { return m_controlTargets.front().m_brkHand; }
|
||||
@@ -584,8 +585,7 @@ public:
|
||||
void emitClsIfSPropBase(Emitter& e);
|
||||
Id emitVisitAndSetUnnamedL(Emitter& e, ExpressionPtr exp);
|
||||
void emitPushAndFreeUnnamedL(Emitter& e, Id tempLocal, Offset start);
|
||||
Label* getContinuationGotoLabel(StatementPtr s);
|
||||
void emitContinuationSwitch(Emitter& e, SwitchStatementPtr s);
|
||||
void emitContinuationSwitch(Emitter& e, int ncase);
|
||||
DataType analyzeSwitch(SwitchStatementPtr s, SwitchState& state);
|
||||
void emitIntegerSwitch(Emitter& e, SwitchStatementPtr s,
|
||||
std::vector<Label>& caseLabels, Label& done,
|
||||
|
||||
@@ -65,7 +65,8 @@ FunctionScope::FunctionScope(AnalysisResultConstPtr ar, bool method,
|
||||
m_directInvoke(false),
|
||||
m_closureGenerator(false), m_noLSB(false), m_nextLSB(false),
|
||||
m_hasTry(false), m_hasGoto(false), m_localRedeclaring(false),
|
||||
m_redeclaring(-1), m_inlineIndex(0), m_optFunction(0), m_nextID(0) {
|
||||
m_redeclaring(-1), m_inlineIndex(0), m_optFunction(0), m_nextID(0),
|
||||
m_yieldLabelCount(0) {
|
||||
init(ar);
|
||||
for (unsigned i = 0; i < attrs.size(); ++i) {
|
||||
if (m_userAttributes.find(attrs[i]->getName()) != m_userAttributes.end()) {
|
||||
@@ -106,7 +107,7 @@ FunctionScope::FunctionScope(FunctionScopePtr orig,
|
||||
m_hasGoto(orig->m_hasGoto), m_localRedeclaring(orig->m_localRedeclaring),
|
||||
m_redeclaring(orig->m_redeclaring),
|
||||
m_inlineIndex(orig->m_inlineIndex), m_optFunction(orig->m_optFunction),
|
||||
m_nextID(0) {
|
||||
m_nextID(0), m_yieldLabelCount(orig->m_yieldLabelCount) {
|
||||
init(ar);
|
||||
m_originalName = originalName;
|
||||
setParamCounts(ar, m_minParam, m_maxParam);
|
||||
|
||||
@@ -113,6 +113,8 @@ public:
|
||||
bool isClosure() const;
|
||||
bool isGenerator() const;
|
||||
bool isGeneratorFromClosure() const;
|
||||
int allocYieldLabel() { return ++m_yieldLabelCount; }
|
||||
int getYieldLabelCount() const { return m_yieldLabelCount; }
|
||||
bool hasGeneratorAsBody() const;
|
||||
MethodStatementRawPtr getOrigGenStmt() const;
|
||||
FunctionScopeRawPtr getOrigGenFS() const;
|
||||
@@ -485,6 +487,7 @@ private:
|
||||
ExpressionListPtr m_closureValues;
|
||||
ReadWriteMutex m_inlineMutex;
|
||||
unsigned m_nextID; // used when cloning generators for traits
|
||||
int m_yieldLabelCount; // number of allocated yield labels
|
||||
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
|
||||
};
|
||||
|
||||
|
||||
@@ -24,9 +24,9 @@ using namespace HPHP;
|
||||
|
||||
YieldExpression::YieldExpression
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr exp, int label)
|
||||
ExpressionPtr exp)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(YieldExpression)),
|
||||
m_exp(exp), m_label(label) {
|
||||
m_exp(exp), m_label(-1) {
|
||||
}
|
||||
|
||||
ExpressionPtr YieldExpression::clone() {
|
||||
@@ -47,6 +47,9 @@ ExpressionPtr YieldExpression::clone() {
|
||||
void YieldExpression::analyzeProgram(AnalysisResultPtr ar) {
|
||||
assert(getFunctionScope() && getFunctionScope()->isGenerator());
|
||||
m_exp->analyzeProgram(ar);
|
||||
if (m_label == -1) {
|
||||
setLabel(getFunctionScope()->allocYieldLabel());
|
||||
}
|
||||
}
|
||||
|
||||
ConstructPtr YieldExpression::getNthKid(int n) const {
|
||||
|
||||
@@ -27,12 +27,13 @@ DECLARE_BOOST_TYPES(YieldExpression);
|
||||
class YieldExpression : public Expression {
|
||||
public:
|
||||
YieldExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr exp, int label);
|
||||
ExpressionPtr exp);
|
||||
|
||||
DECLARE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
|
||||
ExpressionPtr getExpression() { return m_exp; }
|
||||
int getLabel() { return m_label; }
|
||||
int getLabel() { assert(m_label >= 0); return m_label; }
|
||||
void setLabel(int label) { assert(m_label == -1); m_label = label; }
|
||||
|
||||
private:
|
||||
ExpressionPtr m_exp;
|
||||
|
||||
+754
-789
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -109,8 +109,7 @@
|
||||
|
||||
using namespace HPHP::Compiler;
|
||||
|
||||
extern void prepare_generator(Parser *_p, Token &stmt, Token ¶ms,
|
||||
int count);
|
||||
extern void prepare_generator(Parser *_p, Token &stmt, Token ¶ms);
|
||||
extern void create_generator(Parser *_p, Token &out, Token ¶ms,
|
||||
Token &name, const std::string &closureName,
|
||||
const char *clsname, Token *modifiers,
|
||||
@@ -828,7 +827,7 @@ void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
|
||||
ContinuationFromClosure : Continuation;
|
||||
const string &closureName = getAnonFuncName(fKind);
|
||||
Token new_params;
|
||||
prepare_generator(this, stmt, new_params, funcContext.numYields);
|
||||
prepare_generator(this, stmt, new_params);
|
||||
|
||||
func = NEW_STMT(FunctionStatement, exp, ref->num(), closureName,
|
||||
dynamic_pointer_cast<ExpressionList>(new_params->exp),
|
||||
@@ -1130,7 +1129,7 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
||||
if (funcContext.isGenerator) {
|
||||
const string &closureName = getAnonFuncName(ParserBase::Continuation);
|
||||
Token new_params;
|
||||
prepare_generator(this, stmt, new_params, funcContext.numYields);
|
||||
prepare_generator(this, stmt, new_params);
|
||||
ModifierExpressionPtr exp2 = Construct::Clone(exp);
|
||||
mth = NEW_STMT(MethodStatement, exp2, ref->num(), closureName,
|
||||
dynamic_pointer_cast<ExpressionList>(new_params->exp),
|
||||
@@ -1409,9 +1408,7 @@ void Parser::onYield(Token &out, Token &expr) {
|
||||
return;
|
||||
}
|
||||
|
||||
FunctionContext &funcContext = m_funcContexts.back();
|
||||
int label = ++funcContext.numYields;
|
||||
out->exp = NEW_EXP(YieldExpression, expr->exp, label);
|
||||
out->exp = NEW_EXP(YieldExpression, expr->exp);
|
||||
}
|
||||
|
||||
void Parser::onYieldBreak(Token &out) {
|
||||
|
||||
@@ -249,7 +249,6 @@ private:
|
||||
FunctionContext()
|
||||
: isNotGenerator(false)
|
||||
, isGenerator(false)
|
||||
, numYields(0)
|
||||
{}
|
||||
|
||||
// mark this function as generator; returns true on success
|
||||
@@ -270,7 +269,6 @@ private:
|
||||
|
||||
bool isNotGenerator; // function determined to not be a generator
|
||||
bool isGenerator; // function determined to be a generator
|
||||
int numYields; // number of plain yield statements seen so far
|
||||
};
|
||||
|
||||
AnalysisResultPtr m_ar;
|
||||
|
||||
@@ -77,21 +77,6 @@ DefineFunction(
|
||||
'taint_observer' => false,
|
||||
));
|
||||
|
||||
DefineFunction(
|
||||
array(
|
||||
'name' => 'hphp_unpack_continuation',
|
||||
'return' => array(
|
||||
'type' => null,
|
||||
),
|
||||
'args' => array(
|
||||
array(
|
||||
'name' => 'continuation',
|
||||
'type' => Object,
|
||||
),
|
||||
),
|
||||
'taint_observer' => false,
|
||||
));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Classes
|
||||
//
|
||||
|
||||
@@ -40,10 +40,6 @@ p_Continuation f_hphp_create_continuation(CStrRef clsname,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void f_hphp_unpack_continuation(CObjRef continuation) {
|
||||
throw_fatal("Invalid call hphp_unpack_continuation");
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static StaticString s___cont__("__cont__");
|
||||
|
||||
@@ -95,56 +95,6 @@ TypedValue* fg_hphp_create_continuation(HPHP::VM::ActRec *ar) {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void HPHP::f_hphp_unpack_continuation(HPHP::Object const&)
|
||||
_ZN4HPHP26f_hphp_unpack_continuationERKNS_6ObjectE
|
||||
|
||||
continuation => rdi
|
||||
*/
|
||||
|
||||
void fh_hphp_unpack_continuation(Value* continuation) asm("_ZN4HPHP26f_hphp_unpack_continuationERKNS_6ObjectE");
|
||||
|
||||
TypedValue * fg1_hphp_unpack_continuation(TypedValue* rv, HPHP::VM::ActRec* ar, int64_t count) __attribute__((noinline,cold));
|
||||
TypedValue * fg1_hphp_unpack_continuation(TypedValue* rv, HPHP::VM::ActRec* ar, int64_t count) {
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
rv->m_data.num = 0LL;
|
||||
rv->m_type = KindOfNull;
|
||||
tvCastToObjectInPlace(args-0);
|
||||
fh_hphp_unpack_continuation((Value*)(args-0));
|
||||
return rv;
|
||||
}
|
||||
|
||||
TypedValue* fg_hphp_unpack_continuation(HPHP::VM::ActRec *ar) {
|
||||
TypedValue rv;
|
||||
int64_t count = ar->numArgs();
|
||||
TypedValue* args UNUSED = ((TypedValue*)ar) - 1;
|
||||
if (count == 1LL) {
|
||||
if ((args-0)->m_type == KindOfObject) {
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
fh_hphp_unpack_continuation((Value*)(args-0));
|
||||
frame_free_locals_no_this_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
} else {
|
||||
fg1_hphp_unpack_continuation(&rv, ar, count);
|
||||
frame_free_locals_no_this_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
}
|
||||
} else {
|
||||
throw_wrong_arguments_nr("hphp_unpack_continuation", count, 1, 1, 1);
|
||||
}
|
||||
rv.m_data.num = 0LL;
|
||||
rv.m_type = KindOfNull;
|
||||
frame_free_locals_no_this_inl(ar, 1);
|
||||
memcpy(&ar->m_r, &rv, sizeof(TypedValue));
|
||||
return &ar->m_r;
|
||||
return &ar->m_r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HPHP::VM::Instance* new_Continuation_Instance(HPHP::VM::Class* cls) {
|
||||
size_t nProps = cls->numDeclProperties();
|
||||
size_t builtinPropSize = sizeof(c_Continuation) - sizeof(ObjectData);
|
||||
|
||||
@@ -30,15 +30,6 @@ args => r8
|
||||
|
||||
Value* fh_hphp_create_continuation(Value* _rv, Value* clsname, Value* funcname, Value* origFuncName, Value* args) asm("_ZN4HPHP26f_hphp_create_continuationERKNS_6StringES2_S2_RKNS_5ArrayE");
|
||||
|
||||
/*
|
||||
void HPHP::f_hphp_unpack_continuation(HPHP::Object const&)
|
||||
_ZN4HPHP26f_hphp_unpack_continuationERKNS_6ObjectE
|
||||
|
||||
continuation => rdi
|
||||
*/
|
||||
|
||||
void fh_hphp_unpack_continuation(Value* continuation) asm("_ZN4HPHP26f_hphp_unpack_continuationERKNS_6ObjectE");
|
||||
|
||||
|
||||
} // !HPHP
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace HPHP {
|
||||
FORWARD_DECLARE_CLASS_BUILTIN(Continuation);
|
||||
FORWARD_DECLARE_CLASS_BUILTIN(ContinuationWaitHandle);
|
||||
p_Continuation f_hphp_create_continuation(CStrRef clsname, CStrRef funcname, CStrRef origFuncName, CArrRef args = null_array);
|
||||
void f_hphp_unpack_continuation(CObjRef continuation);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// class Continuation
|
||||
|
||||
@@ -191,7 +191,6 @@ TypedValue* fg_get_object_vars(VM::ActRec *ar);
|
||||
TypedValue* fg_call_user_method_array(VM::ActRec *ar);
|
||||
TypedValue* fg_call_user_method(VM::ActRec *ar);
|
||||
TypedValue* fg_hphp_create_continuation(VM::ActRec *ar);
|
||||
TypedValue* fg_hphp_unpack_continuation(VM::ActRec *ar);
|
||||
TypedValue* fg_ctype_alnum(VM::ActRec *ar);
|
||||
TypedValue* fg_ctype_alpha(VM::ActRec *ar);
|
||||
TypedValue* fg_ctype_cntrl(VM::ActRec *ar);
|
||||
@@ -3020,7 +3019,7 @@ TypedValue* tg_9XMLWriter_endDTD(VM::ActRec *ar);
|
||||
TypedValue* tg_9XMLWriter_flush(VM::ActRec *ar);
|
||||
TypedValue* tg_9XMLWriter_outputMemory(VM::ActRec *ar);
|
||||
|
||||
const long long hhbc_ext_funcs_count = 2208;
|
||||
const long long hhbc_ext_funcs_count = 2207;
|
||||
const HhbcExtFuncInfo hhbc_ext_funcs[] = {
|
||||
{ "apache_note", fg_apache_note, (void *)&fh_apache_note },
|
||||
{ "apache_request_headers", fg_apache_request_headers, (void *)&fh_apache_request_headers },
|
||||
@@ -3190,7 +3189,6 @@ const HhbcExtFuncInfo hhbc_ext_funcs[] = {
|
||||
{ "call_user_method_array", fg_call_user_method_array, (void *)&fh_call_user_method_array },
|
||||
{ "call_user_method", fg_call_user_method, (void *)&fh_call_user_method },
|
||||
{ "hphp_create_continuation", fg_hphp_create_continuation, (void *)&fh_hphp_create_continuation },
|
||||
{ "hphp_unpack_continuation", fg_hphp_unpack_continuation, (void *)&fh_hphp_unpack_continuation },
|
||||
{ "ctype_alnum", fg_ctype_alnum, (void *)&fh_ctype_alnum },
|
||||
{ "ctype_alpha", fg_ctype_alpha, (void *)&fh_ctype_alpha },
|
||||
{ "ctype_cntrl", fg_ctype_cntrl, (void *)&fh_ctype_cntrl },
|
||||
|
||||
@@ -2913,10 +2913,7 @@ void Translator::relaxDeps(Tracelet& tclet, TraceletContext& tctxt) {
|
||||
static bool checkTaintFuncs(StringData* name) {
|
||||
static const StringData* s_extract =
|
||||
StringData::GetStaticString("extract");
|
||||
static const StringData* s_hphp_unpack_continuation =
|
||||
StringData::GetStaticString("hphp_unpack_continuation");
|
||||
return name->isame(s_extract) ||
|
||||
name->isame(s_hphp_unpack_continuation);
|
||||
return name->isame(s_extract);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -7146,12 +7146,6 @@ const char *g_class_map[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "hphp_unpack_continuation", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from\n * http://php.net/manual/en/function.hphp-unpack-continuation.php )\n *\n *\n * @continuation\n * object\n */",
|
||||
(const char *)-1, (const char *)0x2000, "continuation", "", (const char *)0x40, "", "", NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "assert_options", "", (const char*)0, (const char*)0,
|
||||
"/**\n * ( excerpt from http://php.net/manual/en/function.assert-options.php )\n *\n * Set the various assert() control options or just query their current\n * settings.\n *\n * @what int Assert Options Option INI Setting Default value\n * Description ASSERT_ACTIVE assert.active 1 enable\n * assert() evaluation ASSERT_WARNING assert.warning 1\n * issue a PHP warning for each failed assertion\n * ASSERT_BAIL assert.bail 0 terminate execution on\n * failed assertions ASSERT_QUIET_EVAL\n * assert.quiet_eval 0 disable error_reporting during\n * assertion expression evaluation ASSERT_CALLBACK\n * assert.callback (NULL) Callback to call on failed\n * assertions\n * @value mixed An optional new value for the option.\n *\n * @return mixed Returns the original setting of any option or FALSE\n * on errors.\n */",
|
||||
(const char *)0xffffffff, (const char *)0x2000, "what", "", (const char *)0xa, "", "", NULL,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
#if EXT_TYPE == 0
|
||||
"hphp_create_continuation", S(999), "Continuation", S(0), "clsname", T(String), NULL, S(0), NULL, S(0), "funcname", T(String), NULL, S(0), NULL, S(0), "origFuncName", T(String), NULL, S(0), NULL, S(0), "args", T(Array), "N;", S(2), "null", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.hphp-create-continuation.php )\n *\n *\n * @clsname string\n * @funcname string\n * @origFuncName\n * string\n * @args map\n *\n * @return Continuation\n *\n */",
|
||||
"hphp_unpack_continuation", T(Void), S(0), "continuation", T(Object), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.hphp-unpack-continuation.php )\n *\n *\n * @continuation\n * object\n */",
|
||||
|
||||
#elif EXT_TYPE == 1
|
||||
|
||||
|
||||
@@ -658,8 +658,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
|
||||
V("<?php function foo() { yield break;}",
|
||||
"function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"switch (hphp_unpack_continuation($" CONTINUATION_OBJECT_NAME ")) {\n"
|
||||
"}\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"return;\n"
|
||||
"}\n"
|
||||
"function foo() {\n"
|
||||
@@ -669,10 +668,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
|
||||
V("<?php function foo() { yield 123;}",
|
||||
"function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"switch (hphp_unpack_continuation($" CONTINUATION_OBJECT_NAME ")) {\n"
|
||||
"case 1:\n"
|
||||
"goto " YIELD_LABEL_PREFIX "1;\n"
|
||||
"}\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"yield 123;\n"
|
||||
"}\n"
|
||||
"function foo() {\n"
|
||||
@@ -687,13 +683,7 @@ bool TestParserStmt::TestYieldStatement() {
|
||||
"(__CLASS__, '3990978909_1', __METHOD__);\n"
|
||||
"}\n"
|
||||
"public function ($" CONTINUATION_OBJECT_NAME ") {\n"
|
||||
"switch (hphp_unpack_continuation($" CONTINUATION_OBJECT_NAME ")) {\n"
|
||||
"case 2:\n"
|
||||
"goto " YIELD_LABEL_PREFIX "2;\n"
|
||||
"\n"
|
||||
"case 1:\n"
|
||||
"goto " YIELD_LABEL_PREFIX "1;\n"
|
||||
"}\n"
|
||||
"hphp_unpack_continuation();\n"
|
||||
"yield 123;\n"
|
||||
"yield 456;\n"
|
||||
"}\n"
|
||||
|
||||
+11
-46
@@ -143,56 +143,21 @@ static void on_constant(Parser *_p, Token &out, Token *stmts,
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// continuation transformations
|
||||
|
||||
void prepare_generator(Parser *_p, Token &stmt, Token ¶ms, int count) {
|
||||
void prepare_generator(Parser *_p, Token &stmt, Token ¶ms) {
|
||||
// 1. add prologue and epilogue to original body and store it back to "stmt"
|
||||
{
|
||||
Token scall;
|
||||
Token switchExp;
|
||||
{
|
||||
// hphp_unpack_continuation(v___cont__)
|
||||
Token name; name.setText(CONTINUATION_OBJECT_NAME);
|
||||
Token var; _p->onSynthesizedVariable(var, name);
|
||||
Token param1; _p->onCallParam(param1, NULL, var, false);
|
||||
// hphp_unpack_continuation()
|
||||
Token empty;
|
||||
Token cname; cname.setText("hphp_unpack_continuation");
|
||||
Token unpack; _p->onCall(unpack, false, cname, empty, NULL, true);
|
||||
Token sunpack; _p->onExpStatement(sunpack, unpack);
|
||||
|
||||
Token cname; cname.setText("hphp_unpack_continuation");
|
||||
Token call; _p->onCall(call, false, cname, param1, NULL, true);
|
||||
Token stmts0; _p->onStatementListStart(stmts0);
|
||||
Token stmts1; _p->addStatement(stmts1, stmts0, sunpack);
|
||||
Token stmts2; _p->addStatement(stmts2, stmts1, stmt);
|
||||
|
||||
switchExp = call;
|
||||
}
|
||||
Token sswitch;
|
||||
{
|
||||
_p->pushLabelScope();
|
||||
{
|
||||
Token cases;
|
||||
for (int i = count; i > 0; i--) {
|
||||
std::string si = boost::lexical_cast<std::string>(i);
|
||||
|
||||
Token label; label.setText(YIELD_LABEL_PREFIX + si);
|
||||
Token sgoto; _p->onGoto(sgoto, label, false);
|
||||
_p->addGoto(label.text(), _p->getLocation(), &sgoto);
|
||||
|
||||
Token stmts0; _p->onStatementListStart(stmts0);
|
||||
Token stmts1; _p->addStatement(stmts1, stmts0, sgoto);
|
||||
Token stmts; _p->finishStatement(stmts, stmts1); stmts = 1;
|
||||
|
||||
Token snum; snum.setText(si);
|
||||
Token num; _p->onScalar(num, T_LNUMBER, snum);
|
||||
Token scase; _p->onCase(scase, cases, &num, stmts);
|
||||
cases = scase;
|
||||
}
|
||||
_p->onSwitch(sswitch, switchExp, cases);
|
||||
}
|
||||
_p->popLabelScope();
|
||||
}
|
||||
{
|
||||
Token stmts0; _p->onStatementListStart(stmts0);
|
||||
Token stmts1; _p->addStatement(stmts1, stmts0, scall);
|
||||
Token stmts2; _p->addStatement(stmts2, stmts1, sswitch);
|
||||
Token stmts3; _p->addStatement(stmts3, stmts2, stmt);
|
||||
|
||||
stmt.reset();
|
||||
_p->finishStatement(stmt, stmts3); stmt = 1;
|
||||
}
|
||||
stmt.reset();
|
||||
_p->finishStatement(stmt, stmts2); stmt = 1;
|
||||
}
|
||||
|
||||
// 2. prepare a single continuation parameter list and store it in "params"
|
||||
|
||||
@@ -247,10 +247,6 @@ void ParserBase::popLabelInfo() {
|
||||
|
||||
for (unsigned int i = 0; i < info.gotos.size(); i++) {
|
||||
const GotoInfo &gotoInfo = info.gotos[i];
|
||||
if (gotoInfo.label.find(YIELD_LABEL_PREFIX) == 0) {
|
||||
labels.erase(gotoInfo.label);
|
||||
continue;
|
||||
}
|
||||
LabelMap::const_iterator iter = info.labels.find(gotoInfo.label);
|
||||
if (iter == info.labels.end()) {
|
||||
invalidateGoto(gotoInfo.stmt, UndefLabel);
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
// NOTE: system/classes/closure.php may have reference to these strings:
|
||||
#define CONTINUATION_OBJECT_NAME "__cont__"
|
||||
#define TYPED_CONTINUATION_OBJECT_NAME "__typedCont__"
|
||||
#define YIELD_LABEL_PREFIX "__yield__"
|
||||
#define FOREACH_VAR_PREFIX "__foreach__"
|
||||
#define NAMESPACE_SEP '\\'
|
||||
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
Referência em uma Nova Issue
Bloquear um usuário