PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/ext/ext_function.cpp

https://bitbucket.org/gnanakeethan/hiphop-php
C++ | 441 lines | 350 code | 60 blank | 31 comment | 75 complexity | 804ad19c7fa427e30909bbc8c3289bb5 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
  6. | Copyright (c) 1997-2010 The PHP Group |
  7. +----------------------------------------------------------------------+
  8. | This source file is subject to version 3.01 of the PHP license, |
  9. | that is bundled with this package in the file LICENSE, and is |
  10. | available through the world-wide-web at the following url: |
  11. | http://www.php.net/license/3_01.txt |
  12. | If you did not receive a copy of the PHP license and are unable to |
  13. | obtain it through the world-wide-web, please send a note to |
  14. | license@php.net so we can mail you a copy immediately. |
  15. +----------------------------------------------------------------------+
  16. */
  17. #include "hphp/runtime/ext/ext_function.h"
  18. #include "hphp/runtime/ext/ext_json.h"
  19. #include "hphp/runtime/ext/ext_class.h"
  20. #include "hphp/runtime/ext/ext_closure.h"
  21. #include "hphp/runtime/base/class_info.h"
  22. #include "hphp/runtime/base/util/libevent_http_client.h"
  23. #include "hphp/runtime/base/server/http_protocol.h"
  24. #include "hphp/runtime/vm/runtime.h"
  25. #include "hphp/runtime/vm/translator/translator.h"
  26. #include "hphp/runtime/vm/translator/translator-inline.h"
  27. #include "hphp/util/exception.h"
  28. #include "hphp/util/util.h"
  29. namespace HPHP {
  30. ///////////////////////////////////////////////////////////////////////////////
  31. using HPHP::Transl::CallerFrame;
  32. using HPHP::Transl::EagerCallerFrame;
  33. static const StaticString s_internal("internal");
  34. static const StaticString s_user("user");
  35. Array f_get_defined_functions() {
  36. return CREATE_MAP2(s_internal, ClassInfo::GetSystemFunctions(),
  37. s_user, ClassInfo::GetUserFunctions());
  38. }
  39. bool f_function_exists(CStrRef function_name, bool autoload /* = true */) {
  40. return
  41. function_exists(function_name) ||
  42. (autoload &&
  43. AutoloadHandler::s_instance->autoloadFunc(function_name.get()) &&
  44. function_exists(function_name));
  45. }
  46. static const StaticString
  47. s__invoke("__invoke"),
  48. s_Closure__invoke("Closure::__invoke");
  49. bool f_is_callable(CVarRef v, bool syntax /* = false */,
  50. VRefParam name /* = null */) {
  51. bool ret = true;
  52. if (LIKELY(!syntax)) {
  53. CallerFrame cf;
  54. ObjectData* obj = NULL;
  55. HPHP::Class* cls = NULL;
  56. StringData* invName = NULL;
  57. const HPHP::Func* f = vm_decode_function(v, cf(), false, obj, cls,
  58. invName, false);
  59. if (f == NULL) {
  60. ret = false;
  61. }
  62. if (invName != NULL) {
  63. decRefStr(invName);
  64. }
  65. if (!name.isReferenced()) return ret;
  66. }
  67. Variant::TypedValueAccessor tv_func = v.getTypedAccessor();
  68. if (Variant::IsString(tv_func)) {
  69. if (name.isReferenced()) name = Variant::GetStringData(tv_func);
  70. return ret;
  71. }
  72. if (Variant::GetAccessorType(tv_func) == KindOfArray) {
  73. CArrRef arr = Variant::GetAsArray(tv_func);
  74. CVarRef clsname = arr.rvalAtRef(int64_t(0));
  75. CVarRef mthname = arr.rvalAtRef(int64_t(1));
  76. if (arr.size() != 2 ||
  77. &clsname == &null_variant ||
  78. &mthname == &null_variant) {
  79. name = v.toString();
  80. return false;
  81. }
  82. Variant::TypedValueAccessor tv_meth = mthname.getTypedAccessor();
  83. if (!Variant::IsString(tv_meth)) {
  84. if (name.isReferenced()) name = v.toString();
  85. return false;
  86. }
  87. Variant::TypedValueAccessor tv_cls = clsname.getTypedAccessor();
  88. if (Variant::GetAccessorType(tv_cls) == KindOfObject) {
  89. name = Variant::GetObjectData(tv_cls)->o_getClassName();
  90. } else if (Variant::IsString(tv_cls)) {
  91. name = Variant::GetStringData(tv_cls);
  92. } else {
  93. name = v.toString();
  94. return false;
  95. }
  96. name = concat3(name, "::", Variant::GetAsString(tv_meth));
  97. return ret;
  98. }
  99. if (Variant::GetAccessorType(tv_func) == KindOfObject) {
  100. ObjectData *d = Variant::GetObjectData(tv_func);
  101. const Func* invoke = d->getVMClass()->lookupMethod(s__invoke.get());
  102. if (name.isReferenced()) {
  103. if (d->instanceof(c_Closure::s_cls)) {
  104. // Hack to stop the mangled name from showing up
  105. name = s_Closure__invoke;
  106. } else {
  107. name = d->o_getClassName() + "::__invoke";
  108. }
  109. }
  110. return invoke != NULL;
  111. }
  112. return false;
  113. }
  114. Variant f_call_user_func(int _argc, CVarRef function,
  115. CArrRef _argv /* = null_array */) {
  116. return vm_call_user_func(function, _argv);
  117. }
  118. Variant f_call_user_func_array(CVarRef function, CArrRef params) {
  119. return vm_call_user_func(function, params);
  120. }
  121. Object f_call_user_func_array_async(CVarRef function, CArrRef params) {
  122. raise_error("%s is no longer supported", __func__);
  123. return null_object;
  124. }
  125. Object f_call_user_func_async(int _argc, CVarRef function,
  126. CArrRef _argv /* = null_array */) {
  127. raise_error("%s is no longer supported", __func__);
  128. return null_object;
  129. }
  130. Variant f_check_user_func_async(CVarRef handles, int timeout /* = -1 */) {
  131. raise_error("%s is no longer supported", __func__);
  132. return uninit_null();
  133. }
  134. Variant f_end_user_func_async(CObjRef handle,
  135. int default_strategy /* = k_GLOBAL_STATE_IGNORE */,
  136. CVarRef additional_strategies /* = null */) {
  137. raise_error("%s is no longer supported", __func__);
  138. return uninit_null();
  139. }
  140. static const StaticString
  141. s_func("func"),
  142. s_args("args"),
  143. s_exception("exception"),
  144. s_ret("ret");
  145. String f_call_user_func_serialized(CStrRef input) {
  146. Variant out;
  147. try {
  148. Variant in = unserialize_from_string(input);
  149. out.set(s_ret, vm_call_user_func(in[s_func], in[s_args]));
  150. } catch (Object &e) {
  151. out.set(s_exception, e);
  152. }
  153. return f_serialize(out);
  154. }
  155. Variant f_call_user_func_array_rpc(CStrRef host, int port, CStrRef auth,
  156. int timeout, CVarRef function,
  157. CArrRef params) {
  158. return f_call_user_func_rpc(0, host, port, auth, timeout, function, params);
  159. }
  160. Variant f_call_user_func_rpc(int _argc, CStrRef host, int port, CStrRef auth,
  161. int timeout, CVarRef function,
  162. CArrRef _argv /* = null_array */) {
  163. string shost = host.data();
  164. if (!RuntimeOption::DebuggerRpcHostDomain.empty()) {
  165. unsigned int pos = shost.find(RuntimeOption::DebuggerRpcHostDomain);
  166. if (pos != shost.length() - RuntimeOption::DebuggerRpcHostDomain.size()) {
  167. shost += RuntimeOption::DebuggerRpcHostDomain;
  168. }
  169. }
  170. string url = "http://";
  171. url += shost;
  172. url += ":";
  173. url += lexical_cast<string>(port);
  174. url += "/call_user_func_serialized?auth=";
  175. url += auth.data();
  176. Array blob = CREATE_MAP2(s_func, function, s_args, _argv);
  177. String message = f_serialize(blob);
  178. vector<string> headers;
  179. LibEventHttpClientPtr http = LibEventHttpClient::Get(shost, port);
  180. if (!http->send(url, headers, timeout < 0 ? 0 : timeout, false,
  181. message.data(), message.size())) {
  182. raise_error("Unable to send RPC request");
  183. return false;
  184. }
  185. int code = http->getCode();
  186. if (code <= 0) {
  187. raise_error("Server timed out or unable to find specified URL: %s",
  188. url.c_str());
  189. return false;
  190. }
  191. int len = 0;
  192. char *response = http->recv(len);
  193. String sresponse(response, len, AttachString);
  194. if (code != 200) {
  195. raise_error("Internal server error: %d %s", code,
  196. HttpProtocol::GetReasonString(code));
  197. return false;
  198. }
  199. // This double decoding can be avoided by modifying RPC server to directly
  200. // take PHP serialization format.
  201. Variant res = unserialize_from_string(f_json_decode(sresponse));
  202. if (!res.isArray()) {
  203. raise_error("Internal protocol error");
  204. return false;
  205. }
  206. if (res.toArray().exists(s_exception)) {
  207. throw res[s_exception];
  208. }
  209. return res[s_ret];
  210. }
  211. Variant f_forward_static_call_array(CVarRef function, CArrRef params) {
  212. return f_forward_static_call(0, function, params);
  213. }
  214. Variant f_forward_static_call(int _argc, CVarRef function,
  215. CArrRef _argv /* = null_array */) {
  216. // Setting the bound parameter to true tells vm_call_user_func()
  217. // propogate the current late bound class
  218. return vm_call_user_func(function, _argv, true);
  219. }
  220. Variant f_get_called_class() {
  221. EagerCallerFrame cf;
  222. ActRec* ar = cf();
  223. if (ar == NULL) {
  224. return Variant(false);
  225. }
  226. if (ar->hasThis()) {
  227. ObjectData* obj = ar->getThis();
  228. return obj->o_getClassName();
  229. } else if (ar->hasClass()) {
  230. return ar->getClass()->preClass()->name()->data();
  231. } else {
  232. return Variant(false);
  233. }
  234. }
  235. String f_create_function(CStrRef args, CStrRef code) {
  236. return g_vmContext->createFunction(args, code);
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////
  239. Variant f_func_get_arg(int arg_num) {
  240. CallerFrame cf;
  241. ActRec* ar = cf.actRecForArgs();
  242. if (ar == NULL) {
  243. return false;
  244. }
  245. if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
  246. raise_warning(
  247. "func_get_arg(): Called from the global scope - no function context"
  248. );
  249. return false;
  250. }
  251. if (arg_num < 0) {
  252. raise_warning(
  253. "func_get_arg(): The argument number should be >= 0"
  254. );
  255. return false;
  256. }
  257. if (arg_num >= ar->numArgs()) {
  258. raise_warning(
  259. "func_get_arg(): Argument %d not passed to function", arg_num
  260. );
  261. return false;
  262. }
  263. const int numParams = ar->m_func->numParams();
  264. if (arg_num < numParams) {
  265. // Formal parameter. Value is on the stack.
  266. TypedValue* loc =
  267. (TypedValue*)(uintptr_t(ar) - (arg_num + 1) * sizeof(TypedValue));
  268. return tvAsVariant(loc);
  269. }
  270. const int numArgs = ar->numArgs();
  271. const int extraArgs = numArgs - numParams;
  272. // Not a formal parameter. Value is potentially in the
  273. // ExtraArgs/VarEnv.
  274. const int extraArgNum = arg_num - numParams;
  275. if (extraArgNum < extraArgs) {
  276. return tvAsVariant(ar->getExtraArg(extraArgNum));
  277. }
  278. return false;
  279. }
  280. Variant func_get_arg(int num_args, CArrRef params, CArrRef args, int pos) {
  281. if (num_args <= params.size()) {
  282. if (pos >= 0 && pos < num_args) {
  283. return params.rvalAt(pos);
  284. }
  285. } else {
  286. if (pos >= 0) {
  287. int index = pos - params.size();
  288. if (index < 0) {
  289. return params.rvalAt(pos);
  290. }
  291. if (index < args.size()) {
  292. return args.rvalAt(index);
  293. }
  294. }
  295. }
  296. return false;
  297. }
  298. Array hhvm_get_frame_args(const ActRec* ar) {
  299. if (ar == NULL) {
  300. return Array();
  301. }
  302. int numParams = ar->m_func->numParams();
  303. int numArgs = ar->numArgs();
  304. auto retval = ArrayData::Make(numArgs);
  305. TypedValue* local = (TypedValue*)(uintptr_t(ar) - sizeof(TypedValue));
  306. for (int i = 0; i < numArgs; ++i) {
  307. if (i < numParams) {
  308. // This corresponds to one of the function's formal parameters, so it's
  309. // on the stack.
  310. retval->nvAppend(local);
  311. --local;
  312. } else {
  313. // This is not a formal parameter, so it's in the ExtraArgs.
  314. retval->nvAppend(ar->getExtraArg(i - numParams));
  315. }
  316. }
  317. return Array(retval);
  318. }
  319. Variant f_func_get_args() {
  320. EagerCallerFrame cf;
  321. ActRec* ar = cf.actRecForArgs();
  322. if (ar && ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
  323. raise_warning(
  324. "func_get_args(): Called from the global scope - no function context"
  325. );
  326. return false;
  327. }
  328. return hhvm_get_frame_args(ar);
  329. }
  330. Array func_get_args(int num_args, CArrRef params, CArrRef args) {
  331. if (params.empty() && args.empty()) return Array::Create();
  332. if (args.empty()) {
  333. if (num_args < params.size()) {
  334. return params.slice(0, num_args, false);
  335. }
  336. return params;
  337. }
  338. Array derefArgs;
  339. for (ArrayIter iter(args); iter; ++iter) {
  340. derefArgs.append(iter.second());
  341. }
  342. if (params.empty()) return derefArgs;
  343. assert(num_args > params.size());
  344. Array ret = Array(params).merge(derefArgs);
  345. return ret;
  346. }
  347. int64_t f_func_num_args() {
  348. EagerCallerFrame cf;
  349. ActRec* ar = cf.actRecForArgs();
  350. if (ar == NULL) {
  351. return -1;
  352. }
  353. if (ar->hasVarEnv() && ar->getVarEnv()->isGlobalScope()) {
  354. raise_warning(
  355. "func_num_args(): Called from the global scope - no function context"
  356. );
  357. return -1;
  358. }
  359. return ar->numArgs();
  360. }
  361. ///////////////////////////////////////////////////////////////////////////////
  362. void f_register_postsend_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  363. g_context->registerShutdownFunction(function, _argv,
  364. ExecutionContext::PostSend);
  365. }
  366. void f_register_shutdown_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  367. g_context->registerShutdownFunction(function, _argv,
  368. ExecutionContext::ShutDown);
  369. }
  370. void f_register_cleanup_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  371. g_context->registerShutdownFunction(function, _argv,
  372. ExecutionContext::CleanUp);
  373. }
  374. bool f_register_tick_function(int _argc, CVarRef function, CArrRef _argv /* = null_array */) {
  375. throw NotImplementedException(__func__);
  376. }
  377. void f_unregister_tick_function(CVarRef function_name) {
  378. throw NotImplementedException(__func__);
  379. }
  380. ///////////////////////////////////////////////////////////////////////////////
  381. }