Store variable arguments in optional local
Save 8 bytes of m_args and its initialization for Continuations without func_get_args() call (does not save real memory due to 16-byte alignment). Store variable arguments in optional local.
Esse commit está contido em:
@@ -109,6 +109,11 @@ TRACE_SET_MOD(emitter)
|
||||
using boost::dynamic_pointer_cast;
|
||||
using boost::static_pointer_cast;
|
||||
|
||||
namespace {
|
||||
const StringData* s_continuationVarArgsLocal
|
||||
= StringData::GetStaticString("0ContinuationVarArgsLocal");
|
||||
}
|
||||
|
||||
namespace StackSym {
|
||||
static const char None = 0x00;
|
||||
|
||||
@@ -3217,6 +3222,38 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else if (call->isCallToFunction("func_num_args") &&
|
||||
m_curFunc->isGenerator()) {
|
||||
static const StringData* s_count =
|
||||
StringData::GetStaticString("count");
|
||||
|
||||
emitVirtualLocal(m_curFunc->lookupVarId(s_continuationVarArgsLocal));
|
||||
emitConvertToCell(e);
|
||||
e.False();
|
||||
e.FCallBuiltin(2, 1, s_count);
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::NopOut, false, 0, 0);
|
||||
e.UnboxR();
|
||||
return true;
|
||||
} else if (call->isCallToFunction("func_get_args") &&
|
||||
m_curFunc->isGenerator()) {
|
||||
emitVirtualLocal(m_curFunc->lookupVarId(s_continuationVarArgsLocal));
|
||||
emitConvertToCell(e);
|
||||
return true;
|
||||
} else if (call->isCallToFunction("func_get_arg") &&
|
||||
m_curFunc->isGenerator()) {
|
||||
if (!params || params->getCount() == 0) {
|
||||
e.Null();
|
||||
return true;
|
||||
}
|
||||
|
||||
visit((*params)[0]);
|
||||
emitConvertToCell(e);
|
||||
e.CastInt();
|
||||
emitVirtualLocal(m_curFunc->lookupVarId(s_continuationVarArgsLocal));
|
||||
emitConvertToCell(e);
|
||||
e.False();
|
||||
e.ArrayIdx();
|
||||
return true;
|
||||
} else if (call->isCompilerCallToFunction("hphp_unpack_continuation")) {
|
||||
assert(!params || params->getCount() == 0);
|
||||
int yieldLabelCount = call->getFunctionScope()->getYieldLabelCount();
|
||||
@@ -3224,16 +3261,28 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
emitContinuationSwitch(e, yieldLabelCount);
|
||||
return false;
|
||||
} else if (call->isCompilerCallToFunction("hphp_create_continuation")) {
|
||||
assert(params && (params->getCount() == 3 ||
|
||||
params->getCount() == 4));
|
||||
assert(params && params->getCount() == 3);
|
||||
ExpressionPtr name = (*params)[1];
|
||||
Variant nameVar;
|
||||
UNUSED bool isScalar = name->getScalarValue(nameVar);
|
||||
assert(isScalar && nameVar.isString());
|
||||
|
||||
if (m_curFunc->hasVar(s_continuationVarArgsLocal)) {
|
||||
static const StringData* s_func_get_args =
|
||||
StringData::GetStaticString("func_get_args");
|
||||
|
||||
Id local = m_curFunc->lookupVarId(s_continuationVarArgsLocal);
|
||||
emitVirtualLocal(local);
|
||||
e.FCallBuiltin(0, 0, s_func_get_args);
|
||||
m_metaInfo.add(m_ue.bcPos(), Unit::MetaInfo::NopOut, false, 0, 0);
|
||||
e.UnboxR();
|
||||
emitSet(e);
|
||||
e.PopC();
|
||||
}
|
||||
|
||||
const StringData* nameStr =
|
||||
StringData::GetStaticString(nameVar.getStringData());
|
||||
bool callGetArgs = params->getCount() == 4;
|
||||
e.CreateCont(callGetArgs, nameStr);
|
||||
e.CreateCont(nameStr);
|
||||
return true;
|
||||
} else if (call->isCompilerCallToFunction("hphp_continuation_done")) {
|
||||
assert(params && params->getCount() == 1);
|
||||
@@ -5363,6 +5412,10 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
}
|
||||
}
|
||||
|
||||
if (p.m_meth->hasCallToGetArgs()) {
|
||||
fe->allocVarId(s_continuationVarArgsLocal);
|
||||
}
|
||||
|
||||
// Assign ids to all of the local variables eagerly. This gives us the
|
||||
// nice property that all named local variables will be assigned ids
|
||||
// 0 through k-1, while any unnamed local variable will have an id >= k.
|
||||
@@ -5379,7 +5432,7 @@ void EmitterVisitor::emitPostponedMeths() {
|
||||
|
||||
if (allowOverride) attrs = attrs | AttrAllowOverride;
|
||||
|
||||
if (funcScope->mayUseVV()) {
|
||||
if (funcScope->mayUseVV() || p.m_meth->hasCallToGetArgs()) {
|
||||
attrs = attrs | AttrMayUseVV;
|
||||
}
|
||||
|
||||
@@ -5901,12 +5954,6 @@ bool EmitterVisitor::canEmitBuiltinCall(FunctionCallPtr fn,
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Special handling for func_get_args and friends inside a generator.
|
||||
if (m_curFunc->isGenerator() &&
|
||||
(name == "func_get_args" || name == "func_num_args"
|
||||
|| name == "func_get_arg")) {
|
||||
return false;
|
||||
}
|
||||
// in sandbox mode, don't emit FCallBuiltin for redefinable functions
|
||||
if (func->allowOverride() && !Option::WholeProgram) {
|
||||
return false;
|
||||
@@ -5977,46 +6024,13 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
}
|
||||
}
|
||||
|
||||
if (useFCallBuiltin) {
|
||||
} else if (!m_curFunc->isGenerator()) {
|
||||
if (!useFCallBuiltin) {
|
||||
fpiStart = m_ue.bcPos();
|
||||
|
||||
if (nsName == nullptr) {
|
||||
e.FPushFuncD(numParams, nLiteral);
|
||||
} else {
|
||||
e.FPushFuncU(numParams, nsName, nLiteral);
|
||||
}
|
||||
} else {
|
||||
// Special handling for func_get_args and friends inside a generator.
|
||||
const StringData* specialMethodName = nullptr;
|
||||
static const StringData* contName =
|
||||
StringData::GetStaticString(CONTINUATION_OBJECT_NAME);
|
||||
Id contId = m_curFunc->lookupVarId(contName);
|
||||
static const StringData* s_get_args =
|
||||
StringData::GetStaticString("get_args");
|
||||
static const StringData* s_num_args =
|
||||
StringData::GetStaticString("num_args");
|
||||
static const StringData* s_get_arg =
|
||||
StringData::GetStaticString("get_arg");
|
||||
if (nameStr == "func_get_args") {
|
||||
specialMethodName = s_get_args;
|
||||
} else if (nameStr == "func_num_args") {
|
||||
specialMethodName = s_num_args;
|
||||
} else if (nameStr == "func_get_arg") {
|
||||
specialMethodName = s_get_arg;
|
||||
}
|
||||
|
||||
if (nsName != nullptr) {
|
||||
e.FPushFuncU(numParams, nsName, nLiteral);
|
||||
} else if (specialMethodName != nullptr) {
|
||||
emitVirtualLocal(contId);
|
||||
emitCGet(e);
|
||||
fpiStart = m_ue.bcPos();
|
||||
e.FPushObjMethodD(numParams, specialMethodName);
|
||||
} else {
|
||||
fpiStart = m_ue.bcPos();
|
||||
e.FPushFuncD(numParams, nLiteral);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// $foo()
|
||||
|
||||
+784
-790
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -115,7 +115,7 @@ 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,
|
||||
bool getArgs, Token &origGenFunc, bool isHhvm,
|
||||
Token &origGenFunc, bool isHhvm,
|
||||
Token *attr);
|
||||
|
||||
namespace HPHP {
|
||||
@@ -858,7 +858,7 @@ void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
|
||||
pushComment(comment);
|
||||
Token origGenFunc;
|
||||
create_generator(this, out, params, name, closureName, nullptr, nullptr,
|
||||
hasCallToGetArgs, origGenFunc,
|
||||
origGenFunc,
|
||||
(!Option::WholeProgram || !Option::ParseTimeOpts),
|
||||
attr);
|
||||
m_closureGenerator = false;
|
||||
@@ -867,6 +867,8 @@ void Parser::onFunction(Token &out, Token *modifiers, Token &ret, Token &ref,
|
||||
assert(origStmt);
|
||||
func->setOrigGeneratorFunc(origStmt);
|
||||
origStmt->setGeneratorFunc(func);
|
||||
origStmt->setHasCallToGetArgs(hasCallToGetArgs);
|
||||
func->setHasCallToGetArgs(hasCallToGetArgs);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -1155,7 +1157,7 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
||||
pushComment(comment);
|
||||
Token origGenFunc;
|
||||
create_generator(this, out, params, name, closureName, m_clsName.c_str(),
|
||||
&modifiers, hasCallToGetArgs, origGenFunc,
|
||||
&modifiers, origGenFunc,
|
||||
(!Option::WholeProgram || !Option::ParseTimeOpts),
|
||||
attr);
|
||||
MethodStatementPtr origStmt =
|
||||
@@ -1163,7 +1165,8 @@ void Parser::onMethod(Token &out, Token &modifiers, Token &ret, Token &ref,
|
||||
assert(origStmt);
|
||||
mth->setOrigGeneratorFunc(origStmt);
|
||||
origStmt->setGeneratorFunc(mth);
|
||||
|
||||
origStmt->setHasCallToGetArgs(hasCallToGetArgs);
|
||||
mth->setHasCallToGetArgs(hasCallToGetArgs);
|
||||
} else {
|
||||
ExpressionListPtr attrList;
|
||||
if (attr && attr->exp) {
|
||||
|
||||
@@ -63,7 +63,7 @@ MethodStatement::MethodStatement
|
||||
StatementListPtr stmt, int attr, const string &docComment,
|
||||
ExpressionListPtr attrList, bool method /* = true */)
|
||||
: Statement(STATEMENT_CONSTRUCTOR_BASE_PARAMETER_VALUES),
|
||||
m_method(method), m_ref(ref), m_attribute(attr),
|
||||
m_method(method), m_ref(ref), m_hasCallToGetArgs(false), m_attribute(attr),
|
||||
m_cppLength(-1), m_modifiers(modifiers),
|
||||
m_originalName(name), m_params(params),
|
||||
m_retTypeConstraint(retTypeConstraint), m_stmt(stmt),
|
||||
@@ -79,8 +79,8 @@ MethodStatement::MethodStatement
|
||||
int attr, const string &docComment, ExpressionListPtr attrList,
|
||||
bool method /* = true */)
|
||||
: Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(MethodStatement)),
|
||||
m_method(method), m_ref(ref), m_attribute(attr), m_cppLength(-1),
|
||||
m_modifiers(modifiers), m_originalName(name),
|
||||
m_method(method), m_ref(ref), m_hasCallToGetArgs(false), m_attribute(attr),
|
||||
m_cppLength(-1), m_modifiers(modifiers), m_originalName(name),
|
||||
m_params(params), m_retTypeConstraint(retTypeConstraint),
|
||||
m_stmt(stmt), m_docComment(docComment), m_attrList(attrList) {
|
||||
m_name = Util::toLower(name);
|
||||
|
||||
@@ -130,9 +130,13 @@ public:
|
||||
void addTraitMethodToScope(AnalysisResultConstPtr ar,
|
||||
ClassScopePtr classScope);
|
||||
|
||||
void setHasCallToGetArgs(bool f) { m_hasCallToGetArgs = f; }
|
||||
bool hasCallToGetArgs() const { return m_hasCallToGetArgs; }
|
||||
|
||||
protected:
|
||||
bool m_method;
|
||||
bool m_ref;
|
||||
bool m_hasCallToGetArgs;
|
||||
int m_attribute;
|
||||
int m_cppLength;
|
||||
ModifierExpressionPtr m_modifiers;
|
||||
|
||||
@@ -3680,13 +3680,12 @@ ArrayIdx [C C C] -> [C]
|
||||
14. Continuation creation and execution
|
||||
---------------------------------------
|
||||
|
||||
CreateCont <getargs> <function name> [] -> [C]
|
||||
CreateCont <function name> [] -> [C]
|
||||
|
||||
Creates a GenericContinuation object and pushes it on the stack. The
|
||||
Continuation will capture all defined local variables in the current
|
||||
function, and if the <getargs> immediate is nonzero it will also store the
|
||||
result of func_get_args(). The Continuation will store a reference to the
|
||||
function named by the string immediate to be used as its body.
|
||||
Creates a Continuation object and pushes it on the stack. The Continuation
|
||||
will capture all defined local variables in the current function. The
|
||||
Continuation will store a reference to the function named by the string
|
||||
immediate to be used as its body.
|
||||
|
||||
ContEnter [] -> []
|
||||
|
||||
|
||||
@@ -93,40 +93,6 @@
|
||||
"args": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "num_args",
|
||||
"return": {
|
||||
"type": "Int64"
|
||||
},
|
||||
"flags": [
|
||||
],
|
||||
"args": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get_args",
|
||||
"return": {
|
||||
"type": "VariantVec"
|
||||
},
|
||||
"flags": [
|
||||
],
|
||||
"args": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "get_arg",
|
||||
"return": {
|
||||
"type": "Variant"
|
||||
},
|
||||
"args": [
|
||||
{
|
||||
"name": "id",
|
||||
"type": "Int64"
|
||||
}
|
||||
],
|
||||
"flags": [
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "current",
|
||||
"return": {
|
||||
|
||||
@@ -436,10 +436,9 @@ public:
|
||||
const Func* origFunc,
|
||||
const Func* genFunc,
|
||||
ObjectData* thisPtr,
|
||||
ArrayData* args,
|
||||
Class* frameStaticCls);
|
||||
template<bool isMethod>
|
||||
static c_Continuation* createContinuation(ActRec* fp, bool getArgs,
|
||||
static c_Continuation* createContinuation(ActRec* fp,
|
||||
const Func* origFunc,
|
||||
const Func* genFunc);
|
||||
static c_Continuation* fillContinuationVars(
|
||||
|
||||
@@ -91,19 +91,6 @@ int64_t c_Continuation::t_getlabel() {
|
||||
return m_label;
|
||||
}
|
||||
|
||||
int64_t c_Continuation::t_num_args() {
|
||||
return m_args.size();
|
||||
}
|
||||
|
||||
Array c_Continuation::t_get_args() {
|
||||
return m_args;
|
||||
}
|
||||
|
||||
Variant c_Continuation::t_get_arg(int64_t id) {
|
||||
if (id < 0LL || id >= m_args.size()) return false;
|
||||
return m_args.rvalAt(id, AccessFlags::Error);
|
||||
}
|
||||
|
||||
Variant c_Continuation::t_current() {
|
||||
const_assert(false);
|
||||
return m_value;
|
||||
|
||||
@@ -45,13 +45,6 @@ class c_Continuation : public ExtObjectData {
|
||||
~c_Continuation();
|
||||
|
||||
public:
|
||||
void init(const Func* origFunc,
|
||||
ArrayData* args) noexcept {
|
||||
m_origFunc = const_cast<Func*>(origFunc);
|
||||
assert(m_origFunc);
|
||||
m_args = args;
|
||||
}
|
||||
|
||||
bool done() const { return o_subclassData.u8[0]; }
|
||||
bool running() const { return o_subclassData.u8[1]; }
|
||||
void setDone(bool done) { o_subclassData.u8[0] = done; }
|
||||
@@ -67,9 +60,6 @@ public:
|
||||
void t_update(int64_t label, CVarRef value);
|
||||
Object t_getwaithandle();
|
||||
int64_t t_getlabel();
|
||||
int64_t t_num_args();
|
||||
Array t_get_args();
|
||||
Variant t_get_arg(int64_t id);
|
||||
Variant t_current();
|
||||
int64_t t_key();
|
||||
void t_next();
|
||||
@@ -81,14 +71,17 @@ public:
|
||||
String t_getcalledclass();
|
||||
Variant t___clone();
|
||||
|
||||
static c_Continuation* alloc(Class* cls, int nLocals, int nIters) {
|
||||
static c_Continuation* alloc(const Func* origFunc, int nLocals, int nIters) {
|
||||
assert(origFunc);
|
||||
|
||||
size_t arOffset = sizeof(c_Continuation) + sizeof(Iter) * nIters +
|
||||
sizeof(TypedValue) * nLocals;
|
||||
arOffset += sizeof(TypedValue) - 1;
|
||||
arOffset &= ~(sizeof(TypedValue) - 1);
|
||||
c_Continuation* cont =
|
||||
(c_Continuation*)ALLOCOBJSZ(arOffset + sizeof(ActRec));
|
||||
new ((void *)cont) c_Continuation(cls);
|
||||
new ((void *)cont) c_Continuation();
|
||||
cont->m_origFunc = const_cast<Func*>(origFunc);
|
||||
cont->m_arPtr = (ActRec*)(uintptr_t(cont) + arOffset);
|
||||
memset((void*)((uintptr_t)cont + sizeof(c_Continuation)), 0,
|
||||
arOffset - sizeof(c_Continuation));
|
||||
@@ -129,7 +122,6 @@ public:
|
||||
Variant m_received;
|
||||
Func *m_origFunc;
|
||||
ActRec* m_arPtr;
|
||||
Array m_args;
|
||||
p_ContinuationWaitHandle m_waitHandle;
|
||||
|
||||
String& getCalledClass() { not_reached(); }
|
||||
|
||||
@@ -6986,16 +6986,14 @@ c_Continuation*
|
||||
VMExecutionContext::createContinuationHelper(const Func* origFunc,
|
||||
const Func* genFunc,
|
||||
ObjectData* thisPtr,
|
||||
ArrayData* args,
|
||||
Class* frameStaticCls) {
|
||||
auto const cont = c_Continuation::alloc(
|
||||
SystemLib::s_ContinuationClass,
|
||||
origFunc,
|
||||
genFunc->numLocals(),
|
||||
genFunc->numIterators()
|
||||
);
|
||||
cont->incRefCount();
|
||||
cont->setNoDestruct();
|
||||
cont->init(origFunc, args);
|
||||
|
||||
// The ActRec corresponding to the generator body lives as long as the object
|
||||
// does. We set it up once, here, and then just change FP to point to it when
|
||||
@@ -7035,21 +7033,14 @@ VMExecutionContext::createContinuationHelper(const Func* origFunc,
|
||||
template<bool isMethod>
|
||||
c_Continuation*
|
||||
VMExecutionContext::createContinuation(ActRec* fp,
|
||||
bool getArgs,
|
||||
const Func* origFunc,
|
||||
const Func* genFunc) {
|
||||
ObjectData* const thisPtr = fp->hasThis() ? fp->getThis() : nullptr;
|
||||
|
||||
Array args;
|
||||
if (getArgs) {
|
||||
args = hhvm_get_frame_args(fp);
|
||||
}
|
||||
|
||||
return createContinuationHelper<isMethod>(
|
||||
origFunc,
|
||||
genFunc,
|
||||
thisPtr,
|
||||
args.get(),
|
||||
frameStaticClass(fp)
|
||||
);
|
||||
}
|
||||
@@ -7118,17 +7109,16 @@ VMExecutionContext::fillContinuationVars(ActRec* fp,
|
||||
|
||||
// Explicitly instantiate for hhbctranslator.o and codegen.o
|
||||
template c_Continuation* VMExecutionContext::createContinuation<true>(
|
||||
ActRec*, bool, const Func*, const Func*);
|
||||
ActRec*, const Func*, const Func*);
|
||||
template c_Continuation* VMExecutionContext::createContinuation<false>(
|
||||
ActRec*, bool, const Func*, const Func*);
|
||||
ActRec*, const Func*, const Func*);
|
||||
template c_Continuation* VMExecutionContext::createContinuationHelper<true>(
|
||||
const Func*, const Func*, ObjectData*, ArrayData*, Class*);
|
||||
const Func*, const Func*, ObjectData*, Class*);
|
||||
template c_Continuation* VMExecutionContext::createContinuationHelper<false>(
|
||||
const Func*, const Func*, ObjectData*, ArrayData*, Class*);
|
||||
const Func*, const Func*, ObjectData*, Class*);
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopCreateCont(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IVA(getArgs);
|
||||
DECODE_LITSTR(genName);
|
||||
|
||||
const Func* origFunc = m_fp->m_func;
|
||||
@@ -7137,8 +7127,8 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCreateCont(PC& pc) {
|
||||
|
||||
bool isMethod = origFunc->isMethod();
|
||||
c_Continuation* cont = isMethod ?
|
||||
createContinuation<true>(m_fp, getArgs, origFunc, genFunc) :
|
||||
createContinuation<false>(m_fp, getArgs, origFunc, genFunc);
|
||||
createContinuation<true>(m_fp, origFunc, genFunc) :
|
||||
createContinuation<false>(m_fp, origFunc, genFunc);
|
||||
|
||||
fillContinuationVars(m_fp, origFunc, genFunc, cont);
|
||||
|
||||
|
||||
@@ -546,7 +546,7 @@ enum SetOpOp {
|
||||
O(LateBoundCls, NA, NOV, ONE(AV), NF) \
|
||||
O(NativeImpl, NA, NOV, NOV, CF_TF) \
|
||||
O(CreateCl, TWO(IVA,SA), CVMANY, ONE(CV), NF) \
|
||||
O(CreateCont, TWO(IVA,SA), NOV, ONE(CV), NF) \
|
||||
O(CreateCont, ONE(SA), NOV, ONE(CV), NF) \
|
||||
O(ContEnter, NA, NOV, NOV, CF) \
|
||||
O(ContExit, NA, NOV, NOV, CF) \
|
||||
O(UnpackCont, NA, NOV, TWO(CV,CV), NF) \
|
||||
|
||||
@@ -3499,7 +3499,6 @@ void CodeGenerator::cgInlineCreateCont(IRInstruction* inst) {
|
||||
.immPtr(data.origFunc)
|
||||
.immPtr(data.genFunc)
|
||||
.ssa(inst->src(0))
|
||||
.immPtr(nullptr) // getArgs array
|
||||
// Deliberately ignoring frameStaticClass parameter, because
|
||||
// it's unused if we have a $this pointer, and we don't inline
|
||||
// functions with a null $this.
|
||||
|
||||
@@ -467,8 +467,8 @@ void optimizeActRecs(IRTrace* trace, DceState& state, IRFactory* factory,
|
||||
FTRACE(5, "CreateCont ({}) -> InlineCreateCont\n", inst->id());
|
||||
|
||||
CreateContData data;
|
||||
data.origFunc = inst->src(3)->getValFunc();
|
||||
data.genFunc = inst->src(4)->getValFunc();
|
||||
data.origFunc = inst->src(2)->getValFunc();
|
||||
data.genFunc = inst->src(3)->getValFunc();
|
||||
|
||||
assert(fp->inst()->src(0)->inst()->op() == SpillFrame);
|
||||
auto const thisPtr = fp->inst()->src(0)->inst()->src(3);
|
||||
|
||||
@@ -998,8 +998,7 @@ bool mapContParams(ContParamMap& map,
|
||||
return true;
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCreateCont(bool getArgs,
|
||||
Id funNameStrId) {
|
||||
void HhbcTranslator::emitCreateCont(Id funNameStrId) {
|
||||
gen(ExitOnVarEnv, getExitSlowTrace()->front(), m_tb->fp());
|
||||
|
||||
auto const genName = lookupStringId(funNameStrId);
|
||||
@@ -1015,7 +1014,6 @@ void HhbcTranslator::emitCreateCont(bool getArgs,
|
||||
(TCA)&VMExecutionContext::createContinuation<false>
|
||||
),
|
||||
m_tb->fp(),
|
||||
cns(getArgs),
|
||||
cns(origFunc),
|
||||
cns(genFunc)
|
||||
);
|
||||
|
||||
@@ -358,7 +358,7 @@ struct HhbcTranslator {
|
||||
void emitVerifyParamType(uint32_t paramId);
|
||||
|
||||
// continuations
|
||||
void emitCreateCont(bool getArgs, Id funNameStrId);
|
||||
void emitCreateCont(Id funNameStrId);
|
||||
void emitContEnter(int32_t returnBcOffset);
|
||||
void emitContExitImpl();
|
||||
void emitContExit();
|
||||
|
||||
@@ -436,7 +436,6 @@ O(Spill, DofS(0), SUnk, Mem) \
|
||||
O(Reload, DofS(0), SUnk, Mem) \
|
||||
O(CreateCont, D(Obj), C(TCA) \
|
||||
S(FramePtr) \
|
||||
C(Bool) \
|
||||
C(Func) \
|
||||
C(Func), E|N|Mem|PRc) \
|
||||
O(InlineCreateCont, D(Obj), S(Obj,Null), E|N|PRc) \
|
||||
|
||||
@@ -546,7 +546,7 @@ void Translator::translateDup(const NormalizedInstruction& ni) {
|
||||
}
|
||||
|
||||
void Translator::translateCreateCont(const NormalizedInstruction& i) {
|
||||
HHIR_EMIT(CreateCont, i.imm[0].u_IVA, i.imm[1].u_SA);
|
||||
HHIR_EMIT(CreateCont, i.imm[0].u_SA);
|
||||
}
|
||||
|
||||
void Translator::translateContEnter(const NormalizedInstruction& i) {
|
||||
@@ -1198,7 +1198,7 @@ bool shouldIRInline(const Func* curFunc,
|
||||
* Continuation allocation functions that take no arguments.
|
||||
*/
|
||||
resetCursor();
|
||||
if (current == OpCreateCont && cursor->imm[0].u_IVA == 0) {
|
||||
if (current == OpCreateCont) {
|
||||
if (func->numParams()) {
|
||||
FTRACE(1, "CreateCont with {} args\n", func->numParams());
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ static CallMap s_callMap({
|
||||
|
||||
/* Continuation support helpers */
|
||||
{CreateCont, {FSSA, 0}, DSSA, SNone,
|
||||
{{SSA, 1}, {SSA, 2}, {SSA, 3}, {SSA, 4}}},
|
||||
{{SSA, 1}, {SSA, 2}, {SSA, 3}}},
|
||||
{InlineCreateCont, nullptr, DSSA, SSync,
|
||||
{{Immed}, {Immed}, {SSA, 0}}},
|
||||
{FillContLocals, (TCA)&VMExecutionContext::fillContinuationVars,
|
||||
|
||||
@@ -24092,22 +24092,6 @@ const char *g_class_map[] = {
|
||||
(const char *)0xa /* KindOfInt64 */, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "num_args", "", (const char*)0, (const char*)0,
|
||||
" /**\n * ( excerpt from http://php.net/manual/en/continuation.num-args.php )\n *\n *\n * @return int\n */",
|
||||
(const char *)0xa /* KindOfInt64 */, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "get_args", "", (const char*)0, (const char*)0,
|
||||
" /**\n * ( excerpt from http://php.net/manual/en/continuation.get-args.php )\n *\n *\n * @return vector\n */",
|
||||
(const char *)0x20 /* KindOfArray */, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "get_arg", "", (const char*)0, (const char*)0,
|
||||
" /**\n * ( excerpt from http://php.net/manual/en/continuation.get-arg.php )\n *\n *\n * @id int\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff /* KindOfUnknown: $t: Variant */, (const char *)0x2000, "id", "", (const char *)0xa /* KindOfInt64 */, "", (const char *)0, "", (const char *)0, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
(const char *)0x10006040, "current", "", (const char*)0, (const char*)0,
|
||||
" /**\n * ( excerpt from http://php.net/manual/en/continuation.current.php )\n *\n *\n * @return mixed\n */",
|
||||
(const char *)0xffffffff /* KindOfUnknown: $t: Variant */, NULL,
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
function func_num_args_simple() {
|
||||
return func_num_args();
|
||||
}
|
||||
|
||||
function func_get_args_simple() {
|
||||
return func_get_args();
|
||||
}
|
||||
|
||||
function func_get_arg_simple($idx) {
|
||||
return func_get_arg($idx);
|
||||
}
|
||||
|
||||
function func_num_args_arg($arg) {
|
||||
return func_num_args();
|
||||
}
|
||||
|
||||
function func_get_args_arg($arg) {
|
||||
return func_get_args();
|
||||
}
|
||||
|
||||
function func_get_arg_arg($arg, $idx) {
|
||||
return func_get_arg($idx);
|
||||
}
|
||||
|
||||
function func_num_args_varenv($dst, $src) {
|
||||
$$dst = $src;
|
||||
return func_num_args();
|
||||
}
|
||||
|
||||
function func_get_args_varenv($dst, $src) {
|
||||
$$dst = $src;
|
||||
return func_get_args();
|
||||
}
|
||||
|
||||
function func_get_arg_varenv($dst, $src, $idx) {
|
||||
$$dst = $src;
|
||||
return func_get_arg($idx);
|
||||
}
|
||||
|
||||
function test(string $generator, array $args) {
|
||||
var_dump(call_user_func_array($generator, $args));
|
||||
}
|
||||
|
||||
function test_num_args(string $type, array $extra_args) {
|
||||
test(
|
||||
'func_num_args_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function test_get_args(string $type, array $extra_args) {
|
||||
test(
|
||||
'func_get_args_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function test_get_arg(string $type, array $extra_args) {
|
||||
$cnt = count($extra_args) + func_num_args() - 1;
|
||||
|
||||
for ($i = -1; $i <= $cnt; ++$i) {
|
||||
test(
|
||||
'func_get_arg_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
array($i),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$extra_args_set = array(
|
||||
array(),
|
||||
array('hello'),
|
||||
array('hello', 47),
|
||||
);
|
||||
|
||||
foreach ($extra_args_set as $extra_args) {
|
||||
test_num_args('simple', $extra_args);
|
||||
test_get_args('simple', $extra_args);
|
||||
test_get_arg('simple', $extra_args);
|
||||
|
||||
test_num_args('arg', $extra_args, 'defined_arg');
|
||||
test_get_args('arg', $extra_args, 'defined_arg');
|
||||
test_get_arg('arg', $extra_args, 'defined_arg');
|
||||
|
||||
foreach (array('dst', 'src', 'idx', 'undef') as $dst) {
|
||||
test_num_args('varenv', $extra_args, $dst, 'replacement');
|
||||
test_get_args('varenv', $extra_args, $dst, 'replacement');
|
||||
test_get_arg('varenv', $extra_args, $dst, 'replacement');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
int(0)
|
||||
array(0) {
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
int(0)
|
||||
HipHop Warning: func_get_arg(): Argument 1 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(1)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
HipHop Warning: func_get_arg(): Argument 2 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(11) "replacement"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "replacement"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
HipHop Warning: func_get_arg(): Argument 3 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
HipHop Warning: func_get_arg(): Argument 3 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
HipHop Warning: func_get_arg(): Argument 3 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(1)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
int(0)
|
||||
string(5) "hello"
|
||||
HipHop Warning: func_get_arg(): Argument 2 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
[1]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
string(5) "hello"
|
||||
HipHop Warning: func_get_arg(): Argument 3 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(11) "replacement"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "replacement"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
HipHop Warning: func_get_arg(): Argument 4 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
HipHop Warning: func_get_arg(): Argument 4 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
HipHop Warning: func_get_arg(): Argument 4 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(5) "hello"
|
||||
[1]=>
|
||||
int(47)
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
int(0)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
HipHop Warning: func_get_arg(): Argument 3 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
[1]=>
|
||||
string(5) "hello"
|
||||
[2]=>
|
||||
int(47)
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
HipHop Warning: func_get_arg(): Argument 4 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(11) "replacement"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(11) "replacement"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
HipHop Warning: func_get_arg(): Argument 5 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
HipHop Warning: func_get_arg(): Argument 5 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
HipHop Warning: func_get_arg(): The argument number should be >= 0 in %s on line %d
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
HipHop Warning: func_get_arg(): Argument 5 not passed to function in %s on line %d
|
||||
bool(false)
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
function gen_func_num_args_simple() {
|
||||
yield func_num_args();
|
||||
}
|
||||
|
||||
function gen_func_get_args_simple() {
|
||||
yield func_get_args();
|
||||
}
|
||||
|
||||
function gen_func_get_arg_simple($idx) {
|
||||
yield func_get_arg($idx);
|
||||
}
|
||||
|
||||
function gen_func_num_args_arg($arg) {
|
||||
yield func_num_args();
|
||||
}
|
||||
|
||||
function gen_func_get_args_arg($arg) {
|
||||
yield func_get_args();
|
||||
}
|
||||
|
||||
function gen_func_get_arg_arg($arg, $idx) {
|
||||
yield func_get_arg($idx);
|
||||
}
|
||||
|
||||
function gen_func_num_args_varenv($dst, $src) {
|
||||
$$dst = $src;
|
||||
yield func_num_args();
|
||||
}
|
||||
|
||||
function gen_func_get_args_varenv($dst, $src) {
|
||||
$$dst = $src;
|
||||
yield func_get_args();
|
||||
}
|
||||
|
||||
function gen_func_get_arg_varenv($dst, $src, $idx) {
|
||||
$$dst = $src;
|
||||
yield func_get_arg($idx);
|
||||
}
|
||||
|
||||
function test(string $generator, array $args) {
|
||||
$gen = call_user_func_array($generator, $args);
|
||||
foreach ($gen as $val) {
|
||||
var_dump($val);
|
||||
}
|
||||
}
|
||||
|
||||
function test_num_args(string $type, array $extra_args) {
|
||||
test(
|
||||
'gen_func_num_args_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function test_get_args(string $type, array $extra_args) {
|
||||
test(
|
||||
'gen_func_get_args_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function test_get_arg(string $type, array $extra_args) {
|
||||
$cnt = count($extra_args) + func_num_args() - 1;
|
||||
|
||||
for ($i = -1; $i <= $cnt; ++$i) {
|
||||
test(
|
||||
'gen_func_get_arg_'.$type,
|
||||
array_merge(
|
||||
array_slice(func_get_args(), 2),
|
||||
array($i),
|
||||
$extra_args
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$extra_args_set = array(
|
||||
array(),
|
||||
array('hello'),
|
||||
array('hello', 47),
|
||||
);
|
||||
|
||||
foreach ($extra_args_set as $extra_args) {
|
||||
test_num_args('simple', $extra_args);
|
||||
test_get_args('simple', $extra_args);
|
||||
test_get_arg('simple', $extra_args);
|
||||
|
||||
test_num_args('arg', $extra_args, 'defined_arg');
|
||||
test_get_args('arg', $extra_args, 'defined_arg');
|
||||
test_get_arg('arg', $extra_args, 'defined_arg');
|
||||
|
||||
foreach (array('dst', 'src', 'idx', 'undef') as $dst) {
|
||||
test_num_args('varenv', $extra_args, $dst, 'replacement');
|
||||
test_get_args('varenv', $extra_args, $dst, 'replacement');
|
||||
test_get_arg('varenv', $extra_args, $dst, 'replacement');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
int(0)
|
||||
array(0) {
|
||||
}
|
||||
bool(false)
|
||||
int(0)
|
||||
bool(false)
|
||||
int(1)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
}
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "dst"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
bool(false)
|
||||
string(3) "dst"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
}
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
bool(false)
|
||||
int(1)
|
||||
array(1) {
|
||||
[0]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
bool(false)
|
||||
int(0)
|
||||
string(5) "hello"
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
[1]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
string(5) "hello"
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(3) "dst"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
bool(false)
|
||||
string(3) "dst"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
}
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
bool(false)
|
||||
int(2)
|
||||
array(2) {
|
||||
[0]=>
|
||||
string(5) "hello"
|
||||
[1]=>
|
||||
int(47)
|
||||
}
|
||||
bool(false)
|
||||
int(0)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
bool(false)
|
||||
int(3)
|
||||
array(3) {
|
||||
[0]=>
|
||||
string(11) "defined_arg"
|
||||
[1]=>
|
||||
string(5) "hello"
|
||||
[2]=>
|
||||
int(47)
|
||||
}
|
||||
bool(false)
|
||||
string(11) "defined_arg"
|
||||
int(1)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "dst"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
bool(false)
|
||||
string(3) "dst"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "src"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
bool(false)
|
||||
string(3) "src"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
bool(false)
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(3) "idx"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
string(3) "idx"
|
||||
int(4)
|
||||
array(4) {
|
||||
[0]=>
|
||||
string(5) "undef"
|
||||
[1]=>
|
||||
string(11) "replacement"
|
||||
[2]=>
|
||||
string(5) "hello"
|
||||
[3]=>
|
||||
int(47)
|
||||
}
|
||||
bool(false)
|
||||
string(5) "undef"
|
||||
string(11) "replacement"
|
||||
int(2)
|
||||
string(5) "hello"
|
||||
int(47)
|
||||
bool(false)
|
||||
@@ -170,7 +170,7 @@ void prepare_generator(Parser *_p, Token &stmt, Token ¶ms) {
|
||||
// create a generator function with original name and parameters
|
||||
void create_generator(Parser *_p, Token &out, Token ¶ms,
|
||||
Token &name, const std::string &closureName,
|
||||
const char *clsname, Token *modifiers, bool getArgs,
|
||||
const char *clsname, Token *modifiers,
|
||||
Token &origGenFunc, bool isHhvm, Token *attr) {
|
||||
_p->pushFuncLocation();
|
||||
if (clsname) {
|
||||
@@ -203,18 +203,12 @@ void create_generator(Parser *_p, Token &out, Token ¶ms,
|
||||
_p->onCallParam(param1, ¶m1, fname, false);
|
||||
_p->onCallParam(param1, ¶m1, oname, false);
|
||||
|
||||
if (getArgs) {
|
||||
Token cname; cname.setText("func_get_args");
|
||||
Token empty;
|
||||
Token call; _p->onCall(call, false, cname, empty, NULL);
|
||||
_p->onCallParam(param1, ¶m1, call, false);
|
||||
}
|
||||
Token stmts0; _p->onStatementListStart(stmts0);
|
||||
|
||||
Token cname0; cname0.setText("hphp_create_continuation");
|
||||
Token call; _p->onCall(call, false, cname0, param1, NULL, true);
|
||||
Token ret; _p->onReturn(ret, &call);
|
||||
|
||||
Token stmts0; _p->onStatementListStart(stmts0);
|
||||
Token stmts1; _p->addStatement(stmts1, stmts0, ret);
|
||||
_p->finishStatement(scont, stmts1); scont = 1;
|
||||
}
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário