PageRenderTime 38ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/construct.h

https://github.com/tstarling/hiphop-php
C Header | 346 lines | 227 code | 43 blank | 76 comment | 5 complexity | e9a33f988ef1c3bbc1e3d0ebb8ab577c MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_CONSTRUCT_H_
  17. #define incl_HPHP_CONSTRUCT_H_
  18. #include "hphp/compiler/json.h"
  19. #include <memory>
  20. #include "hphp/compiler/code_generator.h"
  21. #include "hphp/compiler/analysis/code_error.h"
  22. #include "hphp/compiler/analysis/block_scope.h"
  23. namespace HPHP {
  24. ///////////////////////////////////////////////////////////////////////////////
  25. class Variant;
  26. DECLARE_BOOST_TYPES(StatementList);
  27. DECLARE_BOOST_TYPES(IParseHandler);
  28. DECLARE_BOOST_TYPES(Location);
  29. DECLARE_BOOST_TYPES(AnalysisResult);
  30. DECLARE_BOOST_TYPES(BlockScope);
  31. DECLARE_BOOST_TYPES(ClassScope);
  32. DECLARE_BOOST_TYPES(FunctionScope);
  33. DECLARE_BOOST_TYPES(FileScope);
  34. class AstWalkerStateVec;
  35. class IParseHandler {
  36. /**
  37. * To avoid iteration of parse tree, we move any work that can be done
  38. * in parse phase into this function, so to speed up static analysis.
  39. */
  40. public:
  41. virtual ~IParseHandler() {}
  42. /**
  43. * onParse is called by the parser when the construct has just been parsed
  44. * to allow it to do any necessary work
  45. */
  46. virtual void onParse(AnalysisResultConstPtr ar, FileScopePtr scope) {
  47. always_assert(0);
  48. }
  49. /**
  50. * onParseRecur is called by a parent construct (ultimately a class or
  51. * interface).
  52. * This is done because at the time that onParse would be called for
  53. * (eg) a method, the ClassScope doesnt exist. So we wait until onParse
  54. * is called for the class, and it calls onParseRecur for its children.
  55. */
  56. virtual void onParseRecur(AnalysisResultConstPtr ar, ClassScopePtr scope) {
  57. always_assert(0);
  58. }
  59. };
  60. /**
  61. * Base class of Expression and Statement.
  62. */
  63. class Construct : public std::enable_shared_from_this<Construct>,
  64. public JSON::CodeError::ISerializable {
  65. protected:
  66. Construct(BlockScopePtr scope, LocationPtr loc);
  67. public:
  68. virtual ~Construct() {}
  69. enum Effect {
  70. NoEffect = 0,
  71. IOEffect = 1, // could have an observable effect (not
  72. // changing variable values)
  73. AssignEffect = 2, // writes an object in a way understood by the
  74. // alias manager
  75. GlobalEffect = 4, // could affect global variables
  76. LocalEffect = 8, // could affect variables from the local scope
  77. ParamEffect = 0x10, // a function could affect its parameters
  78. DeepParamEffect = 0x20, // a function could affect the array elements
  79. // or object members referenced by its
  80. // parameters
  81. DynamicParamEffect = 0x40, // a function creates dynamic exps based
  82. // on its parameters, which it could affect
  83. CanThrow = 0x80, // can throw PHP exception
  84. AccessorEffect = 0x100, // could contain a getter/setter
  85. CreateEffect = 0x200, // could cause the creation of an array
  86. // element or an object property
  87. DiagnosticEffect = 0x400, // can cause a diagnostic to be issued
  88. OtherEffect = 0x800, // something else
  89. UnknownEffect = 0xfff // any of the above
  90. };
  91. LocationPtr getLocation() const { return m_loc;}
  92. void setLocation(LocationPtr loc) { m_loc = loc;}
  93. void setFileLevel() { m_flags.topLevel = m_flags.fileLevel = true;}
  94. void setTopLevel() { m_flags.topLevel = true;}
  95. void setVisited() { m_flags.visited = true;}
  96. void clearVisited() { m_flags.visited = false;}
  97. bool isFileLevel() const { return m_flags.fileLevel;}
  98. bool isTopLevel() const { return m_flags.topLevel;}
  99. bool isVisited() const { return m_flags.visited; }
  100. void setAnticipated() { m_flags.anticipated = true; }
  101. void clearAnticipated() { m_flags.anticipated = false; }
  102. bool isAnticipated() const { return m_flags.anticipated; }
  103. void setAvailable() { m_flags.available = true; }
  104. void clearAvailable() { m_flags.available = false; }
  105. bool isAvailable() const { return m_flags.available; }
  106. void setNonNull() { m_flags.nonNull = true; }
  107. void clearNonNull() { m_flags.nonNull = false; }
  108. bool isNonNull() const { return m_flags.nonNull; }
  109. void setLocalExprAltered() { m_flags.localExprNotAltered = false; }
  110. void clearLocalExprAltered() { m_flags.localExprNotAltered = true; }
  111. bool isLocalExprAltered() const { return !m_flags.localExprNotAltered; }
  112. void setChainRoot() { m_flags.chainRoot = true; }
  113. void clearChainRoot() { m_flags.chainRoot = false; }
  114. bool isChainRoot() const { return m_flags.chainRoot; }
  115. void setReferencedValid() { m_flags.referenced_valid = true; }
  116. void clearReferencedValid() { m_flags.referenced_valid = false; }
  117. bool isReferencedValid() const { return m_flags.referenced_valid; }
  118. void setReferenced() { m_flags.referenced = true; }
  119. void clearReferenced() { m_flags.referenced = false; }
  120. bool isReferenced() const { return m_flags.referenced; }
  121. void setNeededValid() { m_flags.needed_valid = true; }
  122. void clearNeededValid() { m_flags.needed_valid = false; }
  123. bool isNeededValid() const { return m_flags.needed_valid; }
  124. void setNeeded() { m_flags.needed = true; }
  125. void clearNeeded() { m_flags.needed = false; }
  126. bool isNeeded() const { return m_flags.needed; }
  127. void setNoRemove() { m_flags.noRemove = true; }
  128. void clearNoRemove() { m_flags.noRemove = false; }
  129. bool isNoRemove() const { return m_flags.noRemove; }
  130. void setGuarded() { m_flags.guarded = true; }
  131. void clearGuarded() { m_flags.guarded = false; }
  132. bool isGuarded() const { return m_flags.guarded; }
  133. void setRefCounted() { m_flags.refCounted = 3; }
  134. void clearRefCounted() { m_flags.refCounted = 2; }
  135. bool maybeRefCounted() const {
  136. return !(m_flags.refCounted & 2) || (m_flags.refCounted & 1);
  137. }
  138. void setInited() { m_flags.inited = 3; }
  139. void clearInited() { m_flags.inited = 2; }
  140. bool maybeInited() const {
  141. return !(m_flags.inited & 2) || (m_flags.inited & 1);
  142. }
  143. void setKilled() { m_flags.killed = true; }
  144. void clearKilled() { m_flags.killed = false; }
  145. bool isKilled() const { return m_flags.killed; }
  146. BlockScopeRawPtr getScope() const { return m_blockScope; }
  147. void setBlockScope(BlockScopeRawPtr scope) { m_blockScope = scope; }
  148. FileScopeRawPtr getFileScope() const {
  149. return m_blockScope->getContainingFile();
  150. }
  151. FunctionScopeRawPtr getFunctionScope() const {
  152. return m_blockScope->getContainingFunction();
  153. }
  154. ClassScopeRawPtr getClassScope() const {
  155. return m_blockScope->getContainingClass();
  156. }
  157. void resetScope(BlockScopeRawPtr scope, bool resetOrigScope=false);
  158. void parseTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
  159. ATTRIBUTE_PRINTF(3,4);
  160. void analysisTimeFatal(Compiler::ErrorType error, const char *fmt, ...)
  161. ATTRIBUTE_PRINTF(3,4);
  162. virtual int getLocalEffects() const { return UnknownEffect;}
  163. int getChildrenEffects() const;
  164. int getContainedEffects() const;
  165. bool hasEffect() const { return getContainedEffects() != NoEffect;}
  166. virtual bool kidUnused(int i) const { return false; }
  167. template<typename T>
  168. static std::shared_ptr<T> Clone(std::shared_ptr<T> constr) {
  169. if (constr) {
  170. return dynamic_pointer_cast<T>(constr->clone());
  171. }
  172. return std::shared_ptr<T>();
  173. }
  174. template<typename T>
  175. std::shared_ptr<T> Clone(std::shared_ptr<T> constr,
  176. BlockScopePtr scope) {
  177. if (constr) {
  178. constr = constr->clone();
  179. constr->resetScope(scope);
  180. }
  181. return constr;
  182. }
  183. /**
  184. * Called when we analyze a program, which file it includes, which function
  185. * and class it uses, etc.
  186. */
  187. virtual void analyzeProgram(AnalysisResultPtr ar) = 0;
  188. /**
  189. * return the nth child construct
  190. */
  191. virtual ConstructPtr getNthKid(int n) const { return ConstructPtr(); }
  192. /**
  193. * set the nth child construct
  194. */
  195. virtual void setNthKid(int n, ConstructPtr cp) {}
  196. /**
  197. * get the kid count
  198. */
  199. virtual int getKidCount() const = 0;
  200. // helpers for GDB
  201. void dump(int spc, AnalysisResultPtr ar) {
  202. AnalysisResultConstPtr arp(ar);
  203. dump(spc, arp);
  204. }
  205. void dumpNode(int spc, AnalysisResultPtr ar) {
  206. AnalysisResultConstPtr arp(ar);
  207. dumpNode(spc, arp);
  208. }
  209. void dumpNode(int spc);
  210. void dumpNode(int spc) const;
  211. void dump(int spc, AnalysisResultConstPtr ar);
  212. void dumpNode(int spc, AnalysisResultConstPtr ar);
  213. static void dump(int spc, AnalysisResultConstPtr ar, bool functionOnly,
  214. const AstWalkerStateVec &start,
  215. ConstructPtr endBefore, ConstructPtr endAfter);
  216. /**
  217. * Generates a serialized Code Model corresponding to this AST.
  218. */
  219. virtual void outputCodeModel(CodeGenerator &cg) = 0;
  220. /**
  221. * Called when generating code.
  222. */
  223. virtual void outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) = 0;
  224. /**
  225. * Implements JSON::CodeError::ISerializable.
  226. */
  227. virtual void serialize(JSON::CodeError::OutputStream &out) const;
  228. /**
  229. * Get canonicalized PHP source code for this construct.
  230. */
  231. std::string getText(bool useCache, bool translate = false,
  232. AnalysisResultPtr ar = AnalysisResultPtr());
  233. std::string getText() { return getText(false); }
  234. void recomputeEffects();
  235. /**
  236. * Write where this construct was in PHP files.
  237. */
  238. void printSource(CodeGenerator &cg);
  239. ExpressionPtr makeConstant(AnalysisResultConstPtr ar,
  240. const std::string &value) const;
  241. ExpressionPtr makeScalarExpression(AnalysisResultConstPtr ar,
  242. const Variant &value) const;
  243. private:
  244. std::string m_text;
  245. BlockScopeRawPtr m_blockScope;
  246. union {
  247. unsigned m_flagsVal;
  248. struct {
  249. unsigned fileLevel : 1; // is it at top level of a file
  250. unsigned topLevel : 1; // is it at top level of a scope
  251. unsigned visited : 1; // general purpose for walks
  252. unsigned anticipated : 1;
  253. unsigned available : 1;
  254. unsigned localExprNotAltered : 1; // whether this node can be
  255. // altered in this expression
  256. unsigned nonNull : 1; // expression is not null
  257. unsigned referenced : 1;
  258. unsigned referenced_valid : 1; // is the above flag is valid
  259. unsigned needed : 1;
  260. unsigned needed_valid : 1; // is the above flag is valid
  261. unsigned chainRoot : 1; // is this the begining of a
  262. // CSE chain
  263. unsigned noRemove : 1; // DCE should NOT remove this node
  264. unsigned guarded : 1; // previously used
  265. unsigned killed : 1;
  266. unsigned refCounted : 2; // high bit indicates whether its valid
  267. unsigned inited : 2; // high bit indicates whether its valid
  268. } m_flags;
  269. };
  270. protected:
  271. LocationPtr m_loc;
  272. mutable int m_containedEffects;
  273. mutable int m_effectsTag;
  274. /**
  275. * Called by analyzeProgram() to add a reference to a user class or
  276. * function.
  277. */
  278. void addUserFunction(AnalysisResultPtr ar, const std::string &name);
  279. void addUserClass(AnalysisResultPtr ar, const std::string &name);
  280. };
  281. class LocalEffectsContainer {
  282. public:
  283. int getLocalEffects() const { return m_localEffects; }
  284. virtual void effectsCallback() = 0;
  285. protected:
  286. explicit LocalEffectsContainer(Construct::Effect localEffect) :
  287. m_localEffects(localEffect) {}
  288. LocalEffectsContainer() :
  289. m_localEffects(0) {}
  290. void setLocalEffect (Construct::Effect effect);
  291. void clearLocalEffect(Construct::Effect effect);
  292. bool hasLocalEffect (Construct::Effect effect) const;
  293. protected:
  294. int m_localEffects;
  295. };
  296. #define DECL_AND_IMPL_LOCAL_EFFECTS_METHODS \
  297. virtual int getLocalEffects() const { \
  298. return LocalEffectsContainer::getLocalEffects(); \
  299. } \
  300. virtual void effectsCallback() { recomputeEffects(); }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. }
  303. #endif // incl_HPHP_CONSTRUCT_H_