diff --git a/hphp/idl/continuation.idl.json b/hphp/idl/continuation.idl.json index 2d1cfd0b8..4c6cd85aa 100644 --- a/hphp/idl/continuation.idl.json +++ b/hphp/idl/continuation.idl.json @@ -215,6 +215,16 @@ "args": [ ] }, + { + "name": "getCalledClass", + "return": { + "type": "String" + }, + "flags": [ + ], + "args": [ + ] + }, { "name": "__clone", "return": { diff --git a/hphp/runtime/ext/asio/continuation_wait_handle.cpp b/hphp/runtime/ext/asio/continuation_wait_handle.cpp index 5f46f50d3..b426894c1 100644 --- a/hphp/runtime/ext/asio/continuation_wait_handle.cpp +++ b/hphp/runtime/ext/asio/continuation_wait_handle.cpp @@ -238,7 +238,13 @@ String c_ContinuationWaitHandle::getName() { case STATE_BLOCKED: case STATE_SCHEDULED: case STATE_RUNNING: - return m_continuation->t_getorigfuncname(); + if (m_continuation->t_getcalledclass().empty()) { + return m_continuation->t_getorigfuncname(); + } else { + return concat3(m_continuation->t_getcalledclass(), + "::", + m_continuation->t_getorigfuncname()); + } default: throw FatalErrorException( diff --git a/hphp/runtime/ext/ext_continuation.cpp b/hphp/runtime/ext/ext_continuation.cpp index 05dd51684..d29f8c469 100644 --- a/hphp/runtime/ext/ext_continuation.cpp +++ b/hphp/runtime/ext/ext_continuation.cpp @@ -146,28 +146,21 @@ void c_Continuation::t_raised() { } String c_Continuation::t_getorigfuncname() { + return String(const_cast(m_origFuncName)); +} + +String c_Continuation::t_getcalledclass() { String called_class; - String origFunc(const_cast(m_origFuncName)); if (actRec()->hasThis()) { called_class = actRec()->getThis()->getVMClass()->name()->data(); } else if (actRec()->hasClass()) { called_class = actRec()->getClass()->name()->data(); - } - if (called_class.size() == 0) { - return origFunc; + } else { + called_class = empty_string; } - /* - Replace the class name in m_origFuncName with the LSB class. This - produces more useful traces. - */ - size_t method_pos = origFunc.find("::"); - if (method_pos != std::string::npos) { - return concat3(called_class, "::", origFunc.substr(method_pos+2)); - } else { - return origFunc; - } + return called_class; } Variant c_Continuation::t___clone() { diff --git a/hphp/runtime/ext/ext_continuation.h b/hphp/runtime/ext/ext_continuation.h index a112a8880..a7b81fb6b 100644 --- a/hphp/runtime/ext/ext_continuation.h +++ b/hphp/runtime/ext/ext_continuation.h @@ -80,6 +80,7 @@ public: void t_raise(CVarRef v); void t_raised(); String t_getorigfuncname(); + String t_getcalledclass(); Variant t___clone(); static c_Continuation* alloc(VM::Class* cls, int nLocals, int nIters) { diff --git a/hphp/runtime/vm/bytecode.cpp b/hphp/runtime/vm/bytecode.cpp index 71a075a45..717d5a5fa 100644 --- a/hphp/runtime/vm/bytecode.cpp +++ b/hphp/runtime/vm/bytecode.cpp @@ -2396,8 +2396,8 @@ Array VMExecutionContext::debugBacktrace(bool skip /* = false */, auto const curOp = *reinterpret_cast(curUnit->at(pc)); auto const isReturning = curOp == OpRetC || curOp == OpRetV; - // Builtins don't have a file and line number - if (prevFp && !prevFp->m_func->isBuiltin()) { + // Builtins and generators don't have a file and line number + if (prevFp && !prevFp->m_func->isBuiltin() && !fp->m_func->isGenerator()) { auto const prevUnit = prevFp->m_func->unit(); frame.set(s_file, const_cast(prevUnit->filepath()), @@ -6749,7 +6749,7 @@ VMExecutionContext::createContinuationHelper(const Func* origFunc, static auto const closureName = StringData::GetStaticString("{closure}"); auto const origName = origFunc->isClosureBody() ? closureName - : origFunc->fullName(); + : origFunc->name(); cont->init(genFunc, origName, thisPtr, args); @@ -6873,11 +6873,15 @@ VMExecutionContext::fillContinuationVars(ActRec* fp, return cont; } -// Explicitly instantiate for hhbctranslator.o +// Explicitly instantiate for hhbctranslator.o and codegen.o template c_Continuation* VMExecutionContext::createContinuation( ActRec*, bool, const Func*, const Func*); template c_Continuation* VMExecutionContext::createContinuation( ActRec*, bool, const Func*, const Func*); +template c_Continuation* VMExecutionContext::createContinuationHelper( + const Func*, const Func*, ObjectData*, ArrayData*, Class*); +template c_Continuation* VMExecutionContext::createContinuationHelper( + const Func*, const Func*, ObjectData*, ArrayData*, Class*); inline void OPTBLD_INLINE VMExecutionContext::iopCreateCont(PC& pc) { NEXT(); diff --git a/hphp/system/class_map.cpp b/hphp/system/class_map.cpp index 69a9781a8..cd83ae744 100644 --- a/hphp/system/class_map.cpp +++ b/hphp/system/class_map.cpp @@ -24654,6 +24654,11 @@ const char *g_class_map[] = { (const char *)0x14 /* KindOfString */, NULL, NULL, NULL, + (const char *)0x10006040, "getCalledClass", "", (const char*)0, (const char*)0, + "/**\n * ( excerpt from http://php.net/manual/en/continuation.getcalledclass.php\n * )\n *\n *\n * @return string\n */", + (const char *)0x14 /* KindOfString */, NULL, + NULL, + NULL, (const char *)0x10006040, "__clone", "", (const char*)0, (const char*)0, "/**\n * ( excerpt from http://php.net/manual/en/continuation.clone.php )\n *\n *\n * @return mixed\n */", (const char *)0xffffffff /* KindOfUnknown: $t: Variant */, NULL, diff --git a/hphp/test/quick/continuation-funcname.php b/hphp/test/quick/continuation-funcname.php index 1bd9b634f..6a6b7fd35 100644 --- a/hphp/test/quick/continuation-funcname.php +++ b/hphp/test/quick/continuation-funcname.php @@ -10,3 +10,4 @@ class ShortDerp extends BaseDerp {} $sd = new ShortDerp; var_dump($sd->genDerp()->getOrigFuncName()); +var_dump($sd->genDerp()->getCalledClass()); diff --git a/hphp/test/quick/continuation-funcname.php.expect b/hphp/test/quick/continuation-funcname.php.expect index 5469b8fb6..783c0489f 100644 --- a/hphp/test/quick/continuation-funcname.php.expect +++ b/hphp/test/quick/continuation-funcname.php.expect @@ -1 +1,2 @@ -string(18) "ShortDerp::genDerp" +string(7) "genDerp" +string(9) "ShortDerp" diff --git a/hphp/test/quick/debug_backtrace_continuation.php b/hphp/test/quick/debug_backtrace_continuation.php index 051152299..d70746bc9 100644 --- a/hphp/test/quick/debug_backtrace_continuation.php +++ b/hphp/test/quick/debug_backtrace_continuation.php @@ -10,4 +10,18 @@ function my_wrapper() { $gen->send(null); } +class my_class { + static function my_member_generator() { + $value = yield null; + var_dump(debug_backtrace()); + } +} + +function my_class_wrapper() { + $gen = my_class::my_member_generator(); + $gen->next(); + $gen->send(null); +} + my_wrapper(); +my_class_wrapper(); diff --git a/hphp/test/quick/debug_backtrace_continuation.php.expectf b/hphp/test/quick/debug_backtrace_continuation.php.expectf index 4489604c5..d1d4a6378 100644 --- a/hphp/test/quick/debug_backtrace_continuation.php.expectf +++ b/hphp/test/quick/debug_backtrace_continuation.php.expectf @@ -1,10 +1,6 @@ array(3) { [0]=> - array(4) { - ["file"]=> - string(0) "" - ["line"]=> - int(-1) + array(2) { ["function"]=> string(12) "my_generator" ["args"]=> @@ -40,7 +36,7 @@ array(3) { ["file"]=> string(%d) "%s" ["line"]=> - int(13) + int(26) ["function"]=> string(10) "my_wrapper" ["args"]=> @@ -48,3 +44,53 @@ array(3) { } } } +array(3) { + [0]=> + array(4) { + ["function"]=> + string(19) "my_member_generator" + ["class"]=> + string(8) "my_class" + ["type"]=> + string(2) "::" + ["args"]=> + array(1) { + [0]=> + object(Continuation)#1 (0) { + } + } + } + [1]=> + array(7) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(23) + ["function"]=> + string(4) "send" + ["class"]=> + string(12) "Continuation" + ["object"]=> + object(Continuation)#1 (0) { + } + ["type"]=> + string(2) "->" + ["args"]=> + array(1) { + [0]=> + NULL + } + } + [2]=> + array(4) { + ["file"]=> + string(%d) "%s" + ["line"]=> + int(27) + ["function"]=> + string(16) "my_class_wrapper" + ["args"]=> + array(0) { + } + } +} diff --git a/hphp/test/slow/traits/2071.php b/hphp/test/slow/traits/2071.php index 9d5d8cf25..a38546acc 100644 --- a/hphp/test/slow/traits/2071.php +++ b/hphp/test/slow/traits/2071.php @@ -6,6 +6,7 @@ function f($x) { } $c = f(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); trait T { function f($x) { yield get_called_class(); } } @@ -13,6 +14,8 @@ class X { use T; } $x = new X; $c = $x->f(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); $fcn = function ($x) { yield $x; }; $c = $fcn(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); diff --git a/hphp/test/slow/traits/2071.php.expect b/hphp/test/slow/traits/2071.php.expect index 16582bd16..245282613 100644 --- a/hphp/test/slow/traits/2071.php.expect +++ b/hphp/test/slow/traits/2071.php.expect @@ -1,3 +1,6 @@ string(1) "f" -string(4) "X::f" +string(0) "" +string(1) "f" +string(1) "X" string(9) "{closure}" +string(0) "" diff --git a/hphp/test/slow/yield/2174.php b/hphp/test/slow/yield/2174.php index 072e478d8..e9a0df55b 100644 --- a/hphp/test/slow/yield/2174.php +++ b/hphp/test/slow/yield/2174.php @@ -6,6 +6,7 @@ function f($x) { } $c = f(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); class X { function f($x) { yield $x; } static function g($x) { yield get_called_class(); } @@ -14,10 +15,14 @@ class Y extends X {} $x = new X; $c = $x->f(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); $c = X::g(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); $c = Y::g(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); $fcn = function ($x) { yield $x; }; $c = $fcn(32); var_dump($c->getOrigFuncName()); +var_dump($c->getCalledClass()); diff --git a/hphp/test/slow/yield/2174.php.expect b/hphp/test/slow/yield/2174.php.expect index 90f151ca5..a49480f25 100644 --- a/hphp/test/slow/yield/2174.php.expect +++ b/hphp/test/slow/yield/2174.php.expect @@ -1,5 +1,10 @@ string(1) "f" -string(4) "X::f" -string(4) "X::g" -string(4) "Y::g" +string(0) "" +string(1) "f" +string(1) "X" +string(1) "g" +string(1) "X" +string(1) "g" +string(1) "Y" string(9) "{closure}" +string(0) ""