PageRenderTime 22ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/statement/statement_list.cpp

https://gitlab.com/Blueprint-Marketing/hhvm
C++ | 436 lines | 364 code | 37 blank | 35 comment | 95 complexity | 60308e27cddee4513758170cf4963c66 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. #include "hphp/compiler/statement/statement_list.h"
  17. #include "hphp/compiler/analysis/analysis_result.h"
  18. #include "hphp/compiler/analysis/function_scope.h"
  19. #include "hphp/compiler/analysis/file_scope.h"
  20. #include "hphp/compiler/analysis/class_scope.h"
  21. #include "hphp/compiler/analysis/code_error.h"
  22. #include "hphp/compiler/statement/exp_statement.h"
  23. #include "hphp/compiler/statement/method_statement.h"
  24. #include "hphp/compiler/statement/class_statement.h"
  25. #include "hphp/compiler/statement/function_statement.h"
  26. #include "hphp/compiler/statement/return_statement.h"
  27. #include "hphp/compiler/statement/block_statement.h"
  28. #include "hphp/parser/hphp.tab.hpp"
  29. #include "hphp/compiler/expression/binary_op_expression.h"
  30. #include "hphp/compiler/expression/assignment_expression.h"
  31. #include "hphp/compiler/expression/simple_variable.h"
  32. #include "hphp/compiler/expression/constant_expression.h"
  33. #include "hphp/compiler/expression/unary_op_expression.h"
  34. #include "hphp/compiler/expression/include_expression.h"
  35. #include "hphp/compiler/expression/simple_function_call.h"
  36. using namespace HPHP;
  37. ///////////////////////////////////////////////////////////////////////////////
  38. // constructors/destructors
  39. StatementList::StatementList
  40. (STATEMENT_CONSTRUCTOR_PARAMETERS)
  41. : Statement(STATEMENT_CONSTRUCTOR_PARAMETER_VALUES(StatementList)),
  42. m_included(false) {
  43. }
  44. StatementPtr StatementList::clone() {
  45. StatementListPtr stmt(new StatementList(*this));
  46. stmt->m_stmts.clear();
  47. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  48. stmt->m_stmts.push_back(Clone(m_stmts[i]));
  49. }
  50. return stmt;
  51. }
  52. StatementListPtr StatementList::shallowClone() {
  53. StatementListPtr stmt(new StatementList(*this));
  54. stmt->m_stmts.clear();
  55. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  56. stmt->m_stmts.push_back(m_stmts[i]);
  57. }
  58. return stmt;
  59. }
  60. ///////////////////////////////////////////////////////////////////////////////
  61. // parser functions
  62. void StatementList::addElement(StatementPtr stmt) {
  63. m_stmts.push_back(stmt);
  64. }
  65. void StatementList::insertElement(StatementPtr stmt, int index /* = 0 */) {
  66. assert(index >= 0 && index <= (int)m_stmts.size());
  67. m_stmts.insert(m_stmts.begin() + index, stmt);
  68. }
  69. void StatementList::removeElement(int index) {
  70. m_stmts.erase(m_stmts.begin() + index, m_stmts.begin() + index + 1);
  71. }
  72. void StatementList::shift(int from, int to) {
  73. assert(from >= 0 && from <= (int)m_stmts.size());
  74. assert(to >= 0 && to <= (int)m_stmts.size());
  75. StatementPtr stmt = m_stmts[from];
  76. for (int i = from; i < to; i++) {
  77. m_stmts[i] = m_stmts[i+1];
  78. }
  79. m_stmts[to] = stmt;
  80. }
  81. ///////////////////////////////////////////////////////////////////////////////
  82. // static analysis functions
  83. StatementPtr StatementList::operator[](int index) {
  84. assert(index >= 0 && index < getCount());
  85. return m_stmts[index];
  86. }
  87. bool StatementList::hasDecl() const {
  88. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  89. if (m_stmts[i]->hasDecl()) return true;
  90. }
  91. return false;
  92. }
  93. bool StatementList::hasImpl() const {
  94. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  95. if (m_stmts[i]->hasImpl()) return true;
  96. }
  97. return false;
  98. }
  99. ExpressionPtr StatementList::getEffectiveImpl(AnalysisResultConstPtr ar) const {
  100. ExpressionListPtr rep;
  101. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  102. StatementPtr s = m_stmts[i];
  103. if (s->is(KindOfReturnStatement)) {
  104. ExpressionPtr e = static_pointer_cast<ReturnStatement>(s)->getRetExp();
  105. if (!e) {
  106. e = CONSTANT("null");
  107. } else if (!e->isScalar()) {
  108. break;
  109. }
  110. if (!rep) return e;
  111. rep->addElement(e);
  112. return rep;
  113. }
  114. if (s->hasImpl()) {
  115. break;
  116. }
  117. }
  118. return ExpressionPtr();
  119. }
  120. bool StatementList::hasBody() const {
  121. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  122. if (m_stmts[i]->hasBody()) return true;
  123. }
  124. return false;
  125. }
  126. bool StatementList::hasRetExp() const {
  127. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  128. if (m_stmts[i]->hasRetExp()) return true;
  129. }
  130. return false;
  131. }
  132. void StatementList::analyzeProgram(AnalysisResultPtr ar) {
  133. m_included = true;
  134. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  135. StatementPtr stmt = m_stmts[i];
  136. // effect testing
  137. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  138. if (!stmt->hasEffect() && !stmt->hasDecl() &&
  139. !stmt->is(Statement::KindOfStatementList)) {
  140. Compiler::Error(Compiler::StatementHasNoEffect, stmt);
  141. }
  142. }
  143. stmt->analyzeProgram(ar);
  144. }
  145. }
  146. bool StatementList::mergeConcatAssign() {
  147. if (Option::LocalCopyProp) {
  148. return false;
  149. } else {
  150. // check for vector string concat assignment such as
  151. // $space = " ";
  152. // $a .= "hello";
  153. // $a .= $space;
  154. // $a .= "world!";
  155. // turn into (for constant folding and concat sequence)
  156. // $a .= " " . "hello " . $space . "world!";
  157. unsigned int i = 0;
  158. bool merged = false;
  159. do {
  160. std::string lhsName;
  161. int length = 0;
  162. for (; i < m_stmts.size(); i++) {
  163. StatementPtr stmt = m_stmts[i];
  164. if (!stmt->is(Statement::KindOfExpStatement)) break;
  165. ExpStatementPtr expStmt = dynamic_pointer_cast<ExpStatement>(stmt);
  166. ExpressionPtr exp = expStmt->getExpression();
  167. // check the first assignment
  168. if (exp->is(Expression::KindOfAssignmentExpression)) {
  169. AssignmentExpressionPtr assignment_exp =
  170. dynamic_pointer_cast<AssignmentExpression>(exp);
  171. ExpressionPtr variable = assignment_exp->getVariable();
  172. ExpressionPtr value = assignment_exp->getValue();
  173. std::string variableName = variable->getText();
  174. if (variableName.find("->") != std::string::npos) break;
  175. if (value->hasEffect()) break;
  176. // cannot turn $a .= $b; a .= $a into $a .= $b . $a;
  177. if (value->getText().find(variableName) != std::string::npos) break;
  178. if (lhsName.empty()) {
  179. lhsName = variable->getText();
  180. length++;
  181. continue;
  182. } else {
  183. break;
  184. }
  185. } else if (!exp->is(Expression::KindOfBinaryOpExpression)) {
  186. break;
  187. }
  188. BinaryOpExpressionPtr binaryOpExp =
  189. dynamic_pointer_cast<BinaryOpExpression>(exp);
  190. if (binaryOpExp->getOp() != T_CONCAT_EQUAL) break;
  191. ExpressionPtr exp1 = binaryOpExp->getExp1();
  192. std::string exp1Text = exp1->getText();
  193. if (exp1Text.find("->") != std::string::npos) break;
  194. ExpressionPtr exp2 = binaryOpExp->getExp2();
  195. if (exp2->hasEffect()) break;
  196. if (exp2->getText().find(exp1Text) != std::string::npos) break;
  197. if (lhsName.empty()) {
  198. lhsName = exp1Text;
  199. length++;
  200. } else if (lhsName == exp1Text) {
  201. length++;
  202. } else {
  203. break;
  204. }
  205. }
  206. if (length > 1) {
  207. // replace m_stmts[j] to m_stmts[i - 1] with a new statement
  208. unsigned j = i - length;
  209. ExpStatementPtr expStmt;
  210. ExpressionPtr exp;
  211. BinaryOpExpressionPtr binaryOpExp;
  212. ExpressionPtr var;
  213. ExpressionPtr exp1;
  214. ExpressionPtr exp2;
  215. bool isAssignment = false;
  216. expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j++]);
  217. exp = expStmt->getExpression();
  218. if (exp->is(Expression::KindOfAssignmentExpression)) {
  219. isAssignment = true;
  220. AssignmentExpressionPtr assignment_exp =
  221. dynamic_pointer_cast<AssignmentExpression>(exp);
  222. var = assignment_exp->getVariable();
  223. exp1 = assignment_exp->getValue();
  224. } else {
  225. binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
  226. var = binaryOpExp->getExp1();
  227. exp1 = binaryOpExp->getExp2();
  228. }
  229. for (; j < i; j++) {
  230. expStmt = dynamic_pointer_cast<ExpStatement>(m_stmts[j]);
  231. exp = expStmt->getExpression();
  232. binaryOpExp = dynamic_pointer_cast<BinaryOpExpression>(exp);
  233. exp2 = binaryOpExp->getExp2();
  234. exp1 = BinaryOpExpressionPtr
  235. (new BinaryOpExpression(getScope(), getLocation(),
  236. exp1, exp2, '.'));
  237. }
  238. if (isAssignment) {
  239. exp = AssignmentExpressionPtr
  240. (new AssignmentExpression(exp->getScope(), exp->getLocation(),
  241. var, exp1,
  242. false));
  243. } else {
  244. exp = BinaryOpExpressionPtr
  245. (new BinaryOpExpression(getScope(), getLocation(),
  246. var, exp1, T_CONCAT_EQUAL));
  247. }
  248. expStmt = ExpStatementPtr
  249. (new ExpStatement(getScope(), getLabelScope(),
  250. getLocation(), exp));
  251. m_stmts[i - length] = expStmt;
  252. for (j = i - (length - 1); i > j; i--) removeElement(j);
  253. merged = true;
  254. } else if (length == 0) {
  255. i++;
  256. }
  257. } while (i < m_stmts.size());
  258. return merged;
  259. }
  260. }
  261. ConstructPtr StatementList::getNthKid(int n) const {
  262. if (n < (int)m_stmts.size()) {
  263. return m_stmts[n];
  264. }
  265. return ConstructPtr();
  266. }
  267. int StatementList::getKidCount() const {
  268. return m_stmts.size();
  269. }
  270. void StatementList::setNthKid(int n, ConstructPtr cp) {
  271. int s = m_stmts.size();
  272. if (n >= s) {
  273. assert(false);
  274. } else {
  275. m_stmts[n] = dynamic_pointer_cast<Statement>(cp);
  276. }
  277. }
  278. StatementPtr StatementList::preOptimize(AnalysisResultConstPtr ar) {
  279. bool del = false;
  280. bool changed = false;
  281. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  282. StatementPtr &s = m_stmts[i];
  283. if (del) {
  284. if (s->hasReachableLabel()) {
  285. del = false;
  286. } else {
  287. switch (s->getKindOf()) {
  288. case Statement::KindOfBlockStatement:
  289. case Statement::KindOfIfBranchStatement:
  290. case Statement::KindOfIfStatement:
  291. case Statement::KindOfWhileStatement:
  292. case Statement::KindOfDoStatement:
  293. case Statement::KindOfForStatement:
  294. case Statement::KindOfSwitchStatement:
  295. case Statement::KindOfCaseStatement:
  296. case Statement::KindOfBreakStatement:
  297. case Statement::KindOfContinueStatement:
  298. case Statement::KindOfReturnStatement:
  299. case Statement::KindOfGlobalStatement:
  300. case Statement::KindOfStaticStatement:
  301. case Statement::KindOfEchoStatement:
  302. case Statement::KindOfUnsetStatement:
  303. case Statement::KindOfExpStatement:
  304. case Statement::KindOfForEachStatement:
  305. case Statement::KindOfCatchStatement:
  306. case Statement::KindOfTryStatement:
  307. case Statement::KindOfThrowStatement:
  308. removeElement(i--);
  309. changed = true;
  310. continue;
  311. default:
  312. break;
  313. }
  314. }
  315. }
  316. if (s) {
  317. if (s->is(KindOfStatementList) && !s->hasDecl()) {
  318. StatementListPtr stmts(static_pointer_cast<StatementList>(s));
  319. removeElement(i);
  320. m_stmts.insert(m_stmts.begin() + i,
  321. stmts->m_stmts.begin(), stmts->m_stmts.end());
  322. i--;
  323. changed = true;
  324. continue;
  325. } else if (s->is(KindOfBlockStatement)) {
  326. BlockStatementPtr bs(static_pointer_cast<BlockStatement>(s));
  327. StatementListPtr stmts(bs->getStmts());
  328. if (!stmts) {
  329. removeElement(i--);
  330. changed = true;
  331. continue;
  332. } else {
  333. FunctionScopePtr fs(getFunctionScope());
  334. if (fs && (!fs->inPseudoMain() || !stmts->hasDecl())) {
  335. removeElement(i);
  336. m_stmts.insert(m_stmts.begin() + i,
  337. stmts->m_stmts.begin(), stmts->m_stmts.end());
  338. i--;
  339. changed = true;
  340. continue;
  341. }
  342. }
  343. } else if (Option::EliminateDeadCode) {
  344. if (s->is(KindOfBreakStatement) ||
  345. s->is(KindOfContinueStatement) ||
  346. s->is(KindOfReturnStatement) ||
  347. s->is(KindOfThrowStatement)) {
  348. del = true;
  349. } else if (s->is(KindOfExpStatement)) {
  350. ExpressionPtr e =
  351. dynamic_pointer_cast<ExpStatement>(s)->getExpression();
  352. if (!e->hasEffect() && !e->isNoRemove()) {
  353. removeElement(i--);
  354. changed = true;
  355. }
  356. }
  357. }
  358. }
  359. }
  360. if (mergeConcatAssign()) changed = true;
  361. return changed ? static_pointer_cast<Statement>(shared_from_this())
  362. : StatementPtr();
  363. }
  364. ///////////////////////////////////////////////////////////////////////////////
  365. void StatementList::outputCodeModel(CodeGenerator &cg) {
  366. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  367. m_stmts[i]->outputCodeModel(cg);
  368. }
  369. }
  370. ///////////////////////////////////////////////////////////////////////////////
  371. // code generation functions
  372. void StatementList::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  373. for (unsigned int i = 0; i < m_stmts.size(); i++) {
  374. StatementPtr stmt = m_stmts[i];
  375. switch (cg.getContext()) {
  376. case CodeGenerator::NoContext:
  377. stmt->outputPHP(cg, ar);
  378. break;
  379. case CodeGenerator::PhpDeclaration:
  380. if (stmt->is(Statement::KindOfFunctionStatement) ||
  381. stmt->is(Statement::KindOfClassStatement) ||
  382. stmt->is(Statement::KindOfInterfaceStatement)) {
  383. cg.setContext(CodeGenerator::PhpImplementation);
  384. stmt->outputPHP(cg, ar);
  385. cg.setContext(CodeGenerator::PhpDeclaration);
  386. }
  387. break;
  388. case CodeGenerator::PhpImplementation:
  389. if (!stmt->is(Statement::KindOfFunctionStatement) &&
  390. !stmt->is(Statement::KindOfClassStatement) &&
  391. !stmt->is(Statement::KindOfInterfaceStatement)) {
  392. stmt->outputPHP(cg, ar);
  393. }
  394. break;
  395. default:
  396. assert(false);
  397. }
  398. }
  399. }