function and constant fallback for namespaces
It turned out a lot of the namespace stuff still worked. The biggest thing for the first pass is that we don't fallback to the global function or constant if there isn't a namespaced one. Also, when a constant has a ##\## anywhere in it it throw an error when it isn't defined, instead of assuming the string.
Esse commit está contido em:
@@ -1824,7 +1824,7 @@ static DataType getPredictedDataType(ExpressionPtr expr) {
|
||||
}
|
||||
|
||||
void EmitterVisitor::fixReturnType(Emitter& e, FunctionCallPtr fn,
|
||||
bool isBuiltinCall) {
|
||||
bool useFCallBuiltin) {
|
||||
int ref = -1;
|
||||
if (fn->hasAnyContext(Expression::RefValue |
|
||||
Expression::DeepReference |
|
||||
@@ -1867,7 +1867,7 @@ void EmitterVisitor::fixReturnType(Emitter& e, FunctionCallPtr fn,
|
||||
} else if (!ref) {
|
||||
DataType dt = getPredictedDataType(fn);
|
||||
if (dt != KindOfUnknown) {
|
||||
if (isBuiltinCall) {
|
||||
if (useFCallBuiltin) {
|
||||
switch (dt) {
|
||||
case KindOfBoolean:
|
||||
case KindOfInt64:
|
||||
@@ -3033,8 +3033,20 @@ bool EmitterVisitor::visitImpl(ConstructPtr node) {
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
StringData* nName = StringData::GetStaticString(c->getName());
|
||||
e.Cns(nName);
|
||||
std::string nameStr = c->getOriginalName();
|
||||
StringData* nName = StringData::GetStaticString(nameStr);
|
||||
if (c->hadBackslash()) {
|
||||
e.CnsE(nName);
|
||||
} else {
|
||||
const std::string& nonNSName = c->getNonNSOriginalName();
|
||||
if (nonNSName != nameStr) {
|
||||
StringData* nsName = nName;
|
||||
nName = StringData::GetStaticString(nonNSName);
|
||||
e.CnsU(nsName, nName);
|
||||
} else {
|
||||
e.Cns(StringData::GetStaticString(c->getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -5860,7 +5872,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
const std::string& nameStr = node->getOriginalName();
|
||||
ExpressionListPtr params(node->getParams());
|
||||
int numParams = params ? params->getCount() : 0;
|
||||
bool isBuiltinCall = false;
|
||||
bool useFCallBuiltin = false;
|
||||
StringData* nLiteral = nullptr;
|
||||
Offset fpiStart;
|
||||
if (node->getClass() || !node->getClassName().empty()) {
|
||||
@@ -5900,12 +5912,27 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
} else if (!nameStr.empty()) {
|
||||
// foo()
|
||||
nLiteral = StringData::GetStaticString(nameStr);
|
||||
isBuiltinCall = canEmitBuiltinCall(node, nameStr, numParams);
|
||||
useFCallBuiltin = canEmitBuiltinCall(node, nameStr, numParams);
|
||||
|
||||
if (isBuiltinCall) {
|
||||
StringData* nsName = nullptr;
|
||||
if (!node->hadBackslash()) {
|
||||
const std::string& nonNSName = node->getNonNSOriginalName();
|
||||
if (nonNSName != nameStr) {
|
||||
nsName = nLiteral;
|
||||
nLiteral = StringData::GetStaticString(nonNSName);
|
||||
useFCallBuiltin = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (useFCallBuiltin) {
|
||||
} else if (!m_curFunc->isGenerator()) {
|
||||
fpiStart = m_ue.bcPos();
|
||||
e.FPushFuncD(numParams, nLiteral);
|
||||
|
||||
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;
|
||||
@@ -5926,7 +5953,9 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
specialMethodName = s_get_arg;
|
||||
}
|
||||
|
||||
if (specialMethodName != nullptr) {
|
||||
if (nsName != nullptr) {
|
||||
e.FPushFuncU(numParams, nsName, nLiteral);
|
||||
} else if (specialMethodName != nullptr) {
|
||||
emitVirtualLocal(contId);
|
||||
emitCGet(e);
|
||||
fpiStart = m_ue.bcPos();
|
||||
@@ -5944,7 +5973,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
fpiStart = m_ue.bcPos();
|
||||
e.FPushFunc(numParams);
|
||||
}
|
||||
if (isBuiltinCall) {
|
||||
if (useFCallBuiltin) {
|
||||
FunctionScopePtr func = node->getFuncScope();
|
||||
assert(func);
|
||||
assert(numParams <= func->getMaxParamCount()
|
||||
@@ -5972,7 +6001,7 @@ void EmitterVisitor::emitFuncCall(Emitter& e, FunctionCallPtr node) {
|
||||
e.FCall(numParams);
|
||||
}
|
||||
if (Option::WholeProgram) {
|
||||
fixReturnType(e, node, isBuiltinCall);
|
||||
fixReturnType(e, node, useFCallBuiltin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,8 @@ void FileScope::cleanupForError(AnalysisResultConstPtr ar,
|
||||
ExpressionListPtr args(new ExpressionList(scope, loc));
|
||||
args->addElement(Expression::MakeScalarExpression(ar, scope, loc, msg));
|
||||
SimpleFunctionCallPtr e(
|
||||
new SimpleFunctionCall(scope, loc, "throw_fatal", args, ExpressionPtr()));
|
||||
new SimpleFunctionCall(scope, loc, "throw_fatal", false, args,
|
||||
ExpressionPtr()));
|
||||
e->setThrowFatal();
|
||||
ExpStatementPtr exp(new ExpStatement(scope, loc, e));
|
||||
StatementListPtr stmts(new StatementList(scope, loc));
|
||||
|
||||
@@ -412,7 +412,7 @@ static ExpressionPtr makeIsNull(AnalysisResultConstPtr ar,
|
||||
|
||||
SimpleFunctionCallPtr call
|
||||
(new SimpleFunctionCall(exp->getScope(), loc,
|
||||
"is_null", expList, ExpressionPtr()));
|
||||
"is_null", false, expList, ExpressionPtr()));
|
||||
|
||||
call->setValid();
|
||||
call->setActualType(Type::Boolean);
|
||||
|
||||
@@ -37,10 +37,11 @@ using namespace HPHP;
|
||||
|
||||
ConstantExpression::ConstantExpression
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const string &name, const string &docComment)
|
||||
const string &name, bool hadBackslash, const string &docComment)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ConstantExpression)),
|
||||
m_name(name), m_docComment(docComment),
|
||||
m_valid(false), m_dynamic(false), m_visited(false), m_depsSet(false) {
|
||||
m_name(name), m_origName(name), m_hadBackslash(hadBackslash),
|
||||
m_docComment(docComment), m_valid(false), m_dynamic(false),
|
||||
m_visited(false), m_depsSet(false) {
|
||||
}
|
||||
|
||||
void ConstantExpression::onParse(AnalysisResultConstPtr ar,
|
||||
|
||||
@@ -30,6 +30,7 @@ class ConstantExpression : public Expression, IParseHandler {
|
||||
public:
|
||||
ConstantExpression(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &name,
|
||||
bool hadBackslash,
|
||||
const std::string &docComment = "");
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
@@ -50,6 +51,14 @@ public:
|
||||
virtual bool canonCompare(ExpressionPtr e) const;
|
||||
|
||||
const std::string &getName() const { return m_name;}
|
||||
const std::string &getOriginalName() const { return m_origName;}
|
||||
const std::string getNonNSOriginalName() const {
|
||||
int nsPos = m_origName.rfind('\\');
|
||||
if (nsPos == string::npos) {
|
||||
return m_origName;
|
||||
}
|
||||
return m_origName.substr(nsPos + 1);
|
||||
}
|
||||
const std::string &getDocComment() const {
|
||||
return m_docComment;
|
||||
}
|
||||
@@ -64,10 +73,13 @@ public:
|
||||
std::string getComment() { return m_comment;}
|
||||
bool isValid() const { return m_valid; }
|
||||
bool isDynamic() const { return m_dynamic; }
|
||||
bool hadBackslash() const { return m_hadBackslash; }
|
||||
private:
|
||||
|
||||
Symbol *resolveNS(AnalysisResultConstPtr ar);
|
||||
std::string m_name;
|
||||
std::string m_origName;
|
||||
bool m_hadBackslash;
|
||||
std::string m_docComment;
|
||||
std::string m_comment; // for inlined constant name
|
||||
bool m_valid;
|
||||
|
||||
@@ -34,7 +34,7 @@ DynamicFunctionCall::DynamicFunctionCall
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr name, ExpressionListPtr params, ExpressionPtr cls)
|
||||
: FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(DynamicFunctionCall),
|
||||
name, "", params, cls) {
|
||||
name, "", false, params, cls) {
|
||||
}
|
||||
|
||||
ExpressionPtr DynamicFunctionCall::clone() {
|
||||
@@ -84,7 +84,7 @@ ExpressionPtr DynamicFunctionCall::preOptimize(AnalysisResultConstPtr ar) {
|
||||
}
|
||||
return ExpressionPtr(NewSimpleFunctionCall(
|
||||
getScope(), getLocation(),
|
||||
name, m_params, cls));
|
||||
name, false, m_params, cls));
|
||||
}
|
||||
}
|
||||
return ExpressionPtr();
|
||||
|
||||
@@ -506,7 +506,7 @@ ExpressionPtr Expression::MakeConstant(AnalysisResultConstPtr ar,
|
||||
const std::string &value) {
|
||||
ConstantExpressionPtr exp(new ConstantExpression(
|
||||
scope, loc,
|
||||
value));
|
||||
value, false));
|
||||
if (value == "true" || value == "false") {
|
||||
if (ar->getPhase() >= AnalysisResult::PostOptimize) {
|
||||
exp->m_actualType = Type::Boolean;
|
||||
|
||||
@@ -44,15 +44,15 @@ using namespace HPHP;
|
||||
|
||||
FunctionCall::FunctionCall
|
||||
(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS,
|
||||
ExpressionPtr nameExp, const std::string &name, ExpressionListPtr params,
|
||||
ExpressionPtr classExp)
|
||||
ExpressionPtr nameExp, const std::string &name, bool hadBackslash,
|
||||
ExpressionListPtr params, ExpressionPtr classExp)
|
||||
: Expression(EXPRESSION_CONSTRUCTOR_BASE_PARAMETER_VALUES),
|
||||
StaticClassName(classExp), m_nameExp(nameExp),
|
||||
m_ciTemp(-1), m_params(params), m_valid(false),
|
||||
m_extraArg(0), m_variableArgument(false), m_voidReturn(false),
|
||||
m_voidWrapper(false), m_redeclared(false),
|
||||
m_noStatic(false), m_noInline(false), m_invokeFewArgsDecision(true),
|
||||
m_arrayParams(false),
|
||||
m_arrayParams(false), m_hadBackslash(hadBackslash),
|
||||
m_argArrayId(-1), m_argArrayHash(-1), m_argArrayIndex(-1) {
|
||||
|
||||
if (m_nameExp &&
|
||||
|
||||
@@ -30,8 +30,8 @@ DECLARE_BOOST_TYPES(FunctionCall);
|
||||
class FunctionCall : public Expression, public StaticClassName {
|
||||
protected:
|
||||
FunctionCall(EXPRESSION_CONSTRUCTOR_BASE_PARAMETERS, ExpressionPtr nameExp,
|
||||
const std::string &name, ExpressionListPtr params,
|
||||
ExpressionPtr classExp);
|
||||
const std::string &name, bool hadBackslash,
|
||||
ExpressionListPtr params, ExpressionPtr classExp);
|
||||
public:
|
||||
void analyzeProgram(AnalysisResultPtr ar);
|
||||
|
||||
@@ -47,6 +47,13 @@ public:
|
||||
|
||||
const std::string &getName() const { return m_name; }
|
||||
const std::string &getOriginalName() const { return m_origName; }
|
||||
const std::string getNonNSOriginalName() const {
|
||||
int nsPos = m_origName.rfind('\\');
|
||||
if (nsPos == string::npos) {
|
||||
return m_origName;
|
||||
}
|
||||
return m_origName.substr(nsPos + 1);
|
||||
}
|
||||
ExpressionPtr getNameExp() const { return m_nameExp; }
|
||||
const ExpressionListPtr& getParams() const { return m_params; }
|
||||
void setNoInline() { m_noInline = true; }
|
||||
@@ -56,6 +63,7 @@ public:
|
||||
bool canInvokeFewArgs();
|
||||
void setArrayParams() { m_arrayParams = true; }
|
||||
bool isValid() const { return m_valid; }
|
||||
bool hadBackslash() const { return m_hadBackslash; }
|
||||
|
||||
protected:
|
||||
ExpressionPtr m_nameExp;
|
||||
@@ -81,6 +89,7 @@ protected:
|
||||
unsigned m_noInline : 1;
|
||||
unsigned m_invokeFewArgsDecision : 1;
|
||||
unsigned m_arrayParams : 1;
|
||||
bool m_hadBackslash;
|
||||
|
||||
// Extra arguments form an array, to which the scalar array optimization
|
||||
// should also apply.
|
||||
|
||||
@@ -32,7 +32,7 @@ NewObjectExpression::NewObjectExpression
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
ExpressionPtr variable, ExpressionListPtr params)
|
||||
: FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(NewObjectExpression),
|
||||
variable, "", params, variable),
|
||||
variable, "", false, params, variable),
|
||||
m_dynamic(false) {
|
||||
/*
|
||||
StaticClassName takes care of parent & self properly, so
|
||||
|
||||
@@ -39,7 +39,7 @@ ObjectMethodExpression::ObjectMethodExpression
|
||||
ExpressionPtr object, ExpressionPtr method, ExpressionListPtr params)
|
||||
: FunctionCall(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ObjectMethodExpression),
|
||||
method, "", params, ExpressionPtr()),
|
||||
method, "", false, params, ExpressionPtr()),
|
||||
m_object(object), m_bindClass(true) {
|
||||
m_object->setContext(Expression::ObjectContext);
|
||||
m_object->clearContext(Expression::LValue);
|
||||
|
||||
@@ -96,9 +96,10 @@ public:
|
||||
|
||||
SimpleFunctionCall::SimpleFunctionCall
|
||||
(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &name, ExpressionListPtr params, ExpressionPtr cls)
|
||||
const std::string &name, bool hadBackslash, ExpressionListPtr params,
|
||||
ExpressionPtr cls)
|
||||
: FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(SimpleFunctionCall),
|
||||
ExpressionPtr(), name, params, cls),
|
||||
ExpressionPtr(), name, hadBackslash, params, cls),
|
||||
m_type(UnknownType), m_dynamicConstant(false),
|
||||
m_builtinFunction(false), m_noPrefix(false), m_fromCompiler(false),
|
||||
m_dynamicInvoke(false), m_transformed(false), m_no_volatile_check(false),
|
||||
@@ -1369,7 +1370,7 @@ SimpleFunctionCallPtr SimpleFunctionCall::GetFunctionCallForCallUserFunc(
|
||||
}
|
||||
SimpleFunctionCallPtr rep(
|
||||
NewSimpleFunctionCall(call->getScope(), call->getLocation(),
|
||||
name, p2, ExpressionPtr()));
|
||||
name, false, p2, ExpressionPtr()));
|
||||
return rep;
|
||||
}
|
||||
v = t;
|
||||
@@ -1464,7 +1465,7 @@ SimpleFunctionCallPtr SimpleFunctionCall::GetFunctionCallForCallUserFunc(
|
||||
}
|
||||
SimpleFunctionCallPtr rep(
|
||||
NewSimpleFunctionCall(call->getScope(), call->getLocation(),
|
||||
smethod, p2, cl));
|
||||
smethod, false, p2, cl));
|
||||
return rep;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ public:
|
||||
|
||||
public:
|
||||
SimpleFunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &name, ExpressionListPtr params,
|
||||
ExpressionPtr cls);
|
||||
const std::string &name, bool hadBackslash,
|
||||
ExpressionListPtr params, ExpressionPtr cls);
|
||||
|
||||
DECLARE_BASE_EXPRESSION_VIRTUAL_FUNCTIONS;
|
||||
ExpressionPtr preOptimize(AnalysisResultConstPtr ar);
|
||||
@@ -128,7 +128,7 @@ private:
|
||||
|
||||
SimpleFunctionCallPtr NewSimpleFunctionCall(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &name, ExpressionListPtr params,
|
||||
const std::string &name, bool hadBackslash, ExpressionListPtr params,
|
||||
ExpressionPtr cls);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+754
-752
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -122,12 +122,12 @@ namespace HPHP {
|
||||
|
||||
SimpleFunctionCallPtr NewSimpleFunctionCall(
|
||||
EXPRESSION_CONSTRUCTOR_PARAMETERS,
|
||||
const std::string &name, ExpressionListPtr params,
|
||||
const std::string &name, bool hadBackslash, ExpressionListPtr params,
|
||||
ExpressionPtr cls) {
|
||||
return SimpleFunctionCallPtr(
|
||||
new RealSimpleFunctionCall(
|
||||
EXPRESSION_CONSTRUCTOR_DERIVED_PARAMETER_VALUES,
|
||||
name, params, cls));
|
||||
name, hadBackslash, params, cls));
|
||||
}
|
||||
|
||||
namespace Compiler {
|
||||
@@ -296,7 +296,7 @@ void Parser::onVariable(Token &out, Token *exprs, Token &var, Token *value,
|
||||
}
|
||||
ExpressionPtr exp;
|
||||
if (constant) {
|
||||
exp = NEW_EXP(ConstantExpression, var->text(), docComment);
|
||||
exp = NEW_EXP(ConstantExpression, var->text(), false, docComment);
|
||||
} else {
|
||||
exp = NEW_EXP(SimpleVariable, var->text(), docComment);
|
||||
}
|
||||
@@ -337,7 +337,7 @@ void Parser::onStaticMember(Token &out, Token &cls, Token &name) {
|
||||
|
||||
void Parser::onRefDim(Token &out, Token &var, Token &offset) {
|
||||
if (!var->exp) {
|
||||
var->exp = NEW_EXP(ConstantExpression, var->text());
|
||||
var->exp = NEW_EXP(ConstantExpression, var->text(), var->num() & 2);
|
||||
}
|
||||
if (!offset->exp) {
|
||||
UnaryOpExpressionPtr uop;
|
||||
@@ -407,7 +407,7 @@ void Parser::onCall(Token &out, bool dynamic, Token &name, Token ¶ms,
|
||||
|
||||
SimpleFunctionCallPtr call
|
||||
(new RealSimpleFunctionCall
|
||||
(BlockScopePtr(), getLocation(), name->text(),
|
||||
(BlockScopePtr(), getLocation(), name->text(), name->num() & 2,
|
||||
dynamic_pointer_cast<ExpressionList>(params->exp), clsExp));
|
||||
if (fromCompiler) {
|
||||
call->setFromCompiler();
|
||||
@@ -504,7 +504,8 @@ void Parser::encapArray(Token &out, Token &var, Token &expr) {
|
||||
// expressions
|
||||
|
||||
void Parser::onConstantValue(Token &out, Token &constant) {
|
||||
ConstantExpressionPtr con = NEW_EXP(ConstantExpression, constant->text());
|
||||
ConstantExpressionPtr con = NEW_EXP(ConstantExpression, constant->text(),
|
||||
constant->num() & 2);
|
||||
con->onParse(m_ar, m_file);
|
||||
out->exp = con;
|
||||
}
|
||||
@@ -1372,6 +1373,7 @@ void Parser::onReturn(Token &out, Token *expr) {
|
||||
|
||||
static void invalidYield(LocationPtr loc) {
|
||||
ExpressionPtr exp(new SimpleFunctionCall(BlockScopePtr(), loc, "yield",
|
||||
false,
|
||||
ExpressionListPtr(),
|
||||
ExpressionPtr()));
|
||||
Compiler::Error(Compiler::InvalidYield, exp);
|
||||
|
||||
@@ -904,6 +904,16 @@ Cns <litstr id> [] -> [C:Null|Bool|Int|Dbl|Str]
|
||||
as a cell. If there is no constant named %1, this instruction raises a notice
|
||||
and pushes the string %1 onto the stack as a cell.
|
||||
|
||||
CnsE <litstr id> [] -> [C:Null|Bool|Int|Dbl|Str]
|
||||
|
||||
Get constant. Pushes the value of the global constant named %1 onto the stack
|
||||
as a cell. If there is no constant named %1, throws a fatal error.
|
||||
|
||||
CnsU <litstr id> <litstr fallback> [] -> [C:Null|Bool|Int|Dbl|Str]
|
||||
|
||||
Get constant. Identical to Cns except returns constant named %2 if the
|
||||
constant named %1 is undefined.
|
||||
|
||||
ClsCns <litstr id> [A] -> [C:Null|Bool|Int|Dbl|Str]
|
||||
|
||||
Get class constant. This instruction pushes the value of the class constant
|
||||
@@ -1603,6 +1613,12 @@ FPushFuncD <num params> <litstr id> [] -> []
|
||||
|
||||
If x is not a string or object, this instruction throws a fatal error.
|
||||
|
||||
FPushFuncU <num params> <litstr id> <litstr fallback> [] -> []
|
||||
|
||||
FPI push function unqualified. Identical to FPushFuncD except first trys to
|
||||
lookup the function named %2 and if it isn't defined calls the function named
|
||||
%3.
|
||||
|
||||
FPushObjMethod <num params> [C C] -> []
|
||||
FPushObjMethodD <num params> <litstr id> [C] -> []
|
||||
|
||||
|
||||
@@ -501,6 +501,7 @@ OPCODES
|
||||
void classExistsImpl(PC& pc, Attr typeAttr);
|
||||
void fPushObjMethodImpl(
|
||||
VM::Class* cls, StringData* name, ObjectData* obj, int numArgs);
|
||||
ActRec* fPushFuncImpl(const VM::Func* func, int numArgs);
|
||||
|
||||
public:
|
||||
typedef hphp_hash_map<const StringData*, ClassInfo::ConstantInfo*,
|
||||
|
||||
@@ -3884,8 +3884,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCns(PC& pc) {
|
||||
DECODE_LITSTR(s);
|
||||
TypedValue* cns = Unit::loadCns(s);
|
||||
if (cns == nullptr) {
|
||||
raise_notice(Strings::UNDEFINED_CONSTANT,
|
||||
s->data(), s->data());
|
||||
raise_notice(Strings::UNDEFINED_CONSTANT, s->data(), s->data());
|
||||
m_stack.pushStaticString(s);
|
||||
return;
|
||||
}
|
||||
@@ -3893,6 +3892,38 @@ inline void OPTBLD_INLINE VMExecutionContext::iopCns(PC& pc) {
|
||||
tvReadCell(cns, c1);
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopCnsE(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_LITSTR(s);
|
||||
TypedValue* cns = Unit::loadCns(s);
|
||||
if (cns == nullptr) {
|
||||
raise_error("Undefined constant '%s'", s->data());
|
||||
}
|
||||
Cell* c1 = m_stack.allocC();
|
||||
tvReadCell(cns, c1);
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopCnsU(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_LITSTR(name);
|
||||
DECODE_LITSTR(fallback);
|
||||
TypedValue* cns = Unit::loadCns(name);
|
||||
if (cns == nullptr) {
|
||||
cns = Unit::loadCns(fallback);
|
||||
if (cns == nullptr) {
|
||||
raise_notice(
|
||||
Strings::UNDEFINED_CONSTANT,
|
||||
fallback->data(),
|
||||
fallback->data()
|
||||
);
|
||||
m_stack.pushStaticString(fallback);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Cell* c1 = m_stack.allocC();
|
||||
tvReadCell(cns, c1);
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopDefCns(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_LITSTR(s);
|
||||
@@ -5416,6 +5447,18 @@ inline void OPTBLD_INLINE VMExecutionContext::iopUnsetM(PC& pc) {
|
||||
setHelperPost<0>(SETHELPERPOST_ARGS);
|
||||
}
|
||||
|
||||
inline ActRec* OPTBLD_INLINE VMExecutionContext::fPushFuncImpl(
|
||||
const Func* func,
|
||||
int numArgs) {
|
||||
DEBUGGER_IF(phpBreakpointEnabled(func->name()->data()));
|
||||
ActRec* ar = m_stack.allocA();
|
||||
arSetSfp(ar, m_fp);
|
||||
ar->m_func = func;
|
||||
ar->initNumArgs(numArgs);
|
||||
ar->setVarEnv(nullptr);
|
||||
return ar;
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPushFunc(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IVA(numArgs);
|
||||
@@ -5438,7 +5481,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPushFunc(PC& pc) {
|
||||
raise_error(Strings::FUNCTION_NAME_MUST_BE_STRING);
|
||||
}
|
||||
if (func == nullptr) {
|
||||
raise_error("Undefined function: %s", c1->m_data.pstr->data());
|
||||
raise_error("Call to undefined function %s()", c1->m_data.pstr->data());
|
||||
}
|
||||
assert(!origObj || !origSd);
|
||||
assert(origObj || origSd);
|
||||
@@ -5446,9 +5489,7 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPushFunc(PC& pc) {
|
||||
// overwriting the pointer on the stack. Don't refcount it now; defer
|
||||
// till after we're done with it.
|
||||
m_stack.discard();
|
||||
ActRec* ar = m_stack.allocA();
|
||||
ar->m_func = func;
|
||||
arSetSfp(ar, m_fp);
|
||||
ActRec* ar = fPushFuncImpl(func, numArgs);
|
||||
if (origObj) {
|
||||
if (func->attrs() & AttrStatic && !func->isClosureBody()) {
|
||||
ar->setClass(origObj->getVMClass());
|
||||
@@ -5462,8 +5503,6 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPushFunc(PC& pc) {
|
||||
ar->setThis(nullptr);
|
||||
decRefStr(origSd);
|
||||
}
|
||||
ar->initNumArgs(numArgs);
|
||||
ar->setVarEnv(nullptr);
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPushFuncD(PC& pc) {
|
||||
@@ -5473,16 +5512,31 @@ inline void OPTBLD_INLINE VMExecutionContext::iopFPushFuncD(PC& pc) {
|
||||
const NamedEntityPair nep = m_fp->m_func->unit()->lookupNamedEntityPairId(id);
|
||||
Func* func = Unit::loadFunc(nep.second, nep.first);
|
||||
if (func == nullptr) {
|
||||
raise_error("Undefined function: %s",
|
||||
raise_error("Call to undefined function %s()",
|
||||
m_fp->m_func->unit()->lookupLitstrId(id)->data());
|
||||
}
|
||||
DEBUGGER_IF(phpBreakpointEnabled(func->name()->data()));
|
||||
ActRec* ar = m_stack.allocA();
|
||||
arSetSfp(ar, m_fp);
|
||||
ar->m_func = func;
|
||||
ActRec* ar = fPushFuncImpl(func, numArgs);
|
||||
ar->setThis(nullptr);
|
||||
}
|
||||
|
||||
inline void OPTBLD_INLINE VMExecutionContext::iopFPushFuncU(PC& pc) {
|
||||
NEXT();
|
||||
DECODE_IVA(numArgs);
|
||||
DECODE(Id, nsFunc);
|
||||
DECODE(Id, globalFunc);
|
||||
Unit* unit = m_fp->m_func->unit();
|
||||
const NamedEntityPair nep = unit->lookupNamedEntityPairId(nsFunc);
|
||||
Func* func = Unit::loadFunc(nep.second, nep.first);
|
||||
if (func == nullptr) {
|
||||
const NamedEntityPair nep2 = unit->lookupNamedEntityPairId(globalFunc);
|
||||
func = Unit::loadFunc(nep2.second, nep2.first);
|
||||
if (func == nullptr) {
|
||||
const char *funcName = unit->lookupLitstrId(nsFunc)->data();
|
||||
raise_error("Call to undefined function %s()", funcName);
|
||||
}
|
||||
}
|
||||
ActRec* ar = fPushFuncImpl(func, numArgs);
|
||||
ar->setThis(nullptr);
|
||||
ar->initNumArgs(numArgs);
|
||||
ar->setVarEnv(nullptr);
|
||||
}
|
||||
|
||||
void VMExecutionContext::fPushObjMethodImpl(
|
||||
|
||||
@@ -490,6 +490,7 @@ bool pushesActRec(Opcode opcode) {
|
||||
switch (opcode) {
|
||||
case OpFPushFunc:
|
||||
case OpFPushFuncD:
|
||||
case OpFPushFuncU:
|
||||
case OpFPushObjMethod:
|
||||
case OpFPushObjMethodD:
|
||||
case OpFPushClsMethod:
|
||||
|
||||
@@ -375,6 +375,8 @@ enum SetOpOp {
|
||||
O(ColAddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
|
||||
O(ColAddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
|
||||
O(Cns, ONE(SA), NOV, ONE(CV), NF) \
|
||||
O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
|
||||
O(CnsU, TWO(SA,SA), NOV, ONE(CV), NF) \
|
||||
O(ClsCns, ONE(SA), ONE(AV), ONE(CV), NF) \
|
||||
O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
|
||||
O(File, NA, NOV, ONE(CV), NF) \
|
||||
@@ -490,6 +492,7 @@ enum SetOpOp {
|
||||
/* NOTE: isFPush below relies on the grouping of FPush* here */ \
|
||||
O(FPushFunc, ONE(IVA), ONE(CV), NOV, NF) \
|
||||
O(FPushFuncD, TWO(IVA,SA), NOV, NOV, NF) \
|
||||
O(FPushFuncU, THREE(IVA,SA,SA), NOV, NOV, NF) \
|
||||
O(FPushObjMethod, ONE(IVA), TWO(CV,CV), NOV, NF) \
|
||||
O(FPushObjMethodD, TWO(IVA,SA), ONE(CV), NOV, NF) \
|
||||
O(FPushClsMethod, ONE(IVA), TWO(AV,CV), NOV, NF) \
|
||||
|
||||
@@ -520,6 +520,14 @@ void HhbcTranslator::emitCns(uint32_t id) {
|
||||
push(result);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCnsE(uint32_t id) {
|
||||
PUNT(CnsE);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitCnsU(uint32_t id) {
|
||||
PUNT(CnsU);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitDefCns(uint32_t id) {
|
||||
StringData* name = lookupStringId(id);
|
||||
SSATmp* val = popC();
|
||||
@@ -1630,6 +1638,12 @@ void HhbcTranslator::emitFPushFuncD(int32_t numParams, int32_t funcId) {
|
||||
nullptr);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitFPushFuncU(int32_t numParams,
|
||||
int32_t funcId,
|
||||
int32_t fallbackFuncId) {
|
||||
PUNT(FPushFuncU);
|
||||
}
|
||||
|
||||
void HhbcTranslator::emitFPushFunc(int32_t numParams) {
|
||||
// input must be a string or an object implementing __invoke();
|
||||
// otherwise fatal
|
||||
|
||||
@@ -153,6 +153,8 @@ struct HhbcTranslator {
|
||||
void emitColAddNewElemC();
|
||||
void emitDefCns(uint32_t id);
|
||||
void emitCns(uint32_t id);
|
||||
void emitCnsE(uint32_t id);
|
||||
void emitCnsU(uint32_t id);
|
||||
void emitConcat();
|
||||
void emitDefCls(int id, Offset after);
|
||||
void emitDefFunc(int id);
|
||||
@@ -225,6 +227,9 @@ struct HhbcTranslator {
|
||||
void emitFPushActRec(SSATmp* func, SSATmp* objOrClass, int32_t numArgs,
|
||||
const StringData* invName);
|
||||
void emitFPushFuncD(int32_t numParams, int32_t funcId);
|
||||
void emitFPushFuncU(int32_t numParams,
|
||||
int32_t funcId,
|
||||
int32_t fallbackFuncId);
|
||||
void emitFPushFunc(int32_t numParams);
|
||||
void emitFPushFunc(int32_t numParams, SSATmp* funcName);
|
||||
SSATmp* getClsMethodCtx(const Func* callee, const Class* cls);
|
||||
|
||||
@@ -1000,6 +1000,8 @@ static const struct {
|
||||
{ OpColAddElemC, {StackTop3, Stack1, OutObject, -2 }},
|
||||
{ OpColAddNewElemC, {StackTop2, Stack1, OutObject, -1 }},
|
||||
{ OpCns, {None, Stack1, OutCns, 1 }},
|
||||
{ OpCnsE, {None, Stack1, OutCns, 1 }},
|
||||
{ OpCnsU, {None, Stack1, OutCns, 1 }},
|
||||
{ OpClsCns, {Stack1, Stack1, OutUnknown, 0 }},
|
||||
{ OpClsCnsD, {None, Stack1, OutPred, 1 }},
|
||||
{ OpFile, {None, Stack1, OutString, 1 }},
|
||||
@@ -1152,6 +1154,8 @@ static const struct {
|
||||
kNumActRecCells - 1 }},
|
||||
{ OpFPushFuncD, {None, FStack, OutFDesc,
|
||||
kNumActRecCells }},
|
||||
{ OpFPushFuncU, {None, FStack, OutFDesc,
|
||||
kNumActRecCells }},
|
||||
{ OpFPushObjMethod,
|
||||
{StackTop2, FStack, OutFDesc,
|
||||
kNumActRecCells - 2 }},
|
||||
@@ -3396,6 +3400,10 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
|
||||
StringData *funcName =
|
||||
curUnit()->lookupLitstrId(getImm(fpushPc, 1).u_SA);
|
||||
doVarEnvTaint = checkTaintFuncs(funcName);
|
||||
} else if (*fpushPc == OpFPushFuncU) {
|
||||
StringData *fallbackName =
|
||||
curUnit()->lookupLitstrId(getImm(fpushPc, 2).u_SA);
|
||||
doVarEnvTaint = checkTaintFuncs(fallbackName);
|
||||
}
|
||||
}
|
||||
t.m_arState.pop();
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
NULL
|
||||
|
||||
Catchable fatal error: Argument 1 passed to foo\bar::__construct() must be of the type array, object given, called in hphp/test/zend/bad/zend/ns_071.php on line %d and defined in hphp/test/zend/bad/zend/ns_071.php on line %d
|
||||
Catchable fatal error: Argument 1 passed to foo\bar::__construct() must be of the type array, object given, called in hphp/test/zend/bad/zend/ns_071.phpt on line %d and defined in hphp/test/zend/bad/zend/ns_071.phpt on line %d
|
||||
@@ -2,4 +2,4 @@ object(foo\test)#%d (0) {
|
||||
}
|
||||
NULL
|
||||
|
||||
Catchable fatal error: Argument 1 passed to foo\bar::__construct() must implement interface foo\foo, instance of stdClass given, called in hphp/test/zend/bad/zend/ns_072.php on line %d and defined in hphp/test/zend/bad/zend/ns_072.php on line %d
|
||||
Catchable fatal error: Argument 1 passed to foo\bar::__construct() must implement interface foo\foo, instance of stdClass given, called in hphp/test/zend/bad/zend/ns_072.phpt on line %d and defined in hphp/test/zend/bad/zend/ns_072.phpt on line %d
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
var_dump((binary)__NAMESPACE__);
|
||||
@@ -271,6 +271,7 @@ other_files = (
|
||||
'/zend/ns_065.inc',
|
||||
'/zend/ns_066.inc',
|
||||
'/zend/ns_067.inc',
|
||||
'/zend/ns_069.inc',
|
||||
'/zend/unset.inc',
|
||||
)
|
||||
|
||||
|
||||
@@ -874,30 +874,32 @@ use_declaration:
|
||||
namespace_name:
|
||||
ident { $$ = $1;}
|
||||
| namespace_name T_NS_SEPARATOR
|
||||
ident { $$ = $1 + $2 + $3;}
|
||||
ident { $$ = $1 + $2 + $3; $$ = $1.num() | 2;}
|
||||
;
|
||||
namespace_string_base:
|
||||
namespace_name { $$ = $1; $$ = 1;}
|
||||
| T_NS_SEPARATOR namespace_name { $$ = $2; $$ = 0;}
|
||||
namespace_name { $$ = $1; $$ = $$.num() | 1;}
|
||||
| T_NAMESPACE T_NS_SEPARATOR
|
||||
namespace_name { $$.setText(_p->nsDecl($3.text()));
|
||||
$$ = 0;}
|
||||
namespace_name { $$.set($3.num() | 2, _p->nsDecl($3.text()));}
|
||||
| T_NS_SEPARATOR namespace_name { $$ = $2; $$ = $$.num() | 2;}
|
||||
;
|
||||
namespace_string:
|
||||
namespace_string_base { if ($1.num())
|
||||
namespace_string_base { if ($1.num() & 1) {
|
||||
$1.setText(_p->resolve($1.text(),0));
|
||||
}
|
||||
$$ = $1;}
|
||||
;
|
||||
namespace_string_typeargs:
|
||||
namespace_string_base
|
||||
sm_typeargs_opt { if ($1.num())
|
||||
sm_typeargs_opt { if ($1.num() & 1) {
|
||||
$1.setText(_p->resolve($1.text(),0));
|
||||
}
|
||||
$$ = $1;}
|
||||
;
|
||||
class_namespace_string_typeargs:
|
||||
namespace_string_base
|
||||
sm_typeargs_opt { if ($1.num())
|
||||
sm_typeargs_opt { if ($1.num() & 1) {
|
||||
$1.setText(_p->resolve($1.text(),1));
|
||||
}
|
||||
$$ = $1;}
|
||||
;
|
||||
constant_declaration:
|
||||
|
||||
@@ -355,6 +355,17 @@ std::string ParserBase::resolve(const std::string &ns, bool cls) {
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// Classes are special. They don't fallback to the global namespace.
|
||||
if (cls) {
|
||||
if (!strcasecmp("self", ns.c_str()) ||
|
||||
!strcasecmp("parent", ns.c_str())) {
|
||||
return ns;
|
||||
}
|
||||
// Don't prefix with \ because that isn't the real classname and we don't
|
||||
// need a flag to signal fallback.
|
||||
return nsDecl(ns);
|
||||
}
|
||||
|
||||
// if qualified name, prepend current namespace
|
||||
if (pos != string::npos) {
|
||||
return nsDecl(ns);
|
||||
@@ -365,23 +376,12 @@ std::string ParserBase::resolve(const std::string &ns, bool cls) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
// unqualified class name always prefixed with NAMESPACE_SEP
|
||||
if (cls) {
|
||||
if (strcasecmp("self", ns.c_str()) && strcasecmp("parent", ns.c_str())) {
|
||||
return m_namespace + NAMESPACE_SEP + ns;
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
if (!strcasecmp("true", ns.c_str()) ||
|
||||
!strcasecmp("false", ns.c_str()) ||
|
||||
!strcasecmp("null", ns.c_str())) {
|
||||
return ns;
|
||||
}
|
||||
|
||||
// unqualified function name needs leading NAMESPACE_SEP to indicate this
|
||||
// needs runtime resolution
|
||||
return NAMESPACE_SEP + m_namespace + NAMESPACE_SEP + ns;
|
||||
return nsDecl(ns);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário