PageRenderTime 26ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/compiler/expression/constant_expression.cpp

https://github.com/github-ivan/hiphop-php
C++ | 334 lines | 271 code | 35 blank | 28 comment | 119 complexity | 0d0a6fd90635a33f687d5e5b2d62aa5d 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/analysis/file_scope.h>
  17. #include <compiler/expression/constant_expression.h>
  18. #include <compiler/analysis/block_scope.h>
  19. #include <compiler/analysis/class_scope.h>
  20. #include <compiler/analysis/function_scope.h>
  21. #include <compiler/analysis/constant_table.h>
  22. #include <compiler/analysis/variable_table.h>
  23. #include <compiler/analysis/code_error.h>
  24. #include <util/hash.h>
  25. #include <util/util.h>
  26. #include <compiler/option.h>
  27. #include <compiler/parser/parser.h>
  28. #include <util/parser/hphp.tab.hpp>
  29. #include <compiler/expression/scalar_expression.h>
  30. #include <runtime/ext/ext_misc.h>
  31. using namespace HPHP;
  32. using namespace std;
  33. using namespace boost;
  34. ///////////////////////////////////////////////////////////////////////////////
  35. // constructors/destructors
  36. ConstantExpression::ConstantExpression
  37. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  38. const string &name, const string &docComment)
  39. : Expression(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(ConstantExpression)),
  40. m_name(name), m_docComment(docComment),
  41. m_valid(false), m_dynamic(false), m_visited(false), m_depsSet(false) {
  42. }
  43. ExpressionPtr ConstantExpression::clone() {
  44. ConstantExpressionPtr exp(new ConstantExpression(*this));
  45. Expression::deepCopy(exp);
  46. m_depsSet = false;
  47. return exp;
  48. }
  49. bool ConstantExpression::isScalar() const {
  50. if (m_name == "INF" || m_name == "NAN") return true;
  51. string lower = Util::toLower(m_name);
  52. return lower == "true" || lower == "false" || lower == "null";
  53. }
  54. bool ConstantExpression::isLiteralNull() const {
  55. return isNull();
  56. }
  57. bool ConstantExpression::isBoolean() const {
  58. string lower = Util::toLower(m_name);
  59. return (lower == "true" || lower == "false");
  60. }
  61. bool ConstantExpression::isNull() const {
  62. string lower = Util::toLower(m_name);
  63. return (lower == "null");
  64. }
  65. bool ConstantExpression::getBooleanValue() const {
  66. string lower = Util::toLower(m_name);
  67. ASSERT(lower == "true" || lower == "false");
  68. return lower == "true";
  69. }
  70. bool ConstantExpression::getScalarValue(Variant &value) {
  71. if (!isScalar()) return false;
  72. if (isBoolean()) {
  73. value = getBooleanValue();
  74. } else if (m_name == "INF") {
  75. value = k_INF;
  76. } else if (m_name == "NAN") {
  77. value = k_NAN;
  78. } else {
  79. value.unset();
  80. }
  81. return true;
  82. }
  83. unsigned ConstantExpression::getCanonHash() const {
  84. int64 val = hash_string(Util::toLower(m_name).c_str(), m_name.size());
  85. return ~unsigned(val) ^ unsigned(val >> 32);
  86. }
  87. bool ConstantExpression::canonCompare(ExpressionPtr e) const {
  88. return Expression::canonCompare(e) &&
  89. m_name == static_cast<ConstantExpression*>(e.get())->m_name;
  90. }
  91. ///////////////////////////////////////////////////////////////////////////////
  92. // parser functions
  93. ///////////////////////////////////////////////////////////////////////////////
  94. // static analysis functions
  95. Symbol *ConstantExpression::resolveNS(AnalysisResultConstPtr ar) {
  96. bool ns = m_name[0] == '\\';
  97. if (ns) m_name = m_name.substr(1);
  98. BlockScopeConstPtr block = ar->findConstantDeclarer(m_name);
  99. if (!block) {
  100. if (ns) {
  101. int pos = m_name.rfind('\\');
  102. m_name = m_name.substr(pos + 1);
  103. block = ar->findConstantDeclarer(m_name);
  104. }
  105. if (!block) return 0;
  106. }
  107. Symbol *sym = const_cast<Symbol*>(block->getConstants()->getSymbol(m_name));
  108. assert(sym);
  109. return sym;
  110. }
  111. void ConstantExpression::analyzeProgram(AnalysisResultPtr ar) {
  112. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  113. Symbol *sym = resolveNS(ar);
  114. if (!(m_context & LValue) && !m_dynamic) {
  115. if (sym && !sym->isSystem()) {
  116. if (sym->isDynamic()) {
  117. m_dynamic = true;
  118. } else {
  119. ConstructPtr decl = sym->getDeclaration();
  120. if (decl) {
  121. decl->getScope()->addUse(
  122. getScope(), BlockScope::UseKindConstRef);
  123. m_depsSet = true;
  124. }
  125. }
  126. }
  127. }
  128. } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal && m_dynamic) {
  129. getFileScope()->addConstantDependency(ar, m_name);
  130. FunctionScopePtr scope = getFunctionScope();
  131. if (scope) scope->setNeedsCheckMem();
  132. }
  133. }
  134. ExpressionPtr ConstantExpression::preOptimize(AnalysisResultConstPtr ar) {
  135. if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
  136. return ExpressionPtr();
  137. }
  138. ConstructPtr decl;
  139. while (!isScalar() && !m_dynamic && !(m_context & LValue)) {
  140. const Symbol *sym = resolveNS(ar);
  141. if (sym &&
  142. (!const_cast<Symbol*>(sym)->checkDefined() || sym->isDynamic())) {
  143. sym = 0;
  144. m_dynamic = true;
  145. }
  146. if (!sym) break;
  147. if (!sym->isSystem()) BlockScope::s_constMutex.lock();
  148. ExpressionPtr value = dynamic_pointer_cast<Expression>(sym->getValue());
  149. if (!sym->isSystem()) BlockScope::s_constMutex.unlock();
  150. if (!value || !value->isScalar()) {
  151. if (!m_depsSet && sym->getDeclaration()) {
  152. sym->getDeclaration()->getScope()->addUse(
  153. getScope(), BlockScope::UseKindConstRef);
  154. m_depsSet = true;
  155. }
  156. break;
  157. }
  158. Variant scalarValue;
  159. if (value->getScalarValue(scalarValue) &&
  160. !scalarValue.isAllowedAsConstantValue()) {
  161. // block further optimization
  162. const_cast<Symbol*>(sym)->setDynamic();
  163. m_dynamic = true;
  164. break;
  165. }
  166. if (sym->isSystem() && !value->is(KindOfScalarExpression)) {
  167. if (ExpressionPtr opt = value->preOptimize(ar)) {
  168. value = opt;
  169. }
  170. }
  171. ExpressionPtr rep = Clone(value, getScope());
  172. bool annotate = Option::FlAnnotate;
  173. Option::FlAnnotate = false; // avoid nested comments on getText
  174. rep->setComment(getText());
  175. Option::FlAnnotate = annotate;
  176. rep->setLocation(getLocation());
  177. return replaceValue(rep);
  178. }
  179. return ExpressionPtr();
  180. }
  181. TypePtr ConstantExpression::inferTypes(AnalysisResultPtr ar, TypePtr type,
  182. bool coerce) {
  183. if (m_context & LValue) return type; // ClassConstantExpression statement
  184. // special cases: STDIN, STDOUT, STDERR
  185. if (m_name == "STDIN" || m_name == "STDOUT" || m_name == "STDERR") {
  186. m_valid = true;
  187. return Type::Variant;
  188. }
  189. if (m_name == "INF" || m_name == "NAN") {
  190. m_valid = true;
  191. return Type::Double;
  192. }
  193. string lower = Util::toLower(m_name);
  194. TypePtr actualType;
  195. ConstructPtr self = shared_from_this();
  196. if (lower == "true" || lower == "false") {
  197. m_valid = true;
  198. actualType = Type::Boolean;
  199. } else if (lower == "null") {
  200. actualType = Type::Variant;
  201. m_valid = true;
  202. } else {
  203. BlockScopePtr scope;
  204. {
  205. Lock lock(ar->getMutex());
  206. scope = ar->findConstantDeclarer(m_name);
  207. if (!scope) {
  208. scope = getFileScope();
  209. // guarded by ar lock
  210. getFileScope()->declareConstant(ar, m_name);
  211. }
  212. }
  213. ASSERT(scope);
  214. ASSERT(scope->is(BlockScope::ProgramScope) ||
  215. scope->is(BlockScope::FileScope));
  216. ConstantTablePtr constants = scope->getConstants();
  217. ConstructPtr value;
  218. bool isDynamic;
  219. {
  220. Lock lock(scope->getMutex()); // since not class/function scope
  221. // read value and dynamic-ness together + check() atomically
  222. value = constants->getValue(m_name);
  223. isDynamic = constants->isDynamic(m_name);
  224. BlockScope *defScope = NULL;
  225. std::vector<std::string> bases;
  226. actualType = constants->check(getScope(), m_name, type, coerce,
  227. ar, self, bases, defScope);
  228. }
  229. if (!m_valid) {
  230. if (ar->isSystemConstant(m_name) || value) {
  231. m_valid = true;
  232. }
  233. }
  234. if (!m_dynamic && isDynamic) {
  235. m_dynamic = true;
  236. actualType = Type::Variant;
  237. }
  238. if (m_dynamic) {
  239. getScope()->getVariables()->
  240. setAttribute(VariableTable::NeedGlobalPointer);
  241. }
  242. }
  243. return actualType;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. // code generation functions
  247. void ConstantExpression::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  248. cg_printf("%s", m_name.c_str());
  249. }
  250. void ConstantExpression::outputCPPImpl(CodeGenerator &cg,
  251. AnalysisResultPtr ar) {
  252. // special cases: STDIN, STDOUT, STDERR, INF, and NAN
  253. if (m_name == "STDIN" || m_name == "STDOUT" || m_name == "STDERR") {
  254. cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
  255. return;
  256. }
  257. if (m_name == "INF" || m_name == "NAN") {
  258. if (cg.hasScalarVariant() && Option::UseScalarVariant) {
  259. cg_printf("%s_varNR", m_name.c_str());
  260. } else {
  261. cg_printf("%s%s", Option::ConstantPrefix, m_name.c_str());
  262. }
  263. return;
  264. }
  265. string lower = Util::toLower(m_name);
  266. bool requireFwDeclaration = false;
  267. if (lower == "true" || lower == "false" || lower == "null") {
  268. if (cg.hasScalarVariant()) {
  269. cg_printf((Option::UseScalarVariant ? "%s_varNR" : "%s"), lower.c_str());
  270. } else {
  271. cg_printf("%s", lower.c_str());
  272. }
  273. } else if (m_valid) {
  274. if (m_dynamic) {
  275. cg_printf("getDynamicConstant(%s->%s%s, ",
  276. cg.getGlobals(ar), Option::ConstantPrefix,
  277. CodeGenerator::FormatLabel(m_name).c_str());
  278. cg_printString(m_name, ar, shared_from_this());
  279. cg_printf(")");
  280. } else {
  281. cg_printf("%s%s", Option::ConstantPrefix,
  282. CodeGenerator::FormatLabel(m_name).c_str());
  283. requireFwDeclaration = true;
  284. }
  285. } else {
  286. cg_printf("getUndefinedConstant(");
  287. cg_printString(CodeGenerator::FormatLabel(m_name).c_str(), ar,
  288. shared_from_this());
  289. cg_printf(")");
  290. requireFwDeclaration = true;
  291. }
  292. if (requireFwDeclaration && cg.isFileOrClassHeader()) {
  293. if (getClassScope()) {
  294. getClassScope()->addUsedConstHeader(m_name);
  295. } else {
  296. getFileScope()->addUsedConstHeader(m_name);
  297. }
  298. }
  299. }