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:
Paul Tarjan
2013-04-27 15:27:34 -07:00
commit de Sara Golemon
commit 96e793360b
99 arquivos alterados com 993 adições e 828 exclusões
+40 -11
Ver Arquivo
@@ -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);
}
}
+2 -1
Ver Arquivo
@@ -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();
+1 -1
Ver Arquivo
@@ -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;
+3 -3
Ver Arquivo
@@ -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 &&
+11 -2
Ver Arquivo
@@ -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;
}
}
+3 -3
Ver Arquivo
@@ -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);
///////////////////////////////////////////////////////////////////////////////
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+8 -6
Ver Arquivo
@@ -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 &params,
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);
+16
Ver Arquivo
@@ -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] -> []
+1
Ver Arquivo
@@ -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*,
+69 -15
Ver Arquivo
@@ -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(
+1
Ver Arquivo
@@ -490,6 +490,7 @@ bool pushesActRec(Opcode opcode) {
switch (opcode) {
case OpFPushFunc:
case OpFPushFuncD:
case OpFPushFuncU:
case OpFPushObjMethod:
case OpFPushObjMethodD:
case OpFPushClsMethod:
+3
Ver Arquivo
@@ -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);
+8
Ver Arquivo
@@ -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 -1
Ver Arquivo
@@ -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
+1 -1
Ver Arquivo
@@ -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
+3
Ver Arquivo
@@ -0,0 +1,3 @@
<?php
var_dump((binary)__NAMESPACE__);
+1
Ver Arquivo
@@ -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',
)
+10 -8
Ver Arquivo
@@ -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:
+12 -12
Ver Arquivo
@@ -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);
}
///////////////////////////////////////////////////////////////////////////////