Free generator locals at return / frame unwind.
[hiphop-php.git] / hphp / runtime / ext / ext_continuation.cpp
blob24685720ff8e61871251318942a0c70a80bb1e76
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 +----------------------------------------------------------------------+
18 #include "hphp/runtime/ext/ext_continuation.h"
19 #include "hphp/runtime/ext/asio/async_function_wait_handle.h"
20 #include "hphp/runtime/base/builtin-functions.h"
22 #include "hphp/runtime/ext/ext_spl.h"
23 #include "hphp/runtime/ext/ext_function.h"
25 #include "hphp/runtime/vm/jit/translator.h"
26 #include "hphp/runtime/vm/jit/translator-inline.h"
27 #include "hphp/runtime/vm/func.h"
28 #include "hphp/runtime/vm/runtime.h"
29 #include "hphp/runtime/base/stats.h"
31 namespace HPHP {
32 ///////////////////////////////////////////////////////////////////////////////
34 void delete_Continuation(ObjectData* od, const Class*) {
35 auto const cont = static_cast<c_Continuation*>(od);
36 auto const size = cont->getObjectSize();
37 auto const base = cont->getMallocBase();
38 cont->~c_Continuation();
39 if (LIKELY(size <= kMaxSmartSize)) {
40 return MM().smartFreeSizeLogged(base, size);
42 MM().smartFreeSizeBigLogged(base, size);
45 ///////////////////////////////////////////////////////////////////////////////
47 c_Continuation::c_Continuation(Class* cb)
48 : ExtObjectDataFlags(cb)
49 , m_index(-1LL)
50 , m_key(make_tv<KindOfInt64>(-1LL))
51 , m_value(make_tv<KindOfNull>())
53 o_subclassData.u16 = 0;
56 c_Continuation::~c_Continuation() {
57 tvRefcountedDecRef(m_key);
58 tvRefcountedDecRef(m_value);
60 if (LIKELY(done())) {
61 return;
64 // Free locals, but don't trigger the EventHook for FunctionExit
65 // since the continuation function has already been exited. We
66 // don't want redundant calls.
67 ActRec* ar = actRec();
68 frame_free_locals_inl_no_hook<false>(ar, ar->m_func->numLocals());
71 //////////////////////////////////////////////////////////////////////
73 void c_Continuation::t___construct() {}
75 void c_Continuation::suspend(Offset offset, const Cell& value) {
76 assert(actRec()->func()->contains(offset));
77 m_offset = offset;
78 cellSet(make_tv<KindOfInt64>(++m_index), m_key);
79 cellSet(value, m_value);
82 void c_Continuation::suspend(Offset offset, const Cell& key,
83 const Cell& value) {
84 assert(actRec()->func()->contains(offset));
85 m_offset = offset;
86 cellSet(key, m_key);
87 cellSet(value, m_value);
88 if (m_key.m_type == KindOfInt64) {
89 int64_t new_index = m_key.m_data.num;
90 m_index = new_index > m_index ? new_index : m_index;
94 Variant c_Continuation::t_current() {
95 const_assert(false);
96 return tvAsCVarRef(&m_value);
99 Variant c_Continuation::t_key() {
100 startedCheck();
101 return tvAsCVarRef(&m_key);
104 void c_Continuation::t_next() {
105 const_assert(false);
108 const StaticString
109 s_next("next"),
110 s__closure_("{closure}"),
111 s_this("this");
113 void c_Continuation::t_rewind() {
114 this->o_invoke_few_args(s_next, 0);
117 bool c_Continuation::t_valid() {
118 const_assert(false);
119 return !done();
122 void c_Continuation::t_send(const Variant& v) {
123 const_assert(false);
126 void c_Continuation::t_raise(const Variant& v) {
127 const_assert(false);
130 String c_Continuation::t_getorigfuncname() {
131 const Func* origFunc = actRec()->func();
132 auto const origName = origFunc->isClosureBody() ? s__closure_.get()
133 : origFunc->name();
134 assert(origName->isStatic());
135 return String(const_cast<StringData*>(origName));
138 String c_Continuation::t_getcalledclass() {
139 String called_class;
141 if (actRec()->hasThis()) {
142 called_class = actRec()->getThis()->getVMClass()->name()->data();
143 } else if (actRec()->hasClass()) {
144 called_class = actRec()->getClass()->name()->data();
145 } else {
146 called_class = empty_string;
149 return called_class;
152 void c_Continuation::copyContinuationVars(ActRec* srcFp) {
153 const auto dstFp = actRec();
154 const auto func = dstFp->func();
155 assert(srcFp->func() == dstFp->func());
157 for (Id i = 0; i < func->numLocals(); ++i) {
158 tvDupFlattenVars(frame_local(srcFp, i), frame_local(dstFp, i));
161 if (dstFp->hasThis()) {
162 dstFp->getThis()->incRefCount();
165 if (LIKELY(srcFp->m_varEnv == nullptr)) {
166 return;
169 if (srcFp->hasExtraArgs()) {
170 dstFp->setExtraArgs(srcFp->getExtraArgs()->clone(dstFp));
171 } else {
172 assert(srcFp->hasVarEnv());
173 dstFp->setVarEnv(srcFp->getVarEnv()->clone(dstFp));
177 c_Continuation *c_Continuation::Clone(ObjectData* obj) {
178 auto thiz = static_cast<c_Continuation*>(obj);
179 auto fp = thiz->actRec();
181 c_Continuation* cont = static_cast<c_Continuation*>(fp->getThisOrClass()
182 ? CreateMeth(fp, thiz->m_offset)
183 : CreateFunc(fp, thiz->m_offset));
185 cont->copyContinuationVars(fp);
187 cont->o_subclassData.u16 = thiz->o_subclassData.u16;
188 cont->m_index = thiz->m_index;
189 cellSet(thiz->m_key, cont->m_key);
190 cellSet(thiz->m_value, cont->m_value);
192 return cont;
195 ///////////////////////////////////////////////////////////////////////////////