diff --git a/bin/systemlib.php b/bin/systemlib.php index 76658a543..5520cfc68 100644 --- a/bin/systemlib.php +++ b/bin/systemlib.php @@ -2217,6 +2217,10 @@ class SplFileObject extends SplFileInfo implements RecursiveIterator, } } +interface Awaitable { + public function getWaitHandle(); +} + interface DebuggerCommand { /** * Called when DebuggerClient needs to auto-complete. Inside this function, diff --git a/hphp/idl/asio.idl.php b/hphp/idl/asio.idl.php index 20385076a..eea9a0fc4 100644 --- a/hphp/idl/asio.idl.php +++ b/hphp/idl/asio.idl.php @@ -187,6 +187,7 @@ BeginClass( 'name' => "WaitHandle", 'desc' => "A wait handle representing asynchronous operation", 'flags' => HasDocComment | IsAbstract | IsCppAbstract, + 'ifaces' => array('Awaitable'), )); DefineFunction( @@ -198,6 +199,16 @@ DefineFunction( ), )); +DefineFunction( + array( + 'name' => "getWaitHandle", + 'desc' => "Return this wait handle (for Awaitable interface)", + 'flags' => HasDocComment, + 'return' => array( + 'type' => Object, + ), + )); + DefineFunction( array( 'name' => "import", diff --git a/hphp/idl/continuation.idl.php b/hphp/idl/continuation.idl.php index 117fd2be4..1f3b22518 100644 --- a/hphp/idl/continuation.idl.php +++ b/hphp/idl/continuation.idl.php @@ -153,7 +153,7 @@ BeginClass( array( 'name' => 'Continuation', 'flags' => IsFinal, - 'ifaces' => array('Iterator'), + 'ifaces' => array('Iterator', 'Awaitable'), 'footer' => << "getWaitHandle", + 'desc' => "Start asynchronous execution of this Continuation and return the wait handle", + 'flags' => HasDocComment, + 'return' => array( + 'type' => Object, + ), + )); + DefineFunction( array( 'name' => 'getLabel', diff --git a/hphp/runtime/ext/asio/wait_handle.cpp b/hphp/runtime/ext/asio/wait_handle.cpp index 373e93d2f..59ff5325b 100644 --- a/hphp/runtime/ext/asio/wait_handle.cpp +++ b/hphp/runtime/ext/asio/wait_handle.cpp @@ -32,6 +32,10 @@ void c_WaitHandle::t___construct() { throw NotSupportedException(__func__, "WTF? This is an abstract class"); } +Object c_WaitHandle::t_getwaithandle() { + return this; +} + // throws if cross-context cycle found void c_WaitHandle::t_import() { if (isFinished()) { diff --git a/hphp/runtime/ext/asio/wait_handle.ext_hhvm.cpp b/hphp/runtime/ext/asio/wait_handle.ext_hhvm.cpp index d6a282816..86572cb72 100644 --- a/hphp/runtime/ext/asio/wait_handle.ext_hhvm.cpp +++ b/hphp/runtime/ext/asio/wait_handle.ext_hhvm.cpp @@ -61,6 +61,44 @@ TypedValue* tg_10WaitHandle___construct(HPHP::VM::ActRec *ar) { return &ar->m_r; } +/* +HPHP::Object HPHP::c_WaitHandle::t_getwaithandle() +_ZN4HPHP12c_WaitHandle15t_getwaithandleEv + +(return value) => rax +_rv => rdi +this_ => rsi +*/ + +Value* th_10WaitHandle_getWaitHandle(Value* _rv, ObjectData* this_) asm("_ZN4HPHP12c_WaitHandle15t_getwaithandleEv"); + +TypedValue* tg_10WaitHandle_getWaitHandle(HPHP::VM::ActRec *ar) { + TypedValue rv; + int64_t count = ar->numArgs(); + TypedValue* args UNUSED = ((TypedValue*)ar) - 1; + ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL); + if (this_) { + if (count == 0LL) { + rv.m_type = KindOfObject; + th_10WaitHandle_getWaitHandle((Value*)(&(rv)), (this_)); + if (rv.m_data.num == 0LL) rv.m_type = KindOfNull; + frame_free_locals_inl(ar, 0); + memcpy(&ar->m_r, &rv, sizeof(TypedValue)); + return &ar->m_r; + } else { + throw_toomany_arguments_nr("WaitHandle::getWaitHandle", 0, 1); + } + } else { + throw_instance_method_fatal("WaitHandle::getWaitHandle"); + } + rv.m_data.num = 0LL; + rv.m_type = KindOfNull; + frame_free_locals_inl(ar, 0); + memcpy(&ar->m_r, &rv, sizeof(TypedValue)); + return &ar->m_r; + return &ar->m_r; +} + /* void HPHP::c_WaitHandle::t_import() _ZN4HPHP12c_WaitHandle8t_importEv diff --git a/hphp/runtime/ext/ext_asio.h b/hphp/runtime/ext/ext_asio.h index 37617ecd7..30635eda0 100644 --- a/hphp/runtime/ext/ext_asio.h +++ b/hphp/runtime/ext/ext_asio.h @@ -65,6 +65,7 @@ class c_WaitHandle : public ExtObjectData { public: c_WaitHandle(VM::Class* cls = c_WaitHandle::s_cls); public: ~c_WaitHandle(); public: void t___construct(); + public: Object t_getwaithandle(); public: void t_import(); public: Variant t_join(); public: bool t_isfinished(); diff --git a/hphp/runtime/ext/ext_continuation.cpp b/hphp/runtime/ext/ext_continuation.cpp index c07a9d9fa..492648515 100644 --- a/hphp/runtime/ext/ext_continuation.cpp +++ b/hphp/runtime/ext/ext_continuation.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -104,6 +105,10 @@ void c_Continuation::t_done() { m_value.setNull(); } +Object c_Continuation::t_getwaithandle() { + return m_waitHandle.isNull() ? c_ContinuationWaitHandle::t_start(this) : m_waitHandle; +} + int64_t c_Continuation::t_getlabel() { return m_label; } diff --git a/hphp/runtime/ext/ext_continuation.ext_hhvm.cpp b/hphp/runtime/ext/ext_continuation.ext_hhvm.cpp index fe3956841..28e111258 100644 --- a/hphp/runtime/ext/ext_continuation.ext_hhvm.cpp +++ b/hphp/runtime/ext/ext_continuation.ext_hhvm.cpp @@ -384,6 +384,44 @@ TypedValue* tg_12Continuation_done(HPHP::VM::ActRec *ar) { return &ar->m_r; } +/* +HPHP::Object HPHP::c_Continuation::t_getwaithandle() +_ZN4HPHP14c_Continuation15t_getwaithandleEv + +(return value) => rax +_rv => rdi +this_ => rsi +*/ + +Value* th_12Continuation_getWaitHandle(Value* _rv, ObjectData* this_) asm("_ZN4HPHP14c_Continuation15t_getwaithandleEv"); + +TypedValue* tg_12Continuation_getWaitHandle(HPHP::VM::ActRec *ar) { + TypedValue rv; + int64_t count = ar->numArgs(); + TypedValue* args UNUSED = ((TypedValue*)ar) - 1; + ObjectData* this_ = (ar->hasThis() ? ar->getThis() : NULL); + if (this_) { + if (count == 0LL) { + rv.m_type = KindOfObject; + th_12Continuation_getWaitHandle((Value*)(&(rv)), (this_)); + if (rv.m_data.num == 0LL) rv.m_type = KindOfNull; + frame_free_locals_inl(ar, 0); + memcpy(&ar->m_r, &rv, sizeof(TypedValue)); + return &ar->m_r; + } else { + throw_toomany_arguments_nr("Continuation::getWaitHandle", 0, 1); + } + } else { + throw_instance_method_fatal("Continuation::getWaitHandle"); + } + rv.m_data.num = 0LL; + rv.m_type = KindOfNull; + frame_free_locals_inl(ar, 0); + memcpy(&ar->m_r, &rv, sizeof(TypedValue)); + return &ar->m_r; + return &ar->m_r; +} + /* long HPHP::c_Continuation::t_getlabel() _ZN4HPHP14c_Continuation10t_getlabelEv diff --git a/hphp/runtime/ext/ext_continuation.h b/hphp/runtime/ext/ext_continuation.h index 994c126c1..ce4992669 100644 --- a/hphp/runtime/ext/ext_continuation.h +++ b/hphp/runtime/ext/ext_continuation.h @@ -50,6 +50,7 @@ class c_Continuation : public ExtObjectData { public: void t___construct(int64_t func, int64_t extra, bool isMethod, CStrRef origFuncName, CVarRef obj = uninit_null(), CArrRef args = null_array); public: void t_update(int64_t label, CVarRef value); public: void t_done(); + public: Object t_getwaithandle(); public: int64_t t_getlabel(); public: int64_t t_num_args(); public: Array t_get_args(); diff --git a/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp b/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp index b6b3ea2a8..dc0bb3f44 100644 --- a/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp +++ b/hphp/runtime/ext_hhvm/ext_hhvm_infotabs.cpp @@ -2232,6 +2232,7 @@ TypedValue* fg_lz4compress(VM::ActRec *ar); TypedValue* fg_lz4hccompress(VM::ActRec *ar); TypedValue* fg_lz4uncompress(VM::ActRec *ar); TypedValue* tg_10WaitHandle___construct(VM::ActRec *ar); +TypedValue* tg_10WaitHandle_getWaitHandle(VM::ActRec *ar); TypedValue* tg_10WaitHandle_import(VM::ActRec *ar); TypedValue* tg_10WaitHandle_join(VM::ActRec *ar); TypedValue* tg_10WaitHandle_isFinished(VM::ActRec *ar); @@ -2402,6 +2403,7 @@ VM::Instance* new_Continuation_Instance(VM::Class*); TypedValue* tg_12Continuation___construct(VM::ActRec *ar); TypedValue* tg_12Continuation_update(VM::ActRec *ar); TypedValue* tg_12Continuation_done(VM::ActRec *ar); +TypedValue* tg_12Continuation_getWaitHandle(VM::ActRec *ar); TypedValue* tg_12Continuation_getLabel(VM::ActRec *ar); TypedValue* tg_12Continuation_num_args(VM::ActRec *ar); TypedValue* tg_12Continuation_get_args(VM::ActRec *ar); @@ -5232,9 +5234,10 @@ const HhbcExtFuncInfo hhbc_ext_funcs[] = { { "lz4uncompress", fg_lz4uncompress, (void *)&fh_lz4uncompress } }; -static const long long hhbc_ext_method_count_WaitHandle = 9; +static const long long hhbc_ext_method_count_WaitHandle = 10; static const HhbcExtMethodInfo hhbc_ext_methods_WaitHandle[] = { { "__construct", tg_10WaitHandle___construct }, + { "getWaitHandle", tg_10WaitHandle_getWaitHandle }, { "import", tg_10WaitHandle_import }, { "join", tg_10WaitHandle_join }, { "isFinished", tg_10WaitHandle_isFinished }, @@ -5463,11 +5466,12 @@ static const HhbcExtMethodInfo hhbc_ext_methods_TupleIterator[] = { { "rewind", tg_13TupleIterator_rewind } }; -static const long long hhbc_ext_method_count_Continuation = 18; +static const long long hhbc_ext_method_count_Continuation = 19; static const HhbcExtMethodInfo hhbc_ext_methods_Continuation[] = { { "__construct", tg_12Continuation___construct }, { "update", tg_12Continuation_update }, { "done", tg_12Continuation_done }, + { "getWaitHandle", tg_12Continuation_getWaitHandle }, { "getLabel", tg_12Continuation_getLabel }, { "num_args", tg_12Continuation_num_args }, { "get_args", tg_12Continuation_get_args }, diff --git a/hphp/system/asio.inc b/hphp/system/asio.inc index 525cdca3d..4cdcd7588 100644 --- a/hphp/system/asio.inc +++ b/hphp/system/asio.inc @@ -12,7 +12,7 @@ #elif EXT_TYPE == 1 #elif EXT_TYPE == 2 -"WaitHandle", "", NULL, "__construct", T(Void), S(0), NULL, S(16640), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.construct.php )\n *\n *\n */", S(16640),"import", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.import.php )\n *\n * Import this wait handle to the current scheduler context\n *\n */", S(16384),"join", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.join.php )\n *\n * Wait until this wait handle is finished and return its result (operates\n * in a new scheduler context)\n *\n * @return mixed A result of the operation represented by given wait\n * handle\n */", S(16384),"isFinished", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.isfinished.php )\n *\n * Check if this wait handle finished (succeeded or failed)\n *\n * @return bool A boolean indicating whether this wait handle\n * finished\n */", S(16384),"isSucceeded", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.issucceeded.php )\n *\n * Check if this wait handle succeeded\n *\n * @return bool A boolean indicating whether this wait handle\n * succeeded\n */", S(16384),"isFailed", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.isfailed.php )\n *\n * Check if this wait handle failed\n *\n * @return bool A boolean indicating whether this wait handle failed\n */", S(16384),"getID", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getid.php )\n *\n * Get unique ID of this wait handle (amongst existing ones)\n *\n * @return int An integer representing unique ID of this wait\n * handle\n */", S(16384),"getName", T(String), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getname.php )\n *\n * Get name of the operation behind this wait handle\n *\n * @return string A name of the operation behind this wait handle\n */", S(16384),"getExceptionIfFailed", T(Object), S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/waithandle.getexceptioniffailed.php )\n *\n * Get exception if this wait handle has failed, or null\n *\n * @return object An exception if this wait handle has failed, or null\n */", S(16384),NULL,NULL,NULL, +"WaitHandle", "", "awaitable",NULL, "__construct", T(Void), S(0), NULL, S(16640), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.construct.php )\n *\n *\n */", S(16640),"import", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.import.php )\n *\n * Import this wait handle to the current scheduler context\n *\n */", S(16384),"getWaitHandle", T(Object), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getwaithandle.php )\n *\n * Start this wait handle to the current scheduler context\n *\n * @return object\n */", S(16384),"join", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.join.php )\n *\n * Wait until this wait handle is finished and return its result (operates\n * in a new scheduler context)\n *\n * @return mixed A result of the operation represented by given wait\n * handle\n */", S(16384),"isFinished", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.isfinished.php )\n *\n * Check if this wait handle finished (succeeded or failed)\n *\n * @return bool A boolean indicating whether this wait handle\n * finished\n */", S(16384),"isSucceeded", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.issucceeded.php )\n *\n * Check if this wait handle succeeded\n *\n * @return bool A boolean indicating whether this wait handle\n * succeeded\n */", S(16384),"isFailed", T(Boolean), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.isfailed.php )\n *\n * Check if this wait handle failed\n *\n * @return bool A boolean indicating whether this wait handle failed\n */", S(16384),"getID", T(Int64), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getid.php )\n *\n * Get unique ID of this wait handle (amongst existing ones)\n *\n * @return int An integer representing unique ID of this wait\n * handle\n */", S(16384),"getName", T(String), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getname.php )\n *\n * Get name of the operation behind this wait handle\n *\n * @return string A name of the operation behind this wait handle\n */", S(16384),"getExceptionIfFailed", T(Object), S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/waithandle.getexceptioniffailed.php )\n *\n * Get exception if this wait handle has failed, or null\n *\n * @return object An exception if this wait handle has failed, or null\n */", S(16384),NULL,NULL,NULL, S(17424), "/**\n * ( excerpt from http://php.net/manual/en/class.waithandle.php )\n *\n * A wait handle representing asynchronous operation\n *\n */", "StaticWaitHandle", "waithandle", NULL, "__construct", T(Void), S(0), NULL, S(16640), "/**\n * ( excerpt from http://php.net/manual/en/staticwaithandle.construct.php )\n *\n *\n */", S(16640),NULL,NULL,NULL, S(17424), "/**\n * ( excerpt from http://php.net/manual/en/class.staticwaithandle.php )\n *\n * A wait handle that is always finished\n *\n */", "StaticResultWaitHandle", "staticwaithandle", NULL, "__construct", T(Void), S(0), NULL, S(16640), "/**\n * ( excerpt from\n * http://php.net/manual/en/staticresultwaithandle.construct.php )\n *\n *\n */", S(16640),"create", T(Object), S(0), "result", T(Variant), NULL, S(0), NULL, S(0), NULL, S(16896), "/**\n * ( excerpt from\n * http://php.net/manual/en/staticresultwaithandle.create.php )\n *\n * Create a wait handle that always succeeds with a given result\n *\n * @result mixed A result wait handle will succeed with\n *\n * @return object A StaticResultWaitHandle representing given result\n */", S(16896),NULL,NULL,NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/class.staticresultwaithandle.php\n * )\n *\n * A wait handle representing static result\n *\n */", "StaticExceptionWaitHandle", "staticwaithandle", NULL, "__construct", T(Void), S(0), NULL, S(16640), "/**\n * ( excerpt from\n * http://php.net/manual/en/staticexceptionwaithandle.construct.php )\n *\n *\n */", S(16640),"create", T(Object), S(0), "exception", T(Object), NULL, S(0), NULL, S(0), NULL, S(16896), "/**\n * ( excerpt from\n * http://php.net/manual/en/staticexceptionwaithandle.create.php )\n *\n * Create a wait handle that always fails with a given exception\n *\n * @exception object An exception wait handle will fail with\n *\n * @return object A StaticExceptionWaitHandle representing given\n * exception\n */", S(16896),NULL,NULL,NULL, diff --git a/hphp/system/class_map.cpp b/hphp/system/class_map.cpp index c4c97b6d2..d62453bea 100644 --- a/hphp/system/class_map.cpp +++ b/hphp/system/class_map.cpp @@ -21925,7 +21925,7 @@ const char *g_class_map[] = { NULL, (const char *)0x10006020, "Continuation", "", "", (const char *)0, (const char *)0, "/**\n * ( excerpt from http://php.net/manual/en/class.continuation.php )\n *\n *\n */", - "iterator", NULL, + "iterator", "awaitable", NULL, (const char *)0x10006040, "__construct", "", (const char*)0, (const char*)0, "/**\n * ( excerpt from http://php.net/manual/en/continuation.construct.php )\n *\n *\n * @func int\n * @extra int\n * @isMethod bool\n * @origFuncName\n * string\n * @obj mixed\n * @args map\n */", (const char *)-1, (const char *)0x2000, "func", "", (const char *)0xa, "", "", NULL, @@ -21949,6 +21949,11 @@ const char *g_class_map[] = { (const char *)-1, NULL, NULL, NULL, + (const char *)0x10006040, "getWaitHandle", "", (const char*)0, (const char*)0, + "/**\n * ( excerpt from http://php.net/manual/en/continuation.getwaithandle.php )\n *\n * Start asynchronous execution of this Continuation and return the wait\n * handle\n *\n * @return object\n */", + (const char *)0x40, NULL, + NULL, + NULL, (const char *)0x10006040, "getLabel", "", (const char*)0, (const char*)0, "/**\n * ( excerpt from http://php.net/manual/en/continuation.getlabel.php )\n *\n *\n * @return int\n */", (const char *)0xa, NULL, @@ -22070,12 +22075,17 @@ const char *g_class_map[] = { NULL, (const char *)0x10006010, "WaitHandle", "", "", (const char *)0, (const char *)0, "/**\n * ( excerpt from http://php.net/manual/en/class.waithandle.php )\n *\n * A wait handle representing asynchronous operation\n *\n */", - NULL, + "awaitable", NULL, (const char *)0x10006100, "__construct", "", (const char*)0, (const char*)0, "/**\n * ( excerpt from http://php.net/manual/en/waithandle.construct.php )\n *\n *\n */", (const char *)-1, NULL, NULL, NULL, + (const char *)0x10006040, "getWaitHandle", "", (const char*)0, (const char*)0, + "/**\n * ( excerpt from http://php.net/manual/en/waithandle.getwaithandle.php )\n *\n * Return this wait handle (for Awaitable interface)\n *\n * @return object\n */", + (const char *)0x40, NULL, + NULL, + NULL, (const char *)0x10006040, "import", "", (const char*)0, (const char*)0, "/**\n * ( excerpt from http://php.net/manual/en/waithandle.import.php )\n *\n * Import this wait handle to the current scheduler context\n *\n */", (const char *)-1, NULL, diff --git a/hphp/system/classes/awaitable.php b/hphp/system/classes/awaitable.php new file mode 100644 index 000000000..cd79cd5ce --- /dev/null +++ b/hphp/system/classes/awaitable.php @@ -0,0 +1,5 @@ +