PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/compiler/expression/simple_function_call.cpp

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