PageRenderTime 1767ms CodeModel.GetById 34ms RepoModel.GetById 1ms app.codeStats 0ms

/src/compiler/expression/simple_function_call.cpp

https://github.com/kevlund/hiphop-php
C++ | 1408 lines | 1211 code | 95 blank | 102 comment | 443 complexity | b3d1b7cac8b20532472e2169f47aefe8 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/simple_function_call.h>
  17. #include <compiler/analysis/file_scope.h>
  18. #include <compiler/analysis/function_scope.h>
  19. #include <compiler/analysis/class_scope.h>
  20. #include <compiler/analysis/code_error.h>
  21. #include <compiler/expression/expression_list.h>
  22. #include <compiler/expression/scalar_expression.h>
  23. #include <compiler/expression/constant_expression.h>
  24. #include <compiler/expression/assignment_expression.h>
  25. #include <compiler/expression/array_pair_expression.h>
  26. #include <compiler/expression/array_element_expression.h>
  27. #include <compiler/expression/unary_op_expression.h>
  28. #include <compiler/expression/parameter_expression.h>
  29. #include <compiler/statement/method_statement.h>
  30. #include <compiler/analysis/constant_table.h>
  31. #include <compiler/analysis/variable_table.h>
  32. #include <util/util.h>
  33. #include <compiler/option.h>
  34. #include <compiler/expression/simple_variable.h>
  35. #include <compiler/parser/parser.h>
  36. #include <runtime/base/complex_types.h>
  37. #include <runtime/base/externals.h>
  38. #include <runtime/base/execution_context.h>
  39. #include <runtime/base/array/array_init.h>
  40. #include <runtime/base/string_util.h>
  41. #include <runtime/ext/ext_variable.h>
  42. using namespace HPHP;
  43. using namespace std;
  44. using namespace boost;
  45. ///////////////////////////////////////////////////////////////////////////////
  46. // statics
  47. std::map<std::string, int> SimpleFunctionCall::FunctionTypeMap;
  48. void SimpleFunctionCall::InitFunctionTypeMap() {
  49. if (FunctionTypeMap.empty()) {
  50. FunctionTypeMap["define"] = DefineFunction;
  51. FunctionTypeMap["create_function"] = CreateFunction;
  52. FunctionTypeMap["func_get_arg"] = VariableArgumentFunction;
  53. FunctionTypeMap["func_get_args"] = VariableArgumentFunction;
  54. FunctionTypeMap["func_num_args"] = VariableArgumentFunction;
  55. FunctionTypeMap["extract"] = ExtractFunction;
  56. FunctionTypeMap["compact"] = CompactFunction;
  57. FunctionTypeMap["shell_exec"] = ShellExecFunction;
  58. FunctionTypeMap["exec"] = ShellExecFunction;
  59. FunctionTypeMap["passthru"] = ShellExecFunction;
  60. FunctionTypeMap["system"] = ShellExecFunction;
  61. FunctionTypeMap["defined"] = DefinedFunction;
  62. FunctionTypeMap["function_exists"] = FunctionExistsFunction;
  63. FunctionTypeMap["class_exists"] = ClassExistsFunction;
  64. FunctionTypeMap["interface_exists"] = InterfaceExistsFunction;
  65. FunctionTypeMap["constant"] = ConstantFunction;
  66. FunctionTypeMap["unserialize"] = UnserializeFunction;
  67. FunctionTypeMap["apc_fetch"] = UnserializeFunction;
  68. FunctionTypeMap["get_defined_vars"] = GetDefinedVarsFunction;
  69. FunctionTypeMap["fb_call_user_func_safe"] = FBCallUserFuncSafeFunction;
  70. FunctionTypeMap["fb_call_user_func_array_safe"] =
  71. FBCallUserFuncSafeFunction;
  72. FunctionTypeMap["fb_call_user_func_safe_return"] =
  73. FBCallUserFuncSafeFunction;
  74. }
  75. }
  76. static class FunctionTypeMapInitializer {
  77. public:
  78. FunctionTypeMapInitializer() {
  79. SimpleFunctionCall::InitFunctionTypeMap();
  80. }
  81. } s_function_type_map_initializer;
  82. ///////////////////////////////////////////////////////////////////////////////
  83. // constructors/destructors
  84. SimpleFunctionCall::SimpleFunctionCall
  85. (EXPRESSION_CONSTRUCTOR_PARAMETERS,
  86. const std::string &name, ExpressionListPtr params, ExpressionPtr cls)
  87. : FunctionCall(EXPRESSION_CONSTRUCTOR_PARAMETER_VALUES(SimpleFunctionCall),
  88. ExpressionPtr(), name, params, cls),
  89. m_type(UnknownType), m_dynamicConstant(false),
  90. m_builtinFunction(false), m_noPrefix(false), m_dynamicInvoke(false),
  91. m_safe(0), m_extra(NULL) {
  92. if (Option::ParseTimeOpts && !m_class && m_className.empty()) {
  93. m_dynamicInvoke = Option::DynamicInvokeFunctions.find(m_name) !=
  94. Option::DynamicInvokeFunctions.end();
  95. map<string, int>::const_iterator iter =
  96. FunctionTypeMap.find(m_name);
  97. if (iter != FunctionTypeMap.end()) {
  98. m_type = iter->second;
  99. }
  100. }
  101. }
  102. ExpressionPtr SimpleFunctionCall::clone() {
  103. SimpleFunctionCallPtr exp(new SimpleFunctionCall(*this));
  104. deepCopy(exp);
  105. return exp;
  106. }
  107. void SimpleFunctionCall::deepCopy(SimpleFunctionCallPtr exp) {
  108. FunctionCall::deepCopy(exp);
  109. exp->m_safeDef = Clone(m_safeDef);
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////
  112. // parser functions
  113. void SimpleFunctionCall::onParse(AnalysisResultConstPtr ar, FileScopePtr fs) {
  114. if (m_class) return;
  115. ConstructPtr self = shared_from_this();
  116. if (m_className.empty()) {
  117. switch (m_type) {
  118. case DefineFunction:
  119. if (m_params && unsigned(m_params->getCount() - 2) <= 1u) {
  120. // need to register the constant before AnalyzeAll, so that
  121. // DefinedFunction can mark this volatile
  122. ExpressionPtr ename = (*m_params)[0];
  123. if (ConstantExpressionPtr cname =
  124. dynamic_pointer_cast<ConstantExpression>(ename)) {
  125. /*
  126. Hack: If the name of the constant being defined is itself
  127. a constant expression, assume that its not yet defined.
  128. So define(FOO, 'bar') is equivalent to define('FOO', 'bar').
  129. */
  130. ename = makeScalarExpression(ar, cname->getName());
  131. m_params->removeElement(0);
  132. m_params->insertElement(ename);
  133. }
  134. ScalarExpressionPtr name =
  135. dynamic_pointer_cast<ScalarExpression>(ename);
  136. if (name) {
  137. string varName = name->getIdentifier();
  138. if (varName.empty()) break;
  139. AnalysisResult::Locker lock(ar);
  140. fs->declareConstant(lock.get(), varName);
  141. // handling define("CONSTANT", ...);
  142. ExpressionPtr value = (*m_params)[1];
  143. BlockScopePtr block = lock->findConstantDeclarer(varName);
  144. ConstantTablePtr constants = block->getConstants();
  145. if (constants != ar->getConstants()) {
  146. constants->add(varName, Type::Some, value, ar, self);
  147. }
  148. }
  149. }
  150. break;
  151. case CreateFunction:
  152. if (m_params->getCount() == 2 &&
  153. (*m_params)[0]->isLiteralString() &&
  154. (*m_params)[1]->isLiteralString()) {
  155. string params = (*m_params)[0]->getLiteralString();
  156. string body = (*m_params)[1]->getLiteralString();
  157. m_lambda = CodeGenerator::GetNewLambda();
  158. string code = "function " + m_lambda + "(" + params + ") "
  159. "{" + body + "}";
  160. m_lambda = "1_" + m_lambda;
  161. ar->appendExtraCode(fs->getName(), code);
  162. }
  163. break;
  164. case VariableArgumentFunction:
  165. /*
  166. Note:
  167. At this point, we dont have a function scope, so we set
  168. the flags on the FileScope.
  169. The FileScope maintains a stack of attributes, so that
  170. it correctly handles each function.
  171. But note that later phases should set/get the attribute
  172. directly on the FunctionScope, rather than on the FileScope
  173. */
  174. fs->setAttribute(FileScope::VariableArgument);
  175. break;
  176. case ExtractFunction:
  177. fs->setAttribute(FileScope::ContainsLDynamicVariable);
  178. fs->setAttribute(FileScope::ContainsExtract);
  179. break;
  180. case CompactFunction: {
  181. // If all the parameters in the compact() call are statically known,
  182. // there is no need to create a variable table.
  183. vector<ExpressionPtr> literals;
  184. if (m_params->flattenLiteralStrings(literals)) {
  185. m_type = StaticCompactFunction;
  186. m_params->clearElements();
  187. for (unsigned i = 0; i < literals.size(); i++) {
  188. m_params->addElement(literals[i]);
  189. }
  190. } else {
  191. fs->setAttribute(FileScope::ContainsDynamicVariable);
  192. }
  193. fs->setAttribute(FileScope::ContainsCompact);
  194. break;
  195. }
  196. case GetDefinedVarsFunction:
  197. fs->setAttribute(FileScope::ContainsDynamicVariable);
  198. fs->setAttribute(FileScope::ContainsGetDefinedVars);
  199. fs->setAttribute(FileScope::ContainsCompact);
  200. break;
  201. default:
  202. break;
  203. }
  204. }
  205. }
  206. ///////////////////////////////////////////////////////////////////////////////
  207. // static analysis functions
  208. void SimpleFunctionCall::addDependencies(AnalysisResultPtr ar) {
  209. if (!m_class) {
  210. if (m_className.empty()) {
  211. addUserFunction(ar, m_name);
  212. } else if ((!isParent() && !isSelf()) ||
  213. getOriginalScope() != getScope()) {
  214. addUserClass(ar, m_className);
  215. }
  216. }
  217. }
  218. void SimpleFunctionCall::setupScopes(AnalysisResultConstPtr ar) {
  219. FunctionScopePtr func;
  220. if (!m_class && m_className.empty()) {
  221. if (!m_dynamicInvoke) {
  222. bool namespaced = (m_name[0] == '\\');
  223. if (namespaced) {
  224. m_name = m_name.substr(1);
  225. }
  226. func = ar->findFunction(m_name);
  227. if (!func && namespaced) {
  228. int pos = m_name.rfind('\\');
  229. m_name = m_name.substr(pos + 1);
  230. func = ar->findFunction(m_name);
  231. }
  232. }
  233. } else {
  234. ClassScopePtr cls = resolveClass();
  235. if (cls) {
  236. m_classScope = cls;
  237. if (m_name == "__construct") {
  238. func = cls->findConstructor(ar, true);
  239. } else {
  240. func = cls->findFunction(ar, m_name, true, true);
  241. }
  242. }
  243. }
  244. if (func && !func->isRedeclaring()) {
  245. if (m_funcScope != func) {
  246. m_funcScope = func;
  247. ASSERT(ar->getPhase() != AnalysisResult::FirstInference);
  248. Construct::recomputeEffects();
  249. m_funcScope->addCaller(getScope());
  250. }
  251. }
  252. }
  253. void SimpleFunctionCall::addLateDependencies(AnalysisResultConstPtr ar) {
  254. m_funcScope.reset();
  255. m_classScope.reset();
  256. setupScopes(ar);
  257. }
  258. ConstructPtr SimpleFunctionCall::getNthKid(int n) const {
  259. if (n == 1) return m_safeDef;
  260. return FunctionCall::getNthKid(n);
  261. }
  262. void SimpleFunctionCall::setNthKid(int n, ConstructPtr cp) {
  263. if (n == 1) {
  264. m_safeDef = boost::dynamic_pointer_cast<Expression>(cp);
  265. } else {
  266. FunctionCall::setNthKid(n, cp);
  267. }
  268. }
  269. void SimpleFunctionCall::analyzeProgram(AnalysisResultPtr ar) {
  270. FunctionCall::analyzeProgram(ar);
  271. if (m_class) {
  272. if (!Option::AllDynamic) {
  273. setDynamicByIdentifier(ar, m_name);
  274. }
  275. } else if (ar->getPhase() >= AnalysisResult::AnalyzeAll) {
  276. addDependencies(ar);
  277. }
  278. if (m_safeDef) m_safeDef->analyzeProgram(ar);
  279. if (ar->getPhase() == AnalysisResult::AnalyzeAll) {
  280. ConstructPtr self = shared_from_this();
  281. // Look up the corresponding FunctionScope and ClassScope
  282. // for this function call
  283. setupScopes(ar);
  284. if (m_funcScope && m_funcScope->getOptFunction()) {
  285. SimpleFunctionCallPtr self(
  286. static_pointer_cast<SimpleFunctionCall>(shared_from_this()));
  287. (m_funcScope->getOptFunction())(0, ar, self, 1);
  288. }
  289. // check for dynamic constant and volatile function/class
  290. if (!m_class && m_className.empty() &&
  291. (m_type == DefinedFunction ||
  292. m_type == FunctionExistsFunction ||
  293. m_type == FBCallUserFuncSafeFunction ||
  294. m_type == ClassExistsFunction ||
  295. m_type == InterfaceExistsFunction) &&
  296. m_params && m_params->getCount() >= 1) {
  297. ExpressionPtr value = (*m_params)[0];
  298. if (value->isScalar()) {
  299. ScalarExpressionPtr name =
  300. dynamic_pointer_cast<ScalarExpression>(value);
  301. if (name && name->isLiteralString()) {
  302. string symbol = name->getLiteralString();
  303. switch (m_type) {
  304. case DefinedFunction: {
  305. ConstantTablePtr constants = ar->getConstants();
  306. if (!constants->isPresent(symbol)) {
  307. // user constant
  308. BlockScopePtr block = ar->findConstantDeclarer(symbol);
  309. if (block) { // found the constant
  310. constants = block->getConstants();
  311. // set to be dynamic
  312. if (m_type == DefinedFunction) {
  313. constants->setDynamic(ar, symbol);
  314. }
  315. }
  316. }
  317. break;
  318. }
  319. case FBCallUserFuncSafeFunction:
  320. case FunctionExistsFunction: {
  321. FunctionScopePtr func = ar->findFunction(Util::toLower(symbol));
  322. if (func && func->isUserFunction()) {
  323. func->setVolatile();
  324. }
  325. break;
  326. }
  327. case InterfaceExistsFunction:
  328. case ClassExistsFunction: {
  329. ClassScopePtr cls = ar->findClass(Util::toLower(symbol));
  330. if (cls && cls->isUserClass()) {
  331. cls->setVolatile();
  332. }
  333. break;
  334. }
  335. default:
  336. ASSERT(false);
  337. }
  338. }
  339. } else if ((m_type == InterfaceExistsFunction ||
  340. m_type == ClassExistsFunction) &&
  341. value->is(KindOfSimpleVariable)) {
  342. SimpleVariablePtr name = dynamic_pointer_cast<SimpleVariable>(value);
  343. if (name && name->getSymbol()) {
  344. // name is checked as class name
  345. name->getSymbol()->setClassName();
  346. }
  347. }
  348. }
  349. if (m_type == StaticCompactFunction) {
  350. FunctionScopePtr fs = getFunctionScope();
  351. VariableTablePtr vt = fs->getVariables();
  352. if (vt->isPseudoMainTable() ||
  353. vt->getAttribute(VariableTable::ContainsDynamicVariable)) {
  354. // When there is a variable table already, we will keep the ordinary
  355. // compact() call.
  356. m_type = CompactFunction;
  357. } else {
  358. // compact('a', 'b', 'c') becomes compact('a', $a, 'b', $b, 'c', $c)
  359. vector<ExpressionPtr> new_params;
  360. vector<string> strs;
  361. for (int i = 0; i < m_params->getCount(); i++) {
  362. ExpressionPtr e = (*m_params)[i];
  363. assert(e->isLiteralString());
  364. string name = e->getLiteralString();
  365. // no need to record duplicate names
  366. bool found = false;
  367. for (unsigned j = 0; j < strs.size(); j++) {
  368. if (strcasecmp(name.data(), strs[j].data()) == 0) {
  369. found = true;
  370. break;
  371. }
  372. }
  373. if (found) continue;
  374. strs.push_back(name);
  375. SimpleVariablePtr var(new SimpleVariable(
  376. e->getScope(), e->getLocation(), name));
  377. var->copyContext(e);
  378. var->updateSymbol(SimpleVariablePtr());
  379. new_params.push_back(e);
  380. new_params.push_back(var);
  381. }
  382. m_params->clearElements();
  383. for (unsigned i = 0; i < new_params.size(); i++) {
  384. m_params->addElement(new_params[i]);
  385. }
  386. }
  387. }
  388. if (m_type == UnserializeFunction) {
  389. ar->forceClassVariants(getOriginalClass(), false);
  390. }
  391. if (m_params) {
  392. markRefParams(m_funcScope, m_name, canInvokeFewArgs());
  393. }
  394. } else if (ar->getPhase() == AnalysisResult::AnalyzeFinal) {
  395. if (!m_class && !m_redeclared && !m_dynamicInvoke && !m_funcScope &&
  396. (m_className.empty() ||
  397. (m_classScope &&
  398. !m_classScope->isTrait() &&
  399. !m_classScope->derivesFromRedeclaring() &&
  400. !m_classScope->getAttribute(
  401. ClassScope::HasUnknownStaticMethodHandler) &&
  402. !m_classScope->getAttribute(
  403. ClassScope::InheritsUnknownStaticMethodHandler)))) {
  404. Compiler::Error(Compiler::UnknownFunction, shared_from_this());
  405. }
  406. }
  407. }
  408. bool SimpleFunctionCall::readsLocals() const {
  409. return m_type == GetDefinedVarsFunction ||
  410. m_type == CompactFunction;
  411. }
  412. bool SimpleFunctionCall::writesLocals() const {
  413. return m_type == ExtractFunction;
  414. }
  415. void SimpleFunctionCall::updateVtFlags() {
  416. FunctionScopeRawPtr f = getFunctionScope();
  417. if (f) {
  418. if (m_funcScope) {
  419. if (m_funcScope->getContextSensitive()) {
  420. f->setInlineSameContext(true);
  421. }
  422. if ((m_classScope && (isSelf() || isParent()) &&
  423. m_funcScope->usesLSB()) ||
  424. isStatic() ||
  425. m_type == FBCallUserFuncSafeFunction ||
  426. m_name == "call_user_func" ||
  427. m_name == "call_user_func_array" ||
  428. m_name == "forward_static_call" ||
  429. m_name == "forward_static_call_array" ||
  430. m_name == "hphp_create_continuation" ||
  431. m_name == "get_called_class") {
  432. f->setNextLSB(true);
  433. }
  434. }
  435. }
  436. if (m_type != UnknownType) {
  437. VariableTablePtr vt = getScope()->getVariables();
  438. switch (m_type) {
  439. case ExtractFunction:
  440. vt->setAttribute(VariableTable::ContainsLDynamicVariable);
  441. vt->setAttribute(VariableTable::ContainsExtract);
  442. break;
  443. case CompactFunction:
  444. vt->setAttribute(VariableTable::ContainsDynamicVariable);
  445. case StaticCompactFunction:
  446. vt->setAttribute(VariableTable::ContainsCompact);
  447. break;
  448. case GetDefinedVarsFunction:
  449. vt->setAttribute(VariableTable::ContainsDynamicVariable);
  450. vt->setAttribute(VariableTable::ContainsGetDefinedVars);
  451. vt->setAttribute(VariableTable::ContainsCompact);
  452. break;
  453. }
  454. }
  455. }
  456. bool SimpleFunctionCall::isDefineWithoutImpl(AnalysisResultConstPtr ar) {
  457. if (m_class || !m_className.empty()) return false;
  458. if (m_type == DefineFunction && m_params &&
  459. unsigned(m_params->getCount() - 2) <= 1u) {
  460. if (m_dynamicConstant) return false;
  461. ScalarExpressionPtr name =
  462. dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
  463. if (!name) return false;
  464. string varName = name->getIdentifier();
  465. if (varName.empty()) return false;
  466. if (ar->isSystemConstant(varName)) {
  467. assert(!m_extra);
  468. return true;
  469. }
  470. ExpressionPtr value = (*m_params)[1];
  471. if (ar->isConstantRedeclared(varName)) {
  472. return false;
  473. }
  474. Variant scalarValue;
  475. return (value->isScalar() &&
  476. value->getScalarValue(scalarValue) &&
  477. scalarValue.isAllowedAsConstantValue());
  478. } else {
  479. return false;
  480. }
  481. }
  482. ExpressionPtr SimpleFunctionCall::optimize(AnalysisResultConstPtr ar) {
  483. if (m_class || !m_funcScope ||
  484. (!m_className.empty() && (!m_classScope || !isPresent()))) {
  485. return ExpressionPtr();
  486. }
  487. if (!m_funcScope->isUserFunction()) {
  488. if (m_type == ExtractFunction && m_params && m_params->getCount() >= 1) {
  489. ExpressionPtr vars = (*m_params)[0];
  490. while (vars) {
  491. if (vars->is(KindOfUnaryOpExpression) &&
  492. static_pointer_cast<UnaryOpExpression>(vars)->getOp() == T_ARRAY) {
  493. break;
  494. }
  495. if (vars->is(KindOfExpressionList)) {
  496. vars = static_pointer_cast<ExpressionList>(vars)->listValue();
  497. } else {
  498. vars = vars->getCanonPtr();
  499. }
  500. }
  501. if (vars) {
  502. bool svar = vars->isScalar();
  503. if (!svar && getScope()->getUpdated()) {
  504. /*
  505. * kind of a hack. If the extract param is non-scalar,
  506. * and we've made changes already, dont try to optimize yet.
  507. * this gives us a better chance of getting a scalar result.
  508. * Later, we should add more array optimizations, which would
  509. * allow us to optimize the generated code once the scalar
  510. * expressions are resolved
  511. */
  512. return ExpressionPtr();
  513. }
  514. int n = m_params->getCount();
  515. String prefix;
  516. int mode = EXTR_OVERWRITE;
  517. if (n >= 2) {
  518. Variant v;
  519. ExpressionPtr m = (*m_params)[1];
  520. if (m->isScalar() && m->getScalarValue(v)) {
  521. mode = v.toInt64();
  522. }
  523. if (n >= 3) {
  524. ExpressionPtr p = (*m_params)[2];
  525. if (p->isScalar() && p->getScalarValue(v)) {
  526. prefix = v.toString();
  527. }
  528. }
  529. }
  530. bool ref = mode & EXTR_REFS;
  531. mode &= ~EXTR_REFS;
  532. switch (mode) {
  533. case EXTR_PREFIX_ALL:
  534. case EXTR_PREFIX_INVALID:
  535. case EXTR_OVERWRITE: {
  536. ExpressionListPtr arr(
  537. static_pointer_cast<ExpressionList>(
  538. static_pointer_cast<UnaryOpExpression>(vars)->getExpression()));
  539. ExpressionListPtr rep(
  540. new ExpressionList(getScope(), getLocation(),
  541. ExpressionList::ListKindWrapped));
  542. string root_name;
  543. int n = arr ? arr->getCount() : 0;
  544. int i, j, k;
  545. for (i = j = k = 0; i < n; i++) {
  546. ArrayPairExpressionPtr ap(
  547. dynamic_pointer_cast<ArrayPairExpression>((*arr)[i]));
  548. assert(ap);
  549. String name;
  550. Variant voff;
  551. if (!ap->getName()) {
  552. voff = j++;
  553. } else {
  554. if (!ap->getName()->isScalar() ||
  555. !ap->getName()->getScalarValue(voff)) {
  556. return ExpressionPtr();
  557. }
  558. }
  559. name = voff.toString();
  560. if (mode == EXTR_PREFIX_ALL ||
  561. (mode == EXTR_PREFIX_INVALID &&
  562. !name.isValidVariableName())) {
  563. name = prefix + "_" + name;
  564. }
  565. if (!name.isValidVariableName()) continue;
  566. SimpleVariablePtr var(
  567. new SimpleVariable(getScope(), getLocation(), name.data()));
  568. var->updateSymbol(SimpleVariablePtr());
  569. ExpressionPtr val(ap->getValue());
  570. if (!val->isScalar()) {
  571. if (root_name.empty()) {
  572. root_name = "t" + lexical_cast<string>(
  573. getFunctionScope()->nextInlineIndex());
  574. SimpleVariablePtr rv(
  575. new SimpleVariable(getScope(), getLocation(), root_name));
  576. rv->updateSymbol(SimpleVariablePtr());
  577. rv->getSymbol()->setHidden();
  578. ExpressionPtr root(
  579. new AssignmentExpression(getScope(), getLocation(),
  580. rv, (*m_params)[0], false));
  581. rep->insertElement(root);
  582. }
  583. SimpleVariablePtr rv(
  584. new SimpleVariable(getScope(), getLocation(), root_name));
  585. rv->updateSymbol(SimpleVariablePtr());
  586. rv->getSymbol()->setHidden();
  587. ExpressionPtr offset(makeScalarExpression(ar, voff));
  588. val = ExpressionPtr(
  589. new ArrayElementExpression(getScope(), getLocation(),
  590. rv, offset));
  591. }
  592. ExpressionPtr a(
  593. new AssignmentExpression(getScope(), getLocation(),
  594. var, val, ref));
  595. rep->addElement(a);
  596. k++;
  597. }
  598. if (root_name.empty()) {
  599. if ((*m_params)[0]->hasEffect()) {
  600. rep->insertElement((*m_params)[0]);
  601. }
  602. } else {
  603. ExpressionListPtr unset_list
  604. (new ExpressionList(getScope(), getLocation()));
  605. SimpleVariablePtr rv(
  606. new SimpleVariable(getScope(), getLocation(), root_name));
  607. rv->updateSymbol(SimpleVariablePtr());
  608. unset_list->addElement(rv);
  609. ExpressionPtr unset(
  610. new UnaryOpExpression(getScope(), getLocation(),
  611. unset_list, T_UNSET, true));
  612. rep->addElement(unset);
  613. }
  614. rep->addElement(makeScalarExpression(ar, k));
  615. return replaceValue(rep);
  616. }
  617. default: break;
  618. }
  619. }
  620. }
  621. }
  622. if (!m_classScope && !m_funcScope->isUserFunction()) {
  623. if (m_type == UnknownType && m_funcScope->isFoldable()) {
  624. Array arr;
  625. if (m_params) {
  626. if (!m_params->isScalar()) return ExpressionPtr();
  627. for (int i = 0, n = m_params->getCount(); i < n; ++i) {
  628. Variant v;
  629. if (!(*m_params)[i]->getScalarValue(v)) return ExpressionPtr();
  630. arr.set(i, v);
  631. }
  632. if (m_arrayParams) {
  633. arr = arr[0];
  634. }
  635. }
  636. try {
  637. g_context->setThrowAllErrors(true);
  638. Variant v = invoke_builtin(m_funcScope->getName().c_str(),
  639. arr, -1, true);
  640. g_context->setThrowAllErrors(false);
  641. return makeScalarExpression(ar, v);
  642. } catch (...) {
  643. g_context->setThrowAllErrors(false);
  644. }
  645. return ExpressionPtr();
  646. }
  647. if (m_funcScope->getOptFunction()) {
  648. SimpleFunctionCallPtr self(
  649. static_pointer_cast<SimpleFunctionCall>(shared_from_this()));
  650. ExpressionPtr e = (m_funcScope->getOptFunction())(0, ar, self, 0);
  651. if (e) return e;
  652. }
  653. }
  654. if (m_type != UnknownType || m_safe) {
  655. return ExpressionPtr();
  656. }
  657. return inliner(ar, ExpressionPtr(), m_localThis);
  658. }
  659. ExpressionPtr SimpleFunctionCall::preOptimize(AnalysisResultConstPtr ar) {
  660. if (m_class) updateClassName();
  661. if (ar->getPhase() < AnalysisResult::FirstPreOptimize) {
  662. return ExpressionPtr();
  663. }
  664. if (ExpressionPtr rep = onPreOptimize(ar)) {
  665. return rep;
  666. }
  667. if (ExpressionPtr rep = optimize(ar)) {
  668. return rep;
  669. }
  670. if (!m_class && m_className.empty() &&
  671. (m_type == DefineFunction ||
  672. m_type == DefinedFunction ||
  673. m_type == FBCallUserFuncSafeFunction ||
  674. m_type == FunctionExistsFunction ||
  675. m_type == ClassExistsFunction ||
  676. m_type == InterfaceExistsFunction) &&
  677. m_params &&
  678. (m_type == DefineFunction ?
  679. unsigned(m_params->getCount() - 2) <= 1u :
  680. m_type == FBCallUserFuncSafeFunction ? m_params->getCount() >= 1 :
  681. m_params->getCount() == 1)) {
  682. ExpressionPtr value = (*m_params)[0];
  683. if (value->isScalar()) {
  684. ScalarExpressionPtr name = dynamic_pointer_cast<ScalarExpression>(value);
  685. if (name && name->isLiteralString()) {
  686. string symbol = name->getLiteralString();
  687. switch (m_type) {
  688. case DefineFunction: {
  689. ConstantTableConstPtr constants = ar->getConstants();
  690. // system constant
  691. if (constants->isPresent(symbol)) {
  692. break;
  693. }
  694. // user constant
  695. BlockScopeConstPtr block = ar->findConstantDeclarer(symbol);
  696. // not found (i.e., undefined)
  697. if (!block) break;
  698. constants = block->getConstants();
  699. const Symbol *sym = constants->getSymbol(symbol);
  700. assert(sym);
  701. m_extra = (void *)sym;
  702. Lock lock(BlockScope::s_constMutex);
  703. if (!sym->isDynamic() && sym->getValue() != (*m_params)[1]) {
  704. if (sym->getDeclaration() != shared_from_this()) {
  705. // redeclared
  706. const_cast<Symbol*>(sym)->setDynamic();
  707. }
  708. const_cast<Symbol*>(sym)->setValue((*m_params)[1]);
  709. getScope()->addUpdates(BlockScope::UseKindConstRef);
  710. }
  711. break;
  712. }
  713. case DefinedFunction: {
  714. if (symbol == "false" ||
  715. symbol == "true" ||
  716. symbol == "null") {
  717. return CONSTANT("true");
  718. }
  719. ConstantTableConstPtr constants = ar->getConstants();
  720. // system constant
  721. if (constants->isPresent(symbol) && !constants->isDynamic(symbol)) {
  722. return CONSTANT("true");
  723. }
  724. // user constant
  725. BlockScopeConstPtr block = ar->findConstantDeclarer(symbol);
  726. // not found (i.e., undefined)
  727. if (!block) {
  728. if (symbol.find("::") == std::string::npos) {
  729. return CONSTANT("false");
  730. } else {
  731. // e.g., defined("self::ZERO")
  732. return ExpressionPtr();
  733. }
  734. }
  735. constants = block->getConstants();
  736. // already set to be dynamic
  737. if (constants->isDynamic(symbol)) return ExpressionPtr();
  738. Lock lock(BlockScope::s_constMutex);
  739. ConstructPtr decl = constants->getValue(symbol);
  740. ExpressionPtr constValue = dynamic_pointer_cast<Expression>(decl);
  741. if (constValue->isScalar()) {
  742. return CONSTANT("true");
  743. } else {
  744. return ExpressionPtr();
  745. }
  746. break;
  747. }
  748. case FBCallUserFuncSafeFunction:
  749. case FunctionExistsFunction: {
  750. const std::string &lname = Util::toLower(symbol);
  751. if (Option::DynamicInvokeFunctions.find(lname) ==
  752. Option::DynamicInvokeFunctions.end()) {
  753. FunctionScopePtr func = ar->findFunction(lname);
  754. if (!func && m_type == FunctionExistsFunction) {
  755. return CONSTANT("false");
  756. }
  757. if (func->isUserFunction()) {
  758. func->setVolatile();
  759. }
  760. if (!func->isVolatile() && m_type == FunctionExistsFunction) {
  761. return CONSTANT("true");
  762. }
  763. }
  764. break;
  765. }
  766. case InterfaceExistsFunction: {
  767. ClassScopePtrVec classes = ar->findClasses(Util::toLower(symbol));
  768. bool interfaceFound = false;
  769. for (ClassScopePtrVec::const_iterator it = classes.begin();
  770. it != classes.end(); ++it) {
  771. ClassScopePtr cls = *it;
  772. if (cls->isUserClass()) cls->setVolatile();
  773. if (cls->isInterface()) {
  774. interfaceFound = true;
  775. }
  776. }
  777. if (!interfaceFound) return CONSTANT("false");
  778. if (classes.size() == 1 && !classes.back()->isVolatile()) {
  779. return CONSTANT("true");
  780. }
  781. break;
  782. }
  783. case ClassExistsFunction: {
  784. ClassScopePtrVec classes = ar->findClasses(Util::toLower(symbol));
  785. bool classFound = false;
  786. for (ClassScopePtrVec::const_iterator it = classes.begin();
  787. it != classes.end(); ++it) {
  788. ClassScopePtr cls = *it;
  789. if (cls->isUserClass()) cls->setVolatile();
  790. if (!cls->isInterface()) {
  791. classFound = true;
  792. }
  793. }
  794. if (!classFound) return CONSTANT("false");
  795. if (classes.size() == 1 && !classes.back()->isVolatile()) {
  796. return CONSTANT("true");
  797. }
  798. break;
  799. }
  800. default:
  801. ASSERT(false);
  802. }
  803. }
  804. }
  805. }
  806. return ExpressionPtr();
  807. }
  808. ExpressionPtr SimpleFunctionCall::postOptimize(AnalysisResultConstPtr ar) {
  809. if (!Option::KeepStatementsWithNoEffect && isDefineWithoutImpl(ar)) {
  810. Construct::recomputeEffects();
  811. if (m_extra) {
  812. Symbol *sym = (Symbol *)m_extra;
  813. Lock lock(BlockScope::s_constMutex);
  814. sym->setReplaced();
  815. }
  816. return m_extra ? CONSTANT("true") : CONSTANT("false");
  817. }
  818. if (m_type == StaticCompactFunction) {
  819. for (int i = 0; i < m_params->getCount(); i += 2) {
  820. ExpressionPtr e = (*m_params)[i + 1];
  821. if (e->is(KindOfUnaryOpExpression) &&
  822. static_pointer_cast<UnaryOpExpression>(e)->getOp() == T_UNSET_CAST) {
  823. m_params->removeElement(i);
  824. m_params->removeElement(i);
  825. i -= 2;
  826. m_extraArg -= 2;
  827. if (m_extraArg < 0) m_extraArg = 0;
  828. }
  829. }
  830. if (!m_params->getCount()) {
  831. ExpressionPtr rep(new UnaryOpExpression(getScope(), getLocation(),
  832. ExpressionPtr(), T_ARRAY, true));
  833. return replaceValue(rep);
  834. }
  835. m_params->resetOutputCount();
  836. }
  837. /*
  838. Dont do this for now. Need to take account of newly created
  839. variables etc (which would normally be handled by inferTypes).
  840. if (ExpressionPtr rep = optimize(ar)) {
  841. return rep;
  842. }
  843. */
  844. return FunctionCall::postOptimize(ar);
  845. }
  846. int SimpleFunctionCall::getLocalEffects() const {
  847. if (m_class) return UnknownEffect;
  848. if (m_funcScope && !m_funcScope->hasEffect()) {
  849. return 0;
  850. }
  851. return UnknownEffect;
  852. }
  853. TypePtr SimpleFunctionCall::inferTypes(AnalysisResultPtr ar, TypePtr type,
  854. bool coerce) {
  855. ASSERT(false);
  856. return TypePtr();
  857. }
  858. TypePtr SimpleFunctionCall::inferAndCheck(AnalysisResultPtr ar, TypePtr type,
  859. bool coerce) {
  860. ASSERT(type);
  861. IMPLEMENT_INFER_AND_CHECK_ASSERT(getScope());
  862. resetTypes();
  863. reset();
  864. if (m_class) {
  865. m_class->inferAndCheck(ar, Type::Any, false);
  866. }
  867. if (m_safeDef) {
  868. m_safeDef->inferAndCheck(ar, Type::Any, false);
  869. }
  870. if (m_safe) {
  871. getScope()->getVariables()->
  872. setAttribute(VariableTable::NeedGlobalPointer);
  873. }
  874. ConstructPtr self = shared_from_this();
  875. // handling define("CONSTANT", ...);
  876. if (!m_class && m_className.empty()) {
  877. if (m_type == DefineFunction && m_params &&
  878. unsigned(m_params->getCount() - 2) <= 1u) {
  879. ScalarExpressionPtr name =
  880. dynamic_pointer_cast<ScalarExpression>((*m_params)[0]);
  881. if (name) {
  882. string varName = name->getIdentifier();
  883. if (!varName.empty()) {
  884. ExpressionPtr value = (*m_params)[1];
  885. TypePtr varType = value->inferAndCheck(ar, Type::Some, false);
  886. BlockScopePtr block;
  887. bool newlyDeclared = false;
  888. {
  889. Lock lock(ar->getMutex());
  890. block = ar->findConstantDeclarer(varName);
  891. if (!block) {
  892. FileScopeRawPtr fs(getFileScope());
  893. GET_LOCK(fs); // file scope cannot depend on a function scope
  894. fs->declareConstant(ar, varName);
  895. block = ar->findConstantDeclarer(varName);
  896. newlyDeclared = true;
  897. }
  898. }
  899. ASSERT(block);
  900. ConstantTablePtr constants = block->getConstants();
  901. if (constants != ar->getConstants()) {
  902. TRY_LOCK(block);
  903. if (value && !value->isScalar()) {
  904. constants->setDynamic(ar, varName);
  905. varType = Type::Variant;
  906. }
  907. if (constants->isDynamic(varName)) {
  908. m_dynamicConstant = true;
  909. getScope()->getVariables()->
  910. setAttribute(VariableTable::NeedGlobalPointer);
  911. } else {
  912. if (newlyDeclared) {
  913. const Symbol *sym = constants->getSymbol(varName);
  914. ASSERT(!sym || !sym->declarationSet());
  915. constants->add(varName, varType, value, ar, self);
  916. sym = constants->getSymbol(varName);
  917. assert(sym);
  918. m_extra = (void *)sym;
  919. } else {
  920. constants->setType(ar, varName, varType, true);
  921. }
  922. }
  923. // in case the old 'value' has been optimized
  924. constants->setValue(ar, varName, value);
  925. } else {
  926. assert(!newlyDeclared);
  927. }
  928. m_valid = true;
  929. return checkTypesImpl(ar, type, Type::Boolean, coerce);
  930. }
  931. }
  932. if (getScope()->isFirstPass()) {
  933. Compiler::Error(Compiler::BadDefine, self);
  934. }
  935. } else if (m_type == ExtractFunction || m_type == GetDefinedVarsFunction) {
  936. getScope()->getVariables()->forceVariants(ar, VariableTable::AnyVars);
  937. }
  938. }
  939. FunctionScopePtr func;
  940. if (!m_class && m_className.empty()) {
  941. if (!m_dynamicInvoke) {
  942. func = ar->findFunction(m_name);
  943. }
  944. } else {
  945. ClassScopePtr cls = resolveClass();
  946. if (cls && !isPresent()) {
  947. getScope()->getVariables()
  948. ->setAttribute(VariableTable::NeedGlobalPointer);
  949. }
  950. if (!cls) {
  951. if (!m_class && !isRedeclared() && getScope()->isFirstPass()) {
  952. Compiler::Error(Compiler::UnknownClass, self);
  953. }
  954. if (m_params) {
  955. m_params->inferAndCheck(ar, Type::Some, false);
  956. m_params->markParams(canInvokeFewArgs());
  957. }
  958. return checkTypesImpl(ar, type, Type::Variant, coerce);
  959. }
  960. m_classScope = cls;
  961. if (m_name == "__construct") {
  962. // if the class is known, php will try to identify class-name ctor
  963. func = cls->findConstructor(ar, true);
  964. } else {
  965. func = cls->findFunction(ar, m_name, true, true);
  966. }
  967. if (func && !func->isStatic()) {
  968. ClassScopePtr clsThis = getOriginalClass();
  969. FunctionScopePtr funcThis = getOriginalFunction();
  970. if (!Option::AllDynamic &&
  971. (!clsThis ||
  972. (clsThis != m_classScope &&
  973. !clsThis->derivesFrom(ar, m_className, true, false)) ||
  974. funcThis->isStatic())) {
  975. func->setDynamic();
  976. }
  977. }
  978. }
  979. if (!func || func->isRedeclaring() || func->isAbstract()) {
  980. if (m_funcScope) {
  981. m_funcScope.reset();
  982. Construct::recomputeEffects();
  983. }
  984. if (func && func->isRedeclaring()) {
  985. m_redeclared = true;
  986. getScope()->getVariables()->
  987. setAttribute(VariableTable::NeedGlobalPointer);
  988. }
  989. if (m_params) {
  990. if (func && func->isRedeclaring()) {
  991. FunctionScope::FunctionInfoPtr info =
  992. FunctionScope::GetFunctionInfo(m_name);
  993. assert(info);
  994. for (int i = m_params->getCount(); i--; ) {
  995. if (!Option::WholeProgram || info->isRefParam(i)) {
  996. m_params->markParam(i, canInvokeFewArgs());
  997. }
  998. }
  999. }
  1000. if (m_arrayParams) {
  1001. (*m_params)[0]->inferAndCheck(ar, Type::Array, false);
  1002. } else {
  1003. m_params->inferAndCheck(ar, Type::Some, false);
  1004. }
  1005. }
  1006. return checkTypesImpl(ar, type, Type::Variant, coerce);
  1007. } else if (func != m_funcScope) {
  1008. ASSERT(!m_funcScope ||
  1009. !func->hasUser(getScope(), BlockScope::UseKindCaller));
  1010. m_funcScope = func;
  1011. m_funcScope->addCaller(getScope(), !type->is(Type::KindOfAny));
  1012. Construct::recomputeEffects();
  1013. }
  1014. m_builtinFunction = (!func->isUserFunction() || func->isSepExtension());
  1015. beforeCheck(ar);
  1016. m_valid = true;
  1017. TypePtr rtype = checkParamsAndReturn(ar, type, coerce,
  1018. func, m_arrayParams);
  1019. // this is ok un-guarded b/c this value never gets un-set (once its
  1020. // true its always true) and the value itself doesn't get read
  1021. // until outputCPP time
  1022. if (m_arrayParams && func && !m_builtinFunction) func->setDirectInvoke();
  1023. if (m_safe) {
  1024. TypePtr atype = getActualType();
  1025. if (m_safe > 0 && !m_safeDef) {
  1026. atype = Type::Array;
  1027. } else if (!m_safeDef) {
  1028. atype = Type::Variant;
  1029. } else {
  1030. TypePtr t = m_safeDef->getActualType();
  1031. if (!t || !atype || !Type::SameType(t, atype)) {
  1032. atype = Type::Variant;
  1033. }
  1034. }
  1035. rtype = checkTypesImpl(ar, type, atype, coerce);
  1036. m_voidReturn = m_voidWrapper = false;
  1037. }
  1038. if (m_valid && !m_className.empty() &&
  1039. (!m_funcScope || !m_funcScope->isStatic())) {
  1040. int objCall = checkObjCall(ar);
  1041. if (objCall < 0 || (objCall > 0 && !m_localThis.empty())) {
  1042. m_implementedType = Type::Variant;
  1043. }
  1044. }
  1045. ASSERT(rtype);
  1046. return rtype;
  1047. }
  1048. ///////////////////////////////////////////////////////////////////////////////
  1049. // code generation functions
  1050. void SimpleFunctionCall::outputPHP(CodeGenerator &cg, AnalysisResultPtr ar) {
  1051. outputLineMap(cg, ar);
  1052. if (m_class || !m_className.empty()) {
  1053. StaticClassName::outputPHP(cg, ar);
  1054. cg_printf("::%s(", m_origName.c_str());
  1055. } else {
  1056. if (cg.getOutput() == CodeGenerator::InlinedPHP ||
  1057. cg.getOutput() == CodeGenerator::TrimmedPHP) {
  1058. if (cg.getOutput() == CodeGenerator::TrimmedPHP &&
  1059. cg.usingStream(CodeGenerator::PrimaryStream) &&
  1060. Option::DynamicFunctionCalls.find(m_name) !=
  1061. Option::DynamicFunctionCalls.end()) {
  1062. int funcNamePos = Option::DynamicFunctionCalls[m_name];
  1063. if (m_params && m_params->getCount() &&
  1064. m_params->getCount() >= funcNamePos + 1) {
  1065. if (funcNamePos == -1) funcNamePos = m_params->getCount() - 1;
  1066. ExpressionPtr funcName = (*m_params)[funcNamePos];
  1067. if (!funcName->is(Expression::KindOfScalarExpression)) {
  1068. cg_printf("%s(", m_name.c_str());
  1069. for (int i = 0; i < m_params->getCount(); i++) {
  1070. if (i > 0) cg_printf(", ");
  1071. if (i == funcNamePos) {
  1072. cg_printf("%sdynamic_load(", Option::IdPrefix.c_str());
  1073. funcName->outputPHP(cg, ar);
  1074. cg_printf(")");
  1075. } else {
  1076. ExpressionPtr param = (*m_params)[i];
  1077. if (param) param->outputPHP(cg, ar);
  1078. }
  1079. }
  1080. cg_printf(")");
  1081. return;
  1082. }
  1083. }
  1084. }
  1085. cg_printf("%s(", m_origName.c_str());
  1086. } else {
  1087. cg_printf("%s(", m_origName.c_str());
  1088. }
  1089. }
  1090. if (m_params) m_params->outputPHP(cg, ar);
  1091. cg_printf(")");
  1092. }
  1093. /*
  1094. * returns: 1 - if the call is dynamic
  1095. * -1 - if the call may be dynamic, depending on redeclared derivation
  1096. * 0 - if the call is static (ie with an "empty" this).
  1097. */
  1098. static int isObjCall(AnalysisResultPtr ar,
  1099. ClassScopeRawPtr thisCls, FunctionScopeRawPtr thisFunc,
  1100. ClassScopeRawPtr methCls, const std::string &methClsName) {
  1101. if (!thisCls || !thisFunc || thisFunc->isStatic()) return 0;
  1102. if (thisCls == methCls) return 1;
  1103. if (thisCls->derivesFrom(ar, methClsName, true, false)) return 1;
  1104. if (thisCls->derivesFromRedeclaring() &&
  1105. thisCls->derivesFrom(ar, methClsName, true, true)) {
  1106. return -1;
  1107. }
  1108. return 0;
  1109. }
  1110. FunctionScopePtr
  1111. SimpleFunctionCall::getFuncScopeFromParams(AnalysisResultPtr ar,
  1112. BlockScopeRawPtr scope,
  1113. ExpressionPtr clsName,
  1114. ExpressionPtr funcName,
  1115. ClassScopePtr &clsScope) {
  1116. clsScope.reset();
  1117. ScalarExpressionPtr clsName0(
  1118. dynamic_pointer_cast<ScalarExpression>(clsName));
  1119. ScalarExpressionPtr funcName0(
  1120. dynamic_pointer_cast<ScalarExpression>(funcName));
  1121. if (clsName0 && funcName0) {
  1122. string cname = clsName0->getLiteralString();
  1123. string fname = funcName0->getLiteralString();
  1124. if (!fname.empty()) {
  1125. if (!cname.empty()) {
  1126. ClassScopePtr cscope(ar->findClass(cname));
  1127. if (cscope && cscope->isRedeclaring()) {
  1128. cscope = scope->findExactClass(Util::toLower(cname));
  1129. }
  1130. if (cscope) {
  1131. FunctionScopePtr fscope(cscope->findFunction(ar, fname, true));
  1132. if (fscope) {
  1133. clsScope = cscope;
  1134. }
  1135. return fscope;
  1136. }
  1137. } else {
  1138. FunctionScopePtr fscope(ar->findFunction(fname));
  1139. return fscope;
  1140. }
  1141. }
  1142. }
  1143. return FunctionScopePtr();
  1144. }
  1145. int SimpleFunctionCall::checkObjCall(AnalysisResultPtr ar) {
  1146. ClassScopeRawPtr orig = getOriginalClass();
  1147. int objCall = isObjCall(ar, orig, getOriginalFunction(),
  1148. m_classScope, m_className);
  1149. if (objCall > 0 && m_localThis.empty() &&
  1150. (getClassScope() != orig || getFunctionScope()->isStatic())) {
  1151. int o = isObjCall(ar, getClassScope(), getFunctionScope(),
  1152. orig, orig->getName());
  1153. if (o <= 0) objCall = o;
  1154. }
  1155. return objCall;
  1156. }
  1157. bool SimpleFunctionCall::preOutputCPP(CodeGenerator &cg, AnalysisResultPtr ar,
  1158. int state) {
  1159. if (m_type == StaticCompactFunction) {
  1160. if (!cg.inExpression()) return true;
  1161. cg.wrapExpressionBegin();
  1162. m_ciTemp = cg.createNewLocalId(shared_from_this());
  1163. cg_printf("ArrayInit compact%d(%d);\n",
  1164. m_ciTemp, m_params->getCount() / 2);
  1165. for (int i = 0; i < m_params->getCount(); i += 2) {
  1166. assert((*m_params)[i]->isLiteralString());
  1167. string p = (*m_params)[i]->getLiteralString();
  1168. ExpressionPtr e = (*m_params)[i + 1];
  1169. if (e->is(KindOfSimpleVariable)
  1170. && Type::SameType(e->getCPPType(), Type::Variant)) {
  1171. SimpleVariablePtr sv = dynamic_pointer_cast<SimpleVariable>(e);
  1172. const string &cppName = sv->getAssignableCPPVariable(ar);
  1173. ASSERT(!cppName.empty());
  1174. cg_printf("if (%s.isInitialized()) ", cppName.c_str());
  1175. }
  1176. e->preOutputCPP(cg, ar, 0);
  1177. cg_printf("compact%d.add(", m_ciTemp);
  1178. cg_printString(p, ar, shared_from_this());
  1179. cg_printf(", ");
  1180. e->outputCPP(cg, ar);
  1181. cg_printf(");\n");
  1182. }
  1183. return true;
  1184. }
  1185. int objCall = 0;
  1186. if (!m_className.empty() && (!m_funcScope || !m_funcScope->isStatic())) {
  1187. objCall = checkObjCall(ar);
  1188. if (objCall < 0) {
  1189. /*
  1190. We have X::foo (which is non-static) inside a non-static
  1191. method of Y, where Y may or may not be derived from X, depending
  1192. on redeclared classes.
  1193. Revert to dynamic dispatch for this case.
  1194. */
  1195. m_valid = false;
  1196. } else if (objCall > 0 && !m_localThis.empty()) {
  1197. m_valid = false;
  1198. }
  1199. }
  1200. if (m_valid) {
  1201. bool ret = false;
  1202. if (m_classScope &&
  1203. (m_arrayParams || !m_funcScope->isStatic())) {
  1204. ret = true;
  1205. if (cg.inExpression()) {
  1206. if (m_funcScope->isStatic()) {
  1207. cg.wrapExpressionBegin();
  1208. m_ciTemp = cg.createNewLocalId(shared_from_this());
  1209. cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
  1210. // mcp.isObj is by default false
  1211. cg_printf("mcp%d.rootCls = %s%s::s_class_name.get();\n",
  1212. m_ciTemp,
  1213. Option::ClassPrefix, m_classScope->getId().c_str());
  1214. } else {
  1215. if (!objCall || m_arrayParams) {
  1216. cg.wrapExpressionBegin();
  1217. m_ciTemp = cg.createNewLocalId(shared_from_this());
  1218. cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
  1219. }
  1220. if (objCall && m_arrayParams) {
  1221. cg_printf("mcp%d.obj = %s;\n",
  1222. m_ciTemp, getThisString(false).c_str());
  1223. }
  1224. }
  1225. }
  1226. } else if (m_arrayParams && !m_funcScope->isUserFunction()) {
  1227. ret = true;
  1228. if (cg.inExpression()) {
  1229. cg.wrapExpressionBegin();
  1230. cg_printf("extern Variant %s%s(void*,CArrRef);\n",
  1231. Option::InvokePrefix, m_funcScope->getId().c_str());
  1232. }
  1233. }
  1234. return FunctionCall::preOutputCPP(cg, ar, state) || ret;
  1235. }
  1236. // Short circuit out if inExpression() returns false
  1237. if (!cg.inExpression()) return true;
  1238. cg.wrapExpressionBegin();
  1239. m_ciTemp = cg.createNewLocalId(shared_from_this());
  1240. bool needHash = true;
  1241. string escapedName(CodeGenerator::EscapeLabel(m_origName));
  1242. string escapedClass;
  1243. ClassScopePtr cls = m_classScope;
  1244. if (!m_className.empty()) {
  1245. if (!m_safe && !isPresent()) {
  1246. ClassScope::OutputVolatileCheck(
  1247. cg, ar, getScope(), m_origClassName, false);
  1248. cg_printf(";\n");
  1249. }
  1250. escapedClass = CodeGenerator::EscapeLabel(m_className);
  1251. }
  1252. cg_printf("const CallInfo *cit%d = NULL;\n", m_ciTemp);
  1253. if (!m_class && m_className.empty()) {
  1254. cg_printf("void *vt%d = NULL;\n", m_ciTemp);
  1255. } else {
  1256. cg_printf("MethodCallPackage mcp%d;\n", m_ciTemp);
  1257. }
  1258. bool safeCheck = false;
  1259. if (m_safe) {
  1260. if (!m_className.empty()) {
  1261. if (!isPresent()) {
  1262. cg_indentBegin("if (");
  1263. ClassScope::OutputVolatileCheck(cg, ar, getScope(),
  1264. m_origClassName, true);
  1265. safeCheck = true;
  1266. }
  1267. } else if (!m_funcScope || m_funcScope->isVolatile()) {
  1268. cg_indentBegin("if (");
  1269. cg_printf("%s->FVF(%s)",
  1270. cg.getGlobals(ar),
  1271. CodeGenerator::FormatLabel(m_name).c_str());
  1272. safeCheck = true;
  1273. }
  1274. }
  1275. if (safeCheck) {
  1276. cg_printf(") {\n");
  1277. }
  1278. if (!m_class && m_className.empty()) {
  1279. if (m_redeclared && !m_dynamicInvoke) {
  1280. needHash = false;
  1281. cg_printf("cit%d = %s->GCI(%s);\n", m_ciTemp, cg.getGlobals(ar),
  1282. CodeGenerator::FormatLabel(m_name).c_str());
  1283. if (!safeCheck) {
  1284. // If m_safe, check cit later, if null then yield null or safeDef
  1285. cg_printf("if (!cit%d) invoke_failed(\"%s\", null_array, -1);\n",
  1286. m_ciTemp, escapedName.c_str());
  1287. }
  1288. } else {
  1289. cg_printf("get_call_info_or_fail(cit%d, vt%d, ", m_ciTemp, m_ciTemp);
  1290. cg_printString(m_name, ar, shared_from_this());
  1291. cg_printf(");\n");
  1292. needHash = false;
  1293. }
  1294. } else {
  1295. if (safeCheck) {
  1296. cg_printf("mcp%d.noFatal();\n", m_ciTemp);
  1297. }
  1298. ClassScopePtr cscope = getOriginalClass();
  1299. // The call was like parent::
  1300. string className;
  1301. if (m_classScope) {
  1302. if (isRedeclared()) {
  1303. className = CodeGenerator::FormatLabel(m_className);
  1304. } else {
  1305. className = m_classScope->getId();
  1306. }
  1307. } else {
  1308. className = CodeGenerator::FormatLabel(m_className);
  1309. if (!m_className.empty() && m_cppTemp.empty() &&
  1310. !isSelf() && !isParent() && !isStatic()) {
  1311. // Create a temporary to hold the class name, in case it is not a
  1312. // Static