Make continuations cloneable

Continuations would throw before if you tried to
clone them. This restriction has been lifted.
Esse commit está contido em:
Eric Caruso
2013-06-28 20:23:20 -07:00
commit de Sara Golemon
commit c498e390da
26 arquivos alterados com 696 adições e 3 exclusões
+77 -3
Ver Arquivo
@@ -149,10 +149,84 @@ String c_Continuation::t_getcalledclass() {
return called_class;
}
void c_Continuation::dupContVar(const StringData* name, TypedValue* src) {
ActRec *fp = actRec();
Id destId = fp->m_func->lookupVarId(name);
if (destId != kInvalidId) {
// Copy the value of the local to the cont object.
tvDupFlattenVars(src, frame_local(fp, destId), nullptr);
} else {
ActRec *contFP = fp;
if (!fp->hasVarEnv()) {
// This VarEnv may potentially outlive the most recently stack-allocated
// VarEnv, so we need to heap allocate it.
fp->setVarEnv(VarEnv::createLocalOnHeap(fp));
}
fp->getVarEnv()->setWithRef(name, src);
}
}
static const StaticString s_this("this");
void c_Continuation::copyContinuationVars(ActRec* fp) {
// For functions that contain only named locals, we can copy TVs
// right to the local space.
static const StringData* thisStr = s_this.get();
bool skipThis;
if (fp->hasVarEnv()) {
Stats::inc(Stats::Cont_CreateVerySlow);
Array definedVariables = fp->getVarEnv()->getDefinedVariables();
skipThis = definedVariables.exists(s_this, true);
for (ArrayIter iter(definedVariables); !iter.end(); iter.next()) {
if (iter.first().getStringData()->same(s___cont__.get())) {
continue;
}
dupContVar(iter.first().getStringData(),
const_cast<TypedValue *>(iter.secondRef().asTypedValue()));
}
} else {
const Func *genFunc = actRec()->m_func;
skipThis = genFunc->lookupVarId(thisStr) != kInvalidId;
// skip local 0 because that's the old continuation
for (Id i = 1; i < genFunc->numNamedLocals(); ++i) {
dupContVar(genFunc->localVarName(i), frame_local(fp, i));
}
}
// If $this is used as a local inside the body and is not provided
// by our containing environment, just prefill it here instead of
// using InitThisLoc inside the body
if (!skipThis && fp->hasThis()) {
Id id = actRec()->m_func->lookupVarId(thisStr);
if (id != kInvalidId) {
tvAsVariant(frame_local(actRec(), id)) = fp->getThis();
}
}
}
// unused
Variant c_Continuation::t___clone() {
throw_fatal(
"Trying to clone an uncloneable object of class Continuation");
return uninit_null();
not_reached();
}
c_Continuation *c_Continuation::clone() {
const Func *origFunc = m_origFunc;
const Func *genFunc = actRec()->m_func;
ActRec *fp = g_vmContext->getFP();
c_Continuation* cont = origFunc->isMethod()
? g_vmContext->createContMeth(origFunc, genFunc, fp->getThisOrClass())
: g_vmContext->createContFunc(origFunc, genFunc);
cont->copyContinuationVars(actRec());
cont->o_subclassData.u16 = o_subclassData.u16;
cont->m_label = m_label;
cont->m_index = m_index;
cont->m_value = m_value;
return cont;
}
namespace {
+5
Ver Arquivo
@@ -71,6 +71,8 @@ public:
String t_getcalledclass();
Variant t___clone();
c_Continuation* clone();
static c_Continuation* alloc(const Func* origFunc, const Func* genFunc) {
assert(origFunc);
assert(genFunc);
@@ -128,6 +130,9 @@ private:
return (char*)(m_arPtr + 1) - (char*)this;
}
void dupContVar(const StringData *name, TypedValue *src);
void copyContinuationVars(ActRec *fp);
public:
/* 32-bit o_id from ObjectData */
int32_t m_label;
+44
Ver Arquivo
@@ -0,0 +1,44 @@
<?php
function foo($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
}
$a1 = 1;
$a2 = -999999999;
$x = foo($a1, $a2);
$y1 = clone $x;
$y2 = clone $x;
$a2 = 2;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+20
Ver Arquivo
@@ -0,0 +1,20 @@
11 102
31 303
61 604
--------
int(1)
int(605)
========
11 705
31 906
61 1207
--------
int(1)
int(1208)
========
11 1308
31 1509
61 1810
--------
int(1)
int(1811)
+25
Ver Arquivo
@@ -0,0 +1,25 @@
<?php
$foo = function() {
static $x = 1;
$x += 10;
yield $x;
$x += 100;
yield $x;
$x += 1000;
yield $x;
};
$x = $foo();
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($x as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y1 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y2 as $v) {
echo $v . "\n";
}
+8
Ver Arquivo
@@ -0,0 +1,8 @@
111
1111
========
1211
2211
========
2311
3311
+23
Ver Arquivo
@@ -0,0 +1,23 @@
<?php
function f(&$a) {
++$a;
yield $a;
++$a;
yield $a;
}
$a = 3;
$x = f($a);
unset($a);
$y1 = clone $x;
$y2 = clone $x;
foreach ($y1 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y2 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($x as $v) {
echo $v . "\n";
}
+8
Ver Arquivo
@@ -0,0 +1,8 @@
4
5
========
4
5
========
4
5
+52
Ver Arquivo
@@ -0,0 +1,52 @@
<?php
function foo($a, &$b) {
$var1 = 'x';
$var2 = 'y';
$$var1 = $a;
$$var2 =& $b;
unset($a);
unset($b);
$$var1 += 10;
$$var2 += 100;
yield $$var1 * 10000 + $$var2;
$$var1 += 20;
$$var2 += 200;
yield $$var1 * 10000 + $$var2;
$$var1 += 30;
$$var2 += 300;
yield $$var1 * 10000 + $$var2;
}
$a1 = 1;
$a2 = -999999999;
$x = foo($a1, $a2);
$a2 = 2;
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+17
Ver Arquivo
@@ -0,0 +1,17 @@
31 302
61 603
--------
int(1)
int(604)
========
31 804
61 1105
--------
int(1)
int(1106)
========
31 1306
61 1607
--------
int(1)
int(1608)
+45
Ver Arquivo
@@ -0,0 +1,45 @@
<?php
function foo($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
}
$a1 = 1;
$a2 = -999999999;
$x = foo($a1, $a2);
$a2 = 2;
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+17
Ver Arquivo
@@ -0,0 +1,17 @@
31 302
61 603
--------
int(1)
int(604)
========
31 804
61 1105
--------
int(1)
int(1106)
========
31 1306
61 1607
--------
int(1)
int(1608)
+44
Ver Arquivo
@@ -0,0 +1,44 @@
<?php
$foo = function ($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
};
$a1 = 1;
$a2 = -999999999;
$x = $foo($a1, $a2);
$y1 = clone $x;
$y2 = clone $x;
$a2 = 2;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+20
Ver Arquivo
@@ -0,0 +1,20 @@
11 102
31 303
61 604
--------
int(1)
int(605)
========
11 705
31 906
61 1207
--------
int(1)
int(1208)
========
11 1308
31 1509
61 1810
--------
int(1)
int(1811)
+45
Ver Arquivo
@@ -0,0 +1,45 @@
<?php
$foo = function ($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
};
$a1 = 1;
$a2 = -999999999;
$x = $foo($a1, $a2);
$a2 = 2;
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+17
Ver Arquivo
@@ -0,0 +1,17 @@
31 302
61 603
--------
int(1)
int(604)
========
31 804
61 1105
--------
int(1)
int(1106)
========
31 1306
61 1607
--------
int(1)
int(1608)
+44
Ver Arquivo
@@ -0,0 +1,44 @@
<?php
$a1 = 1;
$a2 = -999999999;
$foo = function () use ($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
};
$x = $foo();
$y1 = clone $x;
$y2 = clone $x;
$a2 = 2;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+20
Ver Arquivo
@@ -0,0 +1,20 @@
11 102
31 303
61 604
--------
int(1)
int(605)
========
11 705
31 906
61 1207
--------
int(1)
int(1208)
========
11 1308
31 1509
61 1810
--------
int(1)
int(1811)
+45
Ver Arquivo
@@ -0,0 +1,45 @@
<?php
$a1 = 1;
$a2 = -999999999;
$foo = function () use ($a1, &$a2) {
$a1 += 10;
$a2 += 100;
yield $a1 * 10000 + $a2;
$a1 += 20;
$a2 += 200;
yield $a1 * 10000 + $a2;
$a1 += 30;
$a2 += 300;
yield $a1 * 10000 + $a2;
};
$x = $foo();
$a2 = 2;
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($y1 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($y2 as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
echo "========\n";
foreach ($x as $v) {
$v1 = (int)($v / 10000);
$v2 = $v % 10000;
echo $v1 . " " . $v2 . "\n";
++$a2;
}
echo "--------\n";
var_dump($a1, $a2);
+17
Ver Arquivo
@@ -0,0 +1,17 @@
31 302
61 603
--------
int(1)
int(604)
========
31 804
61 1105
--------
int(1)
int(1106)
========
31 1306
61 1607
--------
int(1)
int(1608)
+24
Ver Arquivo
@@ -0,0 +1,24 @@
<?php
function foo() {
static $x = 1;
$x += 10;
yield $x;
$x += 100;
yield $x;
$x += 1000;
yield $x;
}
$x = foo();
$y1 = clone $x;
$y2 = clone $x;
foreach ($x as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y1 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y2 as $v) {
echo $v . "\n";
}
+11
Ver Arquivo
@@ -0,0 +1,11 @@
11
111
1111
========
1121
1221
2221
========
2231
2331
3331
+25
Ver Arquivo
@@ -0,0 +1,25 @@
<?php
function foo() {
static $x = 1;
$x += 10;
yield $x;
$x += 100;
yield $x;
$x += 1000;
yield $x;
}
$x = foo();
$x->next();
$y1 = clone $x;
$y2 = clone $x;
foreach ($x as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y1 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y2 as $v) {
echo $v . "\n";
}
+8
Ver Arquivo
@@ -0,0 +1,8 @@
111
1111
========
1211
2211
========
2311
3311
+24
Ver Arquivo
@@ -0,0 +1,24 @@
<?php
$foo = function() {
static $x = 1;
$x += 10;
yield $x;
$x += 100;
yield $x;
$x += 1000;
yield $x;
};
$x = $foo();
$y1 = clone $x;
$y2 = clone $x;
foreach ($x as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y1 as $v) {
echo $v . "\n";
}
echo "========\n";
foreach ($y2 as $v) {
echo $v . "\n";
}
+11
Ver Arquivo
@@ -0,0 +1,11 @@
11
111
1111
========
1121
1221
2221
========
2231
2331
3331