PageRenderTime 59ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/src/compiler/expression/class_constant_expression.cpp

https://github.com/leonhong/hiphop-php
C++ | 299 lines | 247 code | 27 blank | 25 comment | 56 complexity | 73fd81cbf663be0e971b3011d775fbae MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010 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. #include <compiler/expression/class_constant_expression.h>
  17. #include <compiler/analysis/class_scope.h>
  18. #include <compiler/analysis/constant_table.h>
  19. #include <compiler/analysis/code_error.h>
  20. #include <compiler/analysis/dependency_graph.h>
  21. #include <util/hash.h>
  22. #include <util/util.h>
  23. #include <compiler/option.h>
  24. #include <compiler/analysis/variable_table.h>
  25. #include <compiler/expression/scalar_expression.h>
  26. #include <compiler/expression/constant_expression.h>
  27. using namespace HPHP;
  28. using namespace std;
  29. using namespace boost;
  30. ///////////////////////////////////////////////////////////////////////////////
  31. // constructors/destructors
  32. ClassConstantExpression::ClassConstantExpression
  33. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  34. ExpressionPtr classExp, const std::string &varName)
  35. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES),
  36. StaticClassName(classExp), m_varName(varName), m_valid(false),
  37. m_redeclared(false), m_visited(false) {
  38. }
  39. ExpressionPtr ClassConstantExpression::clone() {
  40. ClassConstantExpressionPtr exp(new ClassConstantExpression(*this));
  41. Expression::deepCopy(exp);
  42. exp->m_class = Clone(m_class);
  43. return exp;
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // parser functions
  47. ///////////////////////////////////////////////////////////////////////////////
  48. // static analysis functions
  49. bool ClassConstantExpression::containsDynamicConstant(AnalysisResultPtr ar)
  50. const {
  51. if (m_class) return true;
  52. ClassScopePtr cls = ar->findClass(m_className);
  53. return !cls || cls->isVolatile() ||
  54. !cls->getConstants()->isRecursivelyDeclared(ar, m_varName);
  55. }
  56. void ClassConstantExpression::analyzeProgram(AnalysisResultPtr ar) {
  57. if (m_class) {
  58. m_class->analyzeProgram(ar);
  59. } else {
  60. addUserClass(ar, m_className);
  61. }
  62. }
  63. ConstructPtr ClassConstantExpression::getNthKid(int n) const {
  64. switch (n) {
  65. case 0:
  66. return m_class;
  67. default:
  68. ASSERT(false);
  69. break;
  70. }
  71. return ConstructPtr();
  72. }
  73. int ClassConstantExpression::getKidCount() const {
  74. return 1;
  75. }
  76. void ClassConstantExpression::setNthKid(int n, ConstructPtr cp) {
  77. switch (n) {
  78. case 0:
  79. m_class = boost::dynamic_pointer_cast<Expression>(cp);
  80. break;
  81. default:
  82. ASSERT(false);
  83. break;
  84. }
  85. }
  86. ExpressionPtr ClassConstantExpression::preOptimize(AnalysisResultPtr ar) {
  87. if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
  88. return ExpressionPtr();
  89. }
  90. if (m_class) {
  91. ar->preOptimize(m_class);
  92. updateClassName();
  93. return ExpressionPtr();
  94. }
  95. string currentClsName;
  96. ClassScopePtr currentCls = ar->getClassScope();
  97. if (currentCls) currentClsName = currentCls->getName();
  98. bool inCurrentClass = currentClsName == m_className;
  99. ClassScopePtr cls =
  100. inCurrentClass ? currentCls : ar->resolveClass(m_className);
  101. if (!cls) return ExpressionPtr();
  102. if (!inCurrentClass) {
  103. if (m_redeclared) return ExpressionPtr();
  104. if (cls->isVolatile() || cls->isRedeclaring()) return ExpressionPtr();
  105. }
  106. ConstantTablePtr constants = cls->getConstants();
  107. if (constants->isRecursivelyDeclared(ar, m_varName)) {
  108. ConstructPtr decl = constants->getValue(m_varName);
  109. if (decl) {
  110. ExpressionPtr value = dynamic_pointer_cast<Expression>(decl);
  111. if (!m_visited) {
  112. m_visited = true;
  113. ar->pushScope(cls);
  114. ExpressionPtr optExp = value->preOptimize(ar);
  115. ar->popScope();
  116. m_visited = false;
  117. if (optExp) value = optExp;
  118. }
  119. if (value->isScalar()) {
  120. // inline the value
  121. if (value->is(Expression::KindOfScalarExpression)) {
  122. ScalarExpressionPtr exp =
  123. dynamic_pointer_cast<ScalarExpression>(Clone(value));
  124. bool annotate = Option::FlAnnotate;
  125. Option::FlAnnotate = false; // avoid nested comments on getText()
  126. exp->setComment(getText());
  127. Option::FlAnnotate = annotate;
  128. exp->setLocation(getLocation());
  129. return exp;
  130. } else if (value->is(Expression::KindOfConstantExpression)) {
  131. // inline the value
  132. ConstantExpressionPtr exp =
  133. dynamic_pointer_cast<ConstantExpression>(Clone(value));
  134. bool annotate = Option::FlAnnotate;
  135. Option::FlAnnotate = false; // avoid nested comments
  136. exp->setComment(getText());
  137. Option::FlAnnotate = annotate;
  138. exp->setLocation(getLocation());
  139. return exp;
  140. }
  141. }
  142. }
  143. }
  144. return ExpressionPtr();
  145. }
  146. ExpressionPtr ClassConstantExpression::postOptimize(AnalysisResultPtr ar) {
  147. if (m_class) ar->postOptimize(m_class);
  148. return ExpressionPtr();
  149. }
  150. TypePtr ClassConstantExpression::inferTypes(AnalysisResultPtr ar,
  151. TypePtr type, bool coerce) {
  152. m_valid = false;
  153. ConstructPtr self = shared_from_this();
  154. if (m_class) {
  155. m_class->inferAndCheck(ar, NEW_TYPE(Any), false);
  156. return Type::Variant;
  157. }
  158. ClassScopePtr cls = ar->resolveClass(m_className);
  159. if (!cls || cls->isRedeclaring()) {
  160. if (cls) {
  161. m_redeclared = true;
  162. ar->getScope()->getVariables()->
  163. setAttribute(VariableTable::NeedGlobalPointer);
  164. }
  165. if (!cls && ar->isFirstPass()) {
  166. ar->getCodeError()->record(self, CodeError::UnknownClass, self);
  167. }
  168. return Type::Variant;
  169. }
  170. if (cls->getConstants()->isDynamic(m_varName) || cls->isVolatile()) {
  171. ar->getScope()->getVariables()->
  172. setAttribute(VariableTable::NeedGlobalPointer);
  173. }
  174. if (cls->getConstants()->isRecursivelyDeclared(ar, m_varName)) {
  175. string name = m_className + "::" + m_varName;
  176. ConstructPtr decl = cls->getConstants()->getDeclaration(m_varName);
  177. if (decl) { // No decl means an extension class.
  178. ar->getDependencyGraph()->add(DependencyGraph::KindOfConstant,
  179. ar->getName(),
  180. name, shared_from_this(), name, decl);
  181. }
  182. m_valid = true;
  183. }
  184. BlockScope *defScope;
  185. TypePtr t = cls->checkConst(m_varName, type, coerce, ar,
  186. shared_from_this(),
  187. cls->getBases(), defScope);
  188. if (defScope) {
  189. m_valid = true;
  190. m_defScope = defScope;
  191. }
  192. return t;
  193. }
  194. unsigned ClassConstantExpression::getCanonHash() const {
  195. int64 val =
  196. hash_string(Util::toLower(m_varName).c_str(), m_varName.size()) -
  197. hash_string(Util::toLower(m_className).c_str(), m_className.size());
  198. return ~unsigned(val) ^ unsigned(val >> 32);
  199. }
  200. bool ClassConstantExpression::canonCompare(ExpressionPtr e) const {
  201. return Expression::canonCompare(e) &&
  202. m_varName == static_cast<ClassConstantExpression*>(e.get())->m_varName &&
  203. m_className == static_cast<ClassConstantExpression*>(e.get())->m_className;
  204. }
  205. ///////////////////////////////////////////////////////////////////////////////
  206. // code generation functions
  207. void ClassConstantExpression::outputPHP(CodeGenerator &cg,
  208. AnalysisResultPtr ar) {
  209. StaticClassName::outputPHP(cg, ar);
  210. cg_printf("::%s", m_varName.c_str());
  211. }
  212. void ClassConstantExpression::outputCPPImpl(CodeGenerator &cg,
  213. AnalysisResultPtr ar) {
  214. if (m_class) {
  215. cg_printf("get_class_constant(");
  216. if (m_class->is(KindOfScalarExpression)) {
  217. ASSERT(strcasecmp(dynamic_pointer_cast<ScalarExpression>(m_class)->
  218. getString().c_str(), "static") == 0);
  219. cg_printf("FrameInjection::GetStaticClassName(info).data()");
  220. } else {
  221. cg_printf("get_static_class_name(");
  222. m_class->outputCPP(cg, ar);
  223. cg_printf(").data()");
  224. }
  225. cg_printf(", \"%s\")", m_varName.c_str());
  226. return;
  227. }
  228. bool outsideClass = !ar->checkClassPresent(m_origClassName);
  229. if (m_valid) {
  230. string trueClassName;
  231. ASSERT(m_defScope);
  232. ClassScope *cls = dynamic_cast<ClassScope*>(m_defScope);
  233. trueClassName = cls->getName();
  234. ASSERT(!trueClassName.empty());
  235. if (outsideClass) {
  236. cls->outputVolatileCheckBegin(cg, ar, m_origClassName);
  237. }
  238. ConstructPtr decl = m_defScope->getConstants()->getValue(m_varName);
  239. if (decl) {
  240. decl->outputCPP(cg, ar);
  241. if (cg.getContext() == CodeGenerator::CppImplementation ||
  242. cg.getContext() == CodeGenerator::CppParameterDefaultValueImpl) {
  243. cg_printf("(%s::%s)", m_className.c_str(), m_varName.c_str());
  244. } else {
  245. cg_printf("/* %s::%s */", m_className.c_str(), m_varName.c_str());
  246. }
  247. } else {
  248. if (cls->getConstants()->isDynamic(m_varName)) {
  249. cg_printf("%s%s::lazy_initializer(%s)->", Option::ClassPrefix,
  250. trueClassName.c_str(), cg.getGlobals(ar));
  251. }
  252. cg_printf("%s%s_%s", Option::ClassConstantPrefix, trueClassName.c_str(),
  253. m_varName.c_str());
  254. }
  255. if (outsideClass) {
  256. cls->outputVolatileCheckEnd(cg);
  257. }
  258. } else if (m_redeclared) {
  259. if (outsideClass) {
  260. ClassScope::OutputVolatileCheckBegin(cg, ar, m_origClassName);
  261. }
  262. cg_printf("%s->%s%s->os_constant(\"%s\")", cg.getGlobals(ar),
  263. Option::ClassStaticsObjectPrefix,
  264. m_className.c_str(), m_varName.c_str());
  265. if (outsideClass) {
  266. ClassScope::OutputVolatileCheckEnd(cg);
  267. }
  268. } else {
  269. cg_printf("throw_fatal(\"unknown class constant %s::%s\")",
  270. m_className.c_str(), m_varName.c_str());
  271. }
  272. }