89765cd4f2
This diff changes HHVM so that arrays are considered to implement the Traversable and KeyedTraversable interfaces (which have no methods). The idea is that these interfaces will be useful for parameter type constraints for PHP code that wants to be compatible with both arrays and collections (and possibly other objects that implement these interfaces).
498 linhas
16 KiB
C++
498 linhas
16 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef incl_HPHP_FUNCTION_SCOPE_H_
|
|
#define incl_HPHP_FUNCTION_SCOPE_H_
|
|
|
|
#include "hphp/compiler/expression/user_attribute.h"
|
|
#include "hphp/compiler/analysis/block_scope.h"
|
|
#include "hphp/compiler/option.h"
|
|
|
|
#include "hphp/util/json.h"
|
|
#include "hphp/util/parser/parser.h"
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
DECLARE_BOOST_TYPES(Type);
|
|
DECLARE_BOOST_TYPES(Construct);
|
|
DECLARE_BOOST_TYPES(ExpressionList);
|
|
DECLARE_BOOST_TYPES(FileScope);
|
|
DECLARE_BOOST_TYPES(AnalysisResult);
|
|
DECLARE_BOOST_TYPES(FunctionScope);
|
|
DECLARE_BOOST_TYPES(Expression);
|
|
DECLARE_BOOST_TYPES(SimpleFunctionCall);
|
|
DECLARE_BOOST_TYPES(ClassScope);
|
|
DECLARE_BOOST_TYPES(ParameterExpression);
|
|
DECLARE_BOOST_TYPES(MethodStatement);
|
|
|
|
class CodeGenerator;
|
|
|
|
typedef ExpressionPtr (*FunctionOptPtr)(CodeGenerator *cg,
|
|
AnalysisResultConstPtr ar,
|
|
SimpleFunctionCallPtr, int);
|
|
|
|
typedef std::pair< ParameterExpressionPtr, int >
|
|
ParameterExpressionPtrIdxPair;
|
|
|
|
typedef std::vector< ParameterExpressionPtrIdxPair >
|
|
ParameterExpressionPtrIdxPairVec;
|
|
|
|
/**
|
|
* A FunctionScope corresponds to a function declaration. We store all
|
|
* inferred types and analyzed results here, so not to pollute syntax trees.
|
|
*/
|
|
class FunctionScope : public BlockScope,
|
|
public JSON::CodeError::ISerializable,
|
|
public JSON::DocTarget::ISerializable {
|
|
public:
|
|
/**
|
|
* User defined functions.
|
|
*/
|
|
FunctionScope(AnalysisResultConstPtr ar, bool method,
|
|
const std::string &name, StatementPtr stmt,
|
|
bool reference, int minParam, int maxParam,
|
|
ModifierExpressionPtr modifiers, int attribute,
|
|
const std::string &docComment,
|
|
FileScopePtr file,
|
|
const std::vector<UserAttributePtr> &attrs,
|
|
bool inPseudoMain = false);
|
|
|
|
FunctionScope(FunctionScopePtr orig, AnalysisResultConstPtr ar,
|
|
const std::string &name, const std::string &originalName,
|
|
StatementPtr stmt, ModifierExpressionPtr modifiers);
|
|
|
|
/**
|
|
* System functions.
|
|
*/
|
|
FunctionScope(bool method, const std::string &name, bool reference);
|
|
void setParamCounts(AnalysisResultConstPtr ar, int minParam, int maxParam);
|
|
void setParamSpecs(AnalysisResultPtr ar);
|
|
void setParamName(int index, const std::string &name);
|
|
void setParamDefault(int index, const char* value, int64_t len,
|
|
const std::string &text);
|
|
CStrRef getParamDefault(int index);
|
|
void setRefParam(int index);
|
|
bool hasRefParam(int max) const;
|
|
|
|
void addModifier(int mod);
|
|
|
|
/**
|
|
* What kind of function this is.
|
|
*/
|
|
bool isUserFunction() const { return !m_system;}
|
|
bool isDynamic() const { return m_dynamic; }
|
|
bool isPublic() const;
|
|
bool isProtected() const;
|
|
bool isPrivate() const;
|
|
bool isStatic() const;
|
|
bool isAbstract() const;
|
|
bool isFinal() const;
|
|
bool isMagic() const;
|
|
bool isRefParam(int index) const;
|
|
bool isRefReturn() const { return m_refReturn;}
|
|
bool isDynamicInvoke() const { return m_dynamicInvoke; }
|
|
void setDynamicInvoke();
|
|
bool hasImpl() const;
|
|
void setDirectInvoke() { m_directInvoke = true; }
|
|
bool hasDirectInvoke() const { return m_directInvoke; }
|
|
bool mayContainThis();
|
|
bool isClosure() const;
|
|
bool isGenerator() const;
|
|
bool isGeneratorFromClosure() const;
|
|
int allocYieldLabel() { return ++m_yieldLabelCount; }
|
|
int getYieldLabelCount() const { return m_yieldLabelCount; }
|
|
bool hasGeneratorAsBody() const;
|
|
MethodStatementRawPtr getOrigGenStmt() const;
|
|
FunctionScopeRawPtr getOrigGenFS() const;
|
|
void setClosureGenerator() { m_closureGenerator = true; }
|
|
bool isClosureGenerator() const {
|
|
assert(!m_closureGenerator || isClosure());
|
|
return m_closureGenerator;
|
|
}
|
|
bool needsClassParam();
|
|
|
|
void setInlineSameContext(bool f) { m_inlineSameContext = f; }
|
|
bool getInlineSameContext() const { return m_inlineSameContext; }
|
|
void setContextSensitive(bool f) { m_contextSensitive = f; }
|
|
bool getContextSensitive() const { return m_contextSensitive; }
|
|
void setInlineAsExpr(bool f) { m_inlineAsExpr = f; }
|
|
bool getInlineAsExpr() const { return m_inlineAsExpr; }
|
|
int nextInlineIndex() { return ++m_inlineIndex; }
|
|
|
|
bool usesLSB() const { return !m_noLSB; }
|
|
void clearUsesLSB() { m_noLSB = true; }
|
|
bool nextLSB() const { return m_nextLSB; }
|
|
void setNextLSB(bool f) { m_nextLSB = f; }
|
|
|
|
void setHasGoto() { m_hasGoto = true; }
|
|
void setHasTry() { m_hasTry = true; }
|
|
bool hasGoto() const { return m_hasGoto; }
|
|
bool hasTry() const { return m_hasTry; }
|
|
unsigned getNewID() { return m_nextID++; }
|
|
|
|
bool needsLocalThis() const;
|
|
|
|
/**
|
|
* Either __construct or a class-name constructor.
|
|
*/
|
|
bool isConstructor(ClassScopePtr cls) const;
|
|
|
|
const std::string &getParamName(int index) const;
|
|
|
|
const std::string &name() const {
|
|
return getName();
|
|
}
|
|
|
|
virtual std::string getId() const;
|
|
std::string getInjectionId() const;
|
|
|
|
int getRedeclaringId() const {
|
|
return m_redeclaring;
|
|
}
|
|
|
|
void setDynamic() {
|
|
m_dynamic = true;
|
|
}
|
|
|
|
void setSystem() {
|
|
m_system = true;
|
|
m_volatile = false;
|
|
}
|
|
|
|
/**
|
|
* Tell this function about another outer scope that contains it.
|
|
*/
|
|
void addClonedTraitOuterScope(FunctionScopePtr scope) {
|
|
m_clonedTraitOuterScope.push_back(scope);
|
|
}
|
|
|
|
/**
|
|
* Get/set original name of the function, without case being lowered.
|
|
*/
|
|
const std::string &getOriginalName() const;
|
|
void setOriginalName(const std::string &name) { m_originalName = name; }
|
|
|
|
std::string getDocName() const;
|
|
std::string getDocFullName() const;
|
|
|
|
/**
|
|
* If class method, returns class::name, otherwise just name.
|
|
*/
|
|
std::string getFullName() const;
|
|
std::string getOriginalFullName() const;
|
|
|
|
/**
|
|
* Whether this function can take variable number of arguments.
|
|
*/
|
|
bool isVariableArgument() const;
|
|
bool isReferenceVariableArgument() const;
|
|
void setVariableArgument(int reference);
|
|
bool isMixedVariableArgument() const;
|
|
|
|
/**
|
|
* Whether this function has no side effects
|
|
*/
|
|
bool hasEffect() const;
|
|
void setNoEffect();
|
|
|
|
/**
|
|
* Whether this function can be constant folded
|
|
*/
|
|
bool isFoldable() const;
|
|
void setIsFoldable();
|
|
|
|
/*
|
|
* If this is a builtin function and does not need an ActRec
|
|
*/
|
|
bool needsActRec() const;
|
|
void setNeedsActRec();
|
|
|
|
/*
|
|
* If this is a builtin (C++ or PHP) and can be redefined
|
|
*/
|
|
bool allowOverride() const;
|
|
void setAllowOverride();
|
|
|
|
/**
|
|
* Whether this function is a runtime helper function
|
|
*/
|
|
void setHelperFunction();
|
|
|
|
/**
|
|
* Whether this function returns reference or has reference parameters.
|
|
*/
|
|
bool containsReference() const;
|
|
|
|
/**
|
|
* Whether this function contains a usage of $this
|
|
*/
|
|
bool containsThis() const { return m_containsThis;}
|
|
void setContainsThis(bool f = true);
|
|
bool containsBareThis() const { return m_containsBareThis; }
|
|
bool containsRefThis() const { return m_containsBareThis & 2; }
|
|
void setContainsBareThis(bool f, bool ref = false);
|
|
/**
|
|
* How many parameters a caller should provide.
|
|
*/
|
|
int getMinParamCount() const { return m_minParam;}
|
|
int getMaxParamCount() const { return m_maxParam;}
|
|
int getOptionalParamCount() const { return m_maxParam - m_minParam;}
|
|
|
|
/**
|
|
* What is the inferred type of this function's return.
|
|
*/
|
|
void pushReturnType();
|
|
void setReturnType(AnalysisResultConstPtr ar, TypePtr type);
|
|
TypePtr getReturnType() const {
|
|
return m_prevReturn ? m_prevReturn : m_returnType;
|
|
}
|
|
bool popReturnType();
|
|
void resetReturnType();
|
|
|
|
void addRetExprToFix(ExpressionPtr e);
|
|
void clearRetExprs();
|
|
void fixRetExprs();
|
|
|
|
void setOptFunction(FunctionOptPtr fn) { m_optFunction = fn; }
|
|
FunctionOptPtr getOptFunction() const { return m_optFunction; }
|
|
|
|
/**
|
|
* Whether this is a virtual function that needs to go through invoke().
|
|
* A perfect virtual will be generated as C++ virtual function without
|
|
* going through invoke(), but rather directly generated as obj->foo().
|
|
* "Overriding" is only being used by magic methods, enforcing parameter
|
|
* and return types.
|
|
*/
|
|
void setVirtual() { m_virtual = true;}
|
|
bool isVirtual() const { return m_virtual;}
|
|
void setHasOverride() { m_hasOverride = true; }
|
|
bool hasOverride() const { return m_hasOverride; }
|
|
void setPerfectVirtual();
|
|
bool isPerfectVirtual() const { return m_perfectVirtual;}
|
|
void setOverriding(TypePtr returnType, TypePtr param1 = TypePtr(),
|
|
TypePtr param2 = TypePtr());
|
|
bool isOverriding() const { return m_overriding;}
|
|
|
|
/**
|
|
* Whether same function name was declared twice or more.
|
|
*/
|
|
void setRedeclaring(int redecId) {
|
|
m_redeclaring = redecId;
|
|
setVolatile(); // redeclared function is also volatile
|
|
}
|
|
bool isRedeclaring() const { return m_redeclaring >= 0;}
|
|
|
|
void setLocalRedeclaring() { m_localRedeclaring = true; }
|
|
bool isLocalRedeclaring() const { return m_localRedeclaring; }
|
|
|
|
/* For function_exists */
|
|
void setVolatile() { m_volatile = true; }
|
|
bool isVolatile() const { return m_volatile; }
|
|
bool isPersistent() const { return m_persistent; }
|
|
void setPersistent(bool p) { m_persistent = p; }
|
|
|
|
bool isInlined() const { return m_inlineable; }
|
|
void disableInline() { m_inlineable = false; }
|
|
|
|
/* Whether this function is brought in by a separable extension */
|
|
void setSepExtension() { m_sep = true;}
|
|
bool isSepExtension() const { return m_sep;}
|
|
|
|
/* Whether we need to worry about the named return value optimization
|
|
for this function */
|
|
void setNRVOFix(bool flag) { m_nrvoFix = flag; }
|
|
bool getNRVOFix() const { return m_nrvoFix; }
|
|
|
|
/* Indicates if a function may need to use a VarEnv or varargs (aka
|
|
* extraArgs) at run time */
|
|
bool mayUseVV() const;
|
|
|
|
/**
|
|
* Whether this function matches the specified one with same number of
|
|
* parameters and types and defaults, so to qualify for perfect virtuals.
|
|
*/
|
|
bool matchParams(FunctionScopePtr func);
|
|
|
|
/**
|
|
* What is the inferred type of this function's parameter at specified
|
|
* index. Returns number of extra arguments to put into ArgumentArray.
|
|
*/
|
|
int inferParamTypes(AnalysisResultPtr ar, ConstructPtr exp,
|
|
ExpressionListPtr params, bool &valid);
|
|
|
|
TypePtr setParamType(AnalysisResultConstPtr ar, int index, TypePtr type);
|
|
TypePtr getParamType(int index);
|
|
TypePtr getParamTypeSpec(int index) { return m_paramTypeSpecs[index]; }
|
|
|
|
typedef hphp_hash_map<std::string, ExpressionPtr, string_hashi,
|
|
string_eqstri> UserAttributeMap;
|
|
|
|
UserAttributeMap& userAttributes() { return m_userAttributes;}
|
|
|
|
/**
|
|
* Override BlockScope::outputPHP() to generate return type.
|
|
*/
|
|
virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar);
|
|
/**
|
|
* Serialize the iface, not everything.
|
|
*/
|
|
void serialize(JSON::CodeError::OutputStream &out) const;
|
|
void serialize(JSON::DocTarget::OutputStream &out) const;
|
|
|
|
bool inPseudoMain() const {
|
|
return m_pseudoMain;
|
|
}
|
|
|
|
void setMagicMethod() {
|
|
m_magicMethod = true;
|
|
}
|
|
bool isMagicMethod() const {
|
|
return m_magicMethod;
|
|
}
|
|
|
|
void setStmtCloned(StatementPtr stmt) {
|
|
m_stmtCloned = stmt;
|
|
}
|
|
|
|
void setClosureVars(ExpressionListPtr closureVars) {
|
|
m_closureVars = closureVars;
|
|
}
|
|
|
|
ExpressionListPtr getClosureVars() const {
|
|
return m_closureVars;
|
|
}
|
|
|
|
void getClosureUseVars(ParameterExpressionPtrIdxPairVec &useVars,
|
|
bool filterUsed = true);
|
|
|
|
bool needsAnonClosureClass(ParameterExpressionPtrVec &useVars);
|
|
|
|
bool needsAnonClosureClass(ParameterExpressionPtrIdxPairVec &useVars);
|
|
|
|
void addCaller(BlockScopePtr caller, bool careAboutReturn = true);
|
|
void addNewObjCaller(BlockScopePtr caller);
|
|
|
|
ReadWriteMutex &getInlineMutex() { return m_inlineMutex; }
|
|
|
|
DECLARE_BOOST_TYPES(FunctionInfo);
|
|
|
|
static void RecordFunctionInfo(std::string fname, FunctionScopePtr func);
|
|
|
|
static FunctionInfoPtr GetFunctionInfo(std::string fname);
|
|
|
|
class FunctionInfo {
|
|
public:
|
|
explicit FunctionInfo(int rva = -1)
|
|
: m_maybeStatic(false)
|
|
, m_maybeRefReturn(false)
|
|
, m_refVarArg(rva)
|
|
{}
|
|
|
|
bool isRefParam(int p) const {
|
|
if (m_refVarArg >= 0 && p >= m_refVarArg) return true;
|
|
return (m_refParams.find(p) != m_refParams.end());
|
|
}
|
|
|
|
void setRefVarArg(int rva) {
|
|
if (rva > m_refVarArg) m_refVarArg = rva;
|
|
}
|
|
|
|
void setRefParam(int p) {
|
|
m_refParams.insert(p);
|
|
}
|
|
|
|
void setMaybeStatic() { m_maybeStatic = true; }
|
|
bool getMaybeStatic() { return m_maybeStatic; }
|
|
|
|
void setMaybeRefReturn() { m_maybeRefReturn = true; }
|
|
bool getMaybeRefReturn() { return m_maybeRefReturn; }
|
|
|
|
private:
|
|
bool m_maybeStatic; // this could be a static method
|
|
bool m_maybeRefReturn;
|
|
int m_refVarArg; // -1: no ref varargs;
|
|
// otherwise, any arg >= m_refVarArg is a reference
|
|
std::set<int> m_refParams; // set of ref arg positions
|
|
};
|
|
|
|
private:
|
|
void init(AnalysisResultConstPtr ar);
|
|
|
|
static StringToFunctionInfoPtrMap s_refParamInfo;
|
|
|
|
int m_minParam;
|
|
int m_maxParam;
|
|
int m_attribute;
|
|
std::vector<std::string> m_paramNames;
|
|
TypePtrVec m_paramTypes;
|
|
TypePtrVec m_paramTypeSpecs;
|
|
std::vector<String> m_paramDefaults;
|
|
std::vector<std::string> m_paramDefaultTexts;
|
|
std::vector<bool> m_refs;
|
|
TypePtr m_returnType;
|
|
TypePtr m_prevReturn;
|
|
ModifierExpressionPtr m_modifiers;
|
|
UserAttributeMap m_userAttributes;
|
|
|
|
unsigned m_hasVoid : 1;
|
|
unsigned m_method : 1;
|
|
unsigned m_refReturn : 1; // whether it's "function &get_reference()"
|
|
unsigned m_virtual : 1;
|
|
unsigned m_hasOverride : 1;
|
|
unsigned m_perfectVirtual : 1;
|
|
unsigned m_dynamic : 1;
|
|
unsigned m_dynamicInvoke : 1;
|
|
unsigned m_overriding : 1; // overriding a virtual function
|
|
unsigned m_volatile : 1; // for function_exists
|
|
unsigned m_persistent : 1;
|
|
unsigned m_pseudoMain : 1;
|
|
unsigned m_magicMethod : 1;
|
|
unsigned m_system : 1;
|
|
unsigned m_inlineable : 1;
|
|
unsigned m_sep : 1;
|
|
unsigned m_containsThis : 1; // contains a usage of $this?
|
|
unsigned m_containsBareThis : 2; // $this outside object-context,
|
|
// 2 if in reference context
|
|
unsigned m_nrvoFix : 1;
|
|
unsigned m_inlineAsExpr : 1;
|
|
unsigned m_inlineSameContext : 1;
|
|
unsigned m_contextSensitive : 1;
|
|
unsigned m_directInvoke : 1;
|
|
unsigned m_closureGenerator : 1;
|
|
unsigned m_noLSB : 1;
|
|
unsigned m_nextLSB : 1;
|
|
unsigned m_hasTry : 1;
|
|
unsigned m_hasGoto : 1;
|
|
unsigned m_localRedeclaring : 1;
|
|
|
|
int m_redeclaring; // multiple definition of the same function
|
|
StatementPtr m_stmtCloned; // cloned method body stmt
|
|
int m_inlineIndex;
|
|
FunctionOptPtr m_optFunction;
|
|
ExpressionPtrVec m_retExprsToFix;
|
|
ExpressionListPtr m_closureVars;
|
|
ExpressionListPtr m_closureValues;
|
|
ReadWriteMutex m_inlineMutex;
|
|
unsigned m_nextID; // used when cloning generators for traits
|
|
int m_yieldLabelCount; // number of allocated yield labels
|
|
std::list<FunctionScopeRawPtr> m_clonedTraitOuterScope;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|
|
#endif // incl_HPHP_FUNCTION_SCOPE_H_
|