PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/runtime/ext/ext_continuation.cpp

https://github.com/github-ivan/hiphop-php
C++ | 317 lines | 255 code | 43 blank | 19 comment | 23 complexity | 69f53208562ec639398256b4238bc6a0 MD5 | raw file
  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 <runtime/ext/ext_continuation.h>
  18. #include <runtime/base/builtin_functions.h>
  19. #include <runtime/ext/ext_spl.h>
  20. #include <runtime/ext/ext_variable.h>
  21. #include <runtime/ext/ext_function.h>
  22. #include <runtime/eval/runtime/variable_environment.h>
  23. #include <system/lib/systemlib.h>
  24. namespace HPHP {
  25. ///////////////////////////////////////////////////////////////////////////////
  26. p_Continuation f_hphp_create_continuation(CStrRef clsname,
  27. CStrRef funcname,
  28. CStrRef origFuncName,
  29. CArrRef args /* = null_array */) {
  30. Eval::VariableEnvironment *env =
  31. FrameInjection::GetVariableEnvironment(true);
  32. if (UNLIKELY(!env)) {
  33. throw_fatal("Cannot call hphp_create_continuation in non-eval context");
  34. }
  35. bool isMethod = !clsname.isNull() && !clsname.empty();
  36. int64 callInfo = f_hphp_get_call_info(clsname, funcname);
  37. int64 extra = f_hphp_get_call_info_extra(clsname, funcname);
  38. CObjRef obj = FrameInjection::GetThis(true);
  39. p_GenericContinuation cont(
  40. ((c_GenericContinuation*)coo_GenericContinuation())->
  41. create(callInfo, extra, isMethod, origFuncName,
  42. env->getDefinedVariables(), obj, args));
  43. if (isMethod) {
  44. CStrRef cls = f_get_called_class();
  45. cont->setCalledClass(cls);
  46. }
  47. return cont;
  48. }
  49. void f_hphp_pack_continuation(CObjRef continuation,
  50. int64 label, CVarRef value) {
  51. Eval::VariableEnvironment *env =
  52. FrameInjection::GetVariableEnvironment(true);
  53. if (UNLIKELY(!env)) {
  54. throw_fatal("Cannot call hphp_pack_continuation in non-eval context");
  55. }
  56. if (UNLIKELY(!continuation->o_instanceof("GenericContinuation"))) {
  57. throw_fatal(
  58. "Cannot call hphp_pack_continuation with a "
  59. "non-GenericContinuation object");
  60. }
  61. p_GenericContinuation c(
  62. static_cast<c_GenericContinuation*>(continuation.get()));
  63. c->t_update(label, value, env->getDefinedVariables());
  64. }
  65. void f_hphp_unpack_continuation(CObjRef continuation) {
  66. Eval::VariableEnvironment *env =
  67. FrameInjection::GetVariableEnvironment(true);
  68. if (UNLIKELY(!env)) {
  69. throw_fatal("Cannot call hphp_unpack_continuation in non-eval context");
  70. }
  71. if (UNLIKELY(!continuation->o_instanceof("GenericContinuation"))) {
  72. throw_fatal(
  73. "Cannot call hphp_pack_continuation with a "
  74. "non-GenericContinuation object");
  75. }
  76. p_GenericContinuation c(
  77. static_cast<c_GenericContinuation*>(continuation.get()));
  78. extract(env, c->t_getvars(), 256 /* EXTR_REFS */);
  79. }
  80. ///////////////////////////////////////////////////////////////////////////////
  81. static StaticString s___cont__("__cont__");
  82. c_Continuation::c_Continuation(const ObjectStaticCallbacks *cb) :
  83. ExtObjectData(cb),
  84. m_label(0LL), m_index(-1LL),
  85. m_value(Variant::nullInit), m_received(Variant::nullInit),
  86. m_done(false), m_running(false), m_should_throw(false),
  87. m_isMethod(false), m_callInfo(NULL), m_extra(NULL) {}
  88. c_Continuation::~c_Continuation() {}
  89. void c_Continuation::t___construct(
  90. int64 func, int64 extra, bool isMethod,
  91. CStrRef origFuncName, CVarRef obj, CArrRef args) {
  92. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::__construct);
  93. m_callInfo = (const CallInfo*) func;
  94. m_extra = (void*) extra;
  95. m_isMethod = isMethod;
  96. m_origFuncName = origFuncName;
  97. if (!obj.isNull()) {
  98. m_obj = obj.toObject();
  99. ASSERT(!m_obj.isNull());
  100. } else {
  101. ASSERT(m_obj.isNull());
  102. }
  103. m_args = args;
  104. ASSERT(m_callInfo);
  105. }
  106. void c_Continuation::t_update(int64 label, CVarRef value) {
  107. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::update);
  108. m_label = label;
  109. m_value.assignVal(value);
  110. }
  111. void c_Continuation::t_done() {
  112. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::done);
  113. m_done = true;
  114. }
  115. int64 c_Continuation::t_getlabel() {
  116. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::getlabel);
  117. return m_label;
  118. }
  119. int64 c_Continuation::t_num_args() {
  120. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::num_args);
  121. return m_args.size();
  122. }
  123. Array c_Continuation::t_get_args() {
  124. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::get_args);
  125. return m_args;
  126. }
  127. Variant c_Continuation::t_get_arg(int64 id) {
  128. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::get_arg);
  129. if (id < 0LL || id >= m_args.size()) return false;
  130. return m_args.rvalAt(id, AccessFlags::Error);
  131. }
  132. Variant c_Continuation::t_current() {
  133. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::current);
  134. if (m_index < 0LL) {
  135. throw_exception(
  136. Object(SystemLib::AllocExceptionObject("Need to call next() first")));
  137. }
  138. return m_value;
  139. }
  140. int64 c_Continuation::t_key() {
  141. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::key);
  142. if (m_index < 0LL) {
  143. throw_exception(
  144. Object(SystemLib::AllocExceptionObject("Need to call next() first")));
  145. }
  146. return m_index;
  147. }
  148. bool c_Continuation::php_sleep(Variant &ret) {
  149. ret = false;
  150. return true;
  151. }
  152. #define NEXT_IMPL \
  153. if (m_done) { \
  154. throw_exception(Object(SystemLib::AllocExceptionObject( \
  155. "Continuation is already finished"))); \
  156. } \
  157. if (m_running) { \
  158. throw_exception(Object(SystemLib::AllocExceptionObject( \
  159. "Continuation is already running"))); \
  160. } \
  161. m_running = true; \
  162. ++m_index; \
  163. try { \
  164. if (m_isMethod) { \
  165. MethodCallPackage mcp; \
  166. mcp.isObj = true; \
  167. mcp.obj = mcp.rootObj = m_obj.get(); \
  168. mcp.extra = m_extra; \
  169. fi.setStaticClassName(m_called_class); \
  170. (m_callInfo->getMeth1Args())(mcp, 1, GET_THIS_TYPED(Continuation)); \
  171. } else { \
  172. (m_callInfo->getFunc1Args())(m_extra, 1, GET_THIS_TYPED(Continuation)); \
  173. } \
  174. } catch (Object e) { \
  175. if (e.instanceof("exception")) { \
  176. m_running = false; \
  177. m_done = true; \
  178. throw_exception(e); \
  179. } else { \
  180. throw; \
  181. } \
  182. } \
  183. m_running = false;
  184. void c_Continuation::t_next() {
  185. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::next);
  186. m_received.setNull();
  187. NEXT_IMPL;
  188. }
  189. void c_Continuation::t_rewind() {
  190. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::rewind);
  191. throw_exception(Object(SystemLib::AllocExceptionObject(
  192. "Cannot rewind on a Continuation object")));
  193. }
  194. bool c_Continuation::t_valid() {
  195. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::valid);
  196. return !m_done;
  197. }
  198. void c_Continuation::t_send(CVarRef v) {
  199. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::send);
  200. if (m_index < 0LL) {
  201. throw_exception(
  202. Object(SystemLib::AllocExceptionObject("Need to call next() first")));
  203. }
  204. m_received.assignVal(v);
  205. NEXT_IMPL;
  206. }
  207. void c_Continuation::t_raise(CVarRef v) {
  208. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::raise);
  209. if (m_index < 0LL) {
  210. throw_exception(
  211. Object(SystemLib::AllocExceptionObject("Need to call next() first")));
  212. }
  213. m_received.assignVal(v);
  214. m_should_throw = true;
  215. NEXT_IMPL;
  216. }
  217. void c_Continuation::t_raised() {
  218. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::raised);
  219. if (m_should_throw) {
  220. m_should_throw = false;
  221. throw_exception(m_received);
  222. }
  223. }
  224. Variant c_Continuation::t_receive() {
  225. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::receive);
  226. if (m_should_throw) {
  227. m_should_throw = false;
  228. throw_exception(m_received);
  229. }
  230. return m_received;
  231. }
  232. String c_Continuation::t_getorigfuncname() {
  233. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::getorigfuncname);
  234. return m_origFuncName;
  235. }
  236. Variant c_Continuation::t___clone() {
  237. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::__clone);
  238. throw_fatal(
  239. "Trying to clone an uncloneable object of class Continuation");
  240. return null;
  241. }
  242. Variant c_Continuation::t___destruct() {
  243. INSTANCE_METHOD_INJECTION_BUILTIN(Continuation, Continuation::__destruct);
  244. return null;
  245. }
  246. #undef NEXT_IMPL
  247. c_GenericContinuation::c_GenericContinuation(const ObjectStaticCallbacks *cb) :
  248. c_Continuation(cb) {}
  249. c_GenericContinuation::~c_GenericContinuation() {}
  250. void
  251. c_GenericContinuation::t___construct(int64 func, int64 extra, bool isMethod,
  252. CStrRef origFuncName, CArrRef vars,
  253. CVarRef obj, CArrRef args) {
  254. INSTANCE_METHOD_INJECTION_BUILTIN(GenericContinuation, GenericContinuation::__construct);
  255. c_Continuation::t___construct(func, extra, isMethod,
  256. origFuncName, obj, args);
  257. m_vars = vars;
  258. }
  259. void c_GenericContinuation::t_update(int64 label, CVarRef value, CArrRef vars) {
  260. INSTANCE_METHOD_INJECTION_BUILTIN(GenericContinuation, GenericContinuation::update);
  261. c_Continuation::t_update(label, value);
  262. m_vars = vars;
  263. m_vars.weakRemove(s___cont__, true);
  264. }
  265. Array c_GenericContinuation::t_getvars() {
  266. INSTANCE_METHOD_INJECTION_BUILTIN(GenericContinuation, GenericContinuation::getvars);
  267. return m_vars;
  268. }
  269. Variant c_GenericContinuation::t___destruct() {
  270. INSTANCE_METHOD_INJECTION_BUILTIN(GenericContinuation, GenericContinuation::__destruct);
  271. return null;
  272. }
  273. ///////////////////////////////////////////////////////////////////////////////
  274. }