summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2012-07-20 00:49:50 +0200
committerNikita Popov <nikic@php.net>2012-07-20 16:09:06 +0200
commitc9709bfbd7a71a42e0472abaf9c7d30598e264bf (patch)
tree995cb4d438093a87c887f1de4319be4d49a05136
parent85f077cea13b3cb4927453b8a2f8ce51a9461bbb (diff)
downloadphp-git-c9709bfbd7a71a42e0472abaf9c7d30598e264bf.tar.gz
Remove asterix modifier (*) for generators
Generators are now automatically detected by the presence of a `yield` expression in their body. This removes the ZEND_SUSPEND_AND_RETURN_GENERATOR opcode. Instead additional checks for ZEND_ACC_GENERATOR are added to the fcall_common helper and zend_call_function. This also adds a new function zend_generator_create_zval, which handles the actual creation of the generator zval from an op array. I feel like I should deglobalize the zend_create_execute_data_from_op_array code a bit. It currently changes EG(current_execute_data) and EG(opline_ptr) which is somewhat confusing (given the name).
-rw-r--r--Zend/tests/generators/auto_incrementing_keys.phpt2
-rw-r--r--Zend/tests/generators/backtrace.phpt3
-rw-r--r--Zend/tests/generators/clone.phpt2
-rw-r--r--Zend/tests/generators/clone_with_foreach.phpt2
-rw-r--r--Zend/tests/generators/clone_with_stack.phpt2
-rw-r--r--Zend/tests/generators/clone_with_symbol_table.phpt2
-rw-r--r--Zend/tests/generators/clone_with_this.phpt4
-rw-r--r--Zend/tests/generators/close_inside_generator.phpt2
-rw-r--r--Zend/tests/generators/dynamic_call.phpt2
-rw-r--r--Zend/tests/generators/errors/generator_cannot_return_error.phpt3
-rw-r--r--Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt2
-rw-r--r--Zend/tests/generators/errors/yield_const_by_ref_error.phpt2
-rw-r--r--Zend/tests/generators/errors/yield_in_normal_function_error.phpt12
-rw-r--r--Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt2
-rw-r--r--Zend/tests/generators/errors/yield_outside_function_error.phpt2
-rw-r--r--Zend/tests/generators/func_get_args.phpt3
-rw-r--r--Zend/tests/generators/generator_close.phpt2
-rw-r--r--Zend/tests/generators/generator_method.phpt2
-rw-r--r--Zend/tests/generators/generator_method_by_ref.phpt2
-rw-r--r--Zend/tests/generators/generator_returns_generator.phpt6
-rw-r--r--Zend/tests/generators/generator_send.phpt2
-rw-r--r--Zend/tests/generators/generator_throwing_during_function_call.phpt2
-rw-r--r--Zend/tests/generators/generator_throwing_exception.phpt2
-rw-r--r--Zend/tests/generators/generator_with_keys.phpt2
-rw-r--r--Zend/tests/generators/no_foreach_var_leaks.phpt2
-rw-r--r--Zend/tests/generators/send_after_close.phpt8
-rw-r--r--Zend/tests/generators/send_returns_current.phpt2
-rw-r--r--Zend/tests/generators/unused_return_value.phpt2
-rw-r--r--Zend/tests/generators/xrange.phpt2
-rw-r--r--Zend/tests/generators/yield_by_reference.phpt2
-rw-r--r--Zend/tests/generators/yield_during_function_call.phpt2
-rw-r--r--Zend/tests/generators/yield_during_method_call.phpt2
-rw-r--r--Zend/tests/generators/yield_ref_function_call_by_reference.phpt2
-rw-r--r--Zend/tests/generators/yield_without_value.phpt2
-rw-r--r--Zend/zend_compile.c38
-rw-r--r--Zend/zend_compile.h5
-rw-r--r--Zend/zend_execute.h1
-rw-r--r--Zend/zend_execute_API.c9
-rw-r--r--Zend/zend_generators.c53
-rw-r--r--Zend/zend_generators.h1
-rw-r--r--Zend/zend_language_parser.y27
-rw-r--r--Zend/zend_vm_def.h109
-rw-r--r--Zend/zend_vm_execute.h228
-rw-r--r--Zend/zend_vm_execute.skl2
-rw-r--r--Zend/zend_vm_opcodes.h5
45 files changed, 247 insertions, 324 deletions
diff --git a/Zend/tests/generators/auto_incrementing_keys.phpt b/Zend/tests/generators/auto_incrementing_keys.phpt
index 623f2d813d..acfb2f2ce0 100644
--- a/Zend/tests/generators/auto_incrementing_keys.phpt
+++ b/Zend/tests/generators/auto_incrementing_keys.phpt
@@ -3,7 +3,7 @@ Generator keys are auto-incrementing by default
--FILE--
<?php
-function *gen() {
+function gen() {
yield 'foo';
yield 'bar';
yield 5 => 'rab';
diff --git a/Zend/tests/generators/backtrace.phpt b/Zend/tests/generators/backtrace.phpt
index 77976f9324..5f665b7e4a 100644
--- a/Zend/tests/generators/backtrace.phpt
+++ b/Zend/tests/generators/backtrace.phpt
@@ -7,8 +7,9 @@ function f1() {
debug_print_backtrace();
}
-function *f2($arg1, $arg2) {
+function f2($arg1, $arg2) {
f1();
+ yield; // force generator
}
function f3($gen) {
diff --git a/Zend/tests/generators/clone.phpt b/Zend/tests/generators/clone.phpt
index 94c4c6364e..36811dfe6e 100644
--- a/Zend/tests/generators/clone.phpt
+++ b/Zend/tests/generators/clone.phpt
@@ -3,7 +3,7 @@ Generators can be cloned
--FILE--
<?php
-function *firstN($end) {
+function firstN($end) {
for ($i = 0; $i < $end; ++$i) {
yield $i;
}
diff --git a/Zend/tests/generators/clone_with_foreach.phpt b/Zend/tests/generators/clone_with_foreach.phpt
index 42cf3348ea..b887338036 100644
--- a/Zend/tests/generators/clone_with_foreach.phpt
+++ b/Zend/tests/generators/clone_with_foreach.phpt
@@ -3,7 +3,7 @@ Cloning a generator with a foreach loop properly adds a ref for the loop var
--FILE--
<?php
-function *gen() {
+function gen() {
foreach ([1, 2, 3] as $i) {
yield $i;
}
diff --git a/Zend/tests/generators/clone_with_stack.phpt b/Zend/tests/generators/clone_with_stack.phpt
index 79bca31bb6..673c0e5d1e 100644
--- a/Zend/tests/generators/clone_with_stack.phpt
+++ b/Zend/tests/generators/clone_with_stack.phpt
@@ -3,7 +3,7 @@ A generator with an active stack can be cloned
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(str_repeat("x", yield));
}
diff --git a/Zend/tests/generators/clone_with_symbol_table.phpt b/Zend/tests/generators/clone_with_symbol_table.phpt
index 2a4cf10aab..0d1bd4ec3c 100644
--- a/Zend/tests/generators/clone_with_symbol_table.phpt
+++ b/Zend/tests/generators/clone_with_symbol_table.phpt
@@ -3,7 +3,7 @@ A generator using a symbol table can be cloned
--FILE--
<?php
-function *gen() {
+function gen() {
// force compiled variable for $foo
$foo = 'foo';
diff --git a/Zend/tests/generators/clone_with_this.phpt b/Zend/tests/generators/clone_with_this.phpt
index b0f28be3c9..66efd02987 100644
--- a/Zend/tests/generators/clone_with_this.phpt
+++ b/Zend/tests/generators/clone_with_this.phpt
@@ -1,12 +1,12 @@
--TEST--
-Cloning a generator method (with this)
+Cloning a generator method (with $this)
--FILE--
<?php
class Test {
protected $foo;
- public function *gen() {
+ public function gen() {
$this->foo = 'bar';
yield; // interrupt
var_dump($this->foo);
diff --git a/Zend/tests/generators/close_inside_generator.phpt b/Zend/tests/generators/close_inside_generator.phpt
index 41a91c9fc7..1df64bf6b1 100644
--- a/Zend/tests/generators/close_inside_generator.phpt
+++ b/Zend/tests/generators/close_inside_generator.phpt
@@ -3,7 +3,7 @@ Calling close() during the exectution of the generator
--FILE--
<?php
-function *gen() {
+function gen() {
/* Pass the generator object itself in */
$gen = yield;
diff --git a/Zend/tests/generators/dynamic_call.phpt b/Zend/tests/generators/dynamic_call.phpt
index 7b4b0c3e59..d564540952 100644
--- a/Zend/tests/generators/dynamic_call.phpt
+++ b/Zend/tests/generators/dynamic_call.phpt
@@ -3,7 +3,7 @@ It's possible to invoke a generator dynamically
--FILE--
<?php
-function *gen($foo, $bar) {
+function gen($foo, $bar) {
yield $foo;
yield $bar;
}
diff --git a/Zend/tests/generators/errors/generator_cannot_return_error.phpt b/Zend/tests/generators/errors/generator_cannot_return_error.phpt
index 070e3d5d5c..9a46bff5e6 100644
--- a/Zend/tests/generators/errors/generator_cannot_return_error.phpt
+++ b/Zend/tests/generators/errors/generator_cannot_return_error.phpt
@@ -3,7 +3,8 @@ Generators cannot return values
--FILE--
<?php
-function *gen() {
+function gen() {
+ yield;
return $abc;
}
diff --git a/Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt b/Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
index 5d1a9e3484..9c618d2515 100644
--- a/Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
+++ b/Zend/tests/generators/errors/non_ref_generator_iterated_by_ref_error.phpt
@@ -3,7 +3,7 @@ Non-ref generators cannot be iterated by-ref
--FILE--
<?php
-function *gen() { }
+function gen() { yield; }
$gen = gen();
foreach ($gen as &$value) { }
diff --git a/Zend/tests/generators/errors/yield_const_by_ref_error.phpt b/Zend/tests/generators/errors/yield_const_by_ref_error.phpt
index 37ce1450db..e79f83e24a 100644
--- a/Zend/tests/generators/errors/yield_const_by_ref_error.phpt
+++ b/Zend/tests/generators/errors/yield_const_by_ref_error.phpt
@@ -3,7 +3,7 @@ A notice is thrown when yielding a constant value by reference
--FILE--
<?php
-function *&gen() {
+function &gen() {
yield "foo";
}
diff --git a/Zend/tests/generators/errors/yield_in_normal_function_error.phpt b/Zend/tests/generators/errors/yield_in_normal_function_error.phpt
deleted file mode 100644
index 4670a41542..0000000000
--- a/Zend/tests/generators/errors/yield_in_normal_function_error.phpt
+++ /dev/null
@@ -1,12 +0,0 @@
---TEST--
-Yield cannot be used in normal (non-generator) functions
---FILE--
-<?php
-
-function foo() {
- yield "Test";
-}
-
-?>
---EXPECTF--
-Fatal error: The "yield" expression can only be used inside a generator function in %s on line %d
diff --git a/Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt b/Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt
index 2487149eef..4b8563331c 100644
--- a/Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt
+++ b/Zend/tests/generators/errors/yield_non_ref_function_call_by_ref_error.phpt
@@ -7,7 +7,7 @@ function foo() {
return "bar";
}
-function *&gen() {
+function &gen() {
yield foo();
}
diff --git a/Zend/tests/generators/errors/yield_outside_function_error.phpt b/Zend/tests/generators/errors/yield_outside_function_error.phpt
index 5f47e75366..f999c1c03b 100644
--- a/Zend/tests/generators/errors/yield_outside_function_error.phpt
+++ b/Zend/tests/generators/errors/yield_outside_function_error.phpt
@@ -7,4 +7,4 @@ yield "Test";
?>
--EXPECTF--
-Fatal error: The "yield" expression can only be used inside a generator function in %s on line %d
+Fatal error: The "yield" expression can only be used inside a function in %s on line %d
diff --git a/Zend/tests/generators/func_get_args.phpt b/Zend/tests/generators/func_get_args.phpt
index 7ce7fb002f..f8d3fa7c14 100644
--- a/Zend/tests/generators/func_get_args.phpt
+++ b/Zend/tests/generators/func_get_args.phpt
@@ -3,8 +3,9 @@ func_get_args() can be used inside generator functions
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(func_get_args());
+ yield; // trigger generator
}
$gen = gen("foo", "bar");
diff --git a/Zend/tests/generators/generator_close.phpt b/Zend/tests/generators/generator_close.phpt
index 003eef094d..3dec285409 100644
--- a/Zend/tests/generators/generator_close.phpt
+++ b/Zend/tests/generators/generator_close.phpt
@@ -3,7 +3,7 @@ Generator can be closed by calling ->close()
--FILE--
<?php
-function *allNumbers() {
+function allNumbers() {
for ($i = 0; true; ++$i) {
yield $i;
}
diff --git a/Zend/tests/generators/generator_method.phpt b/Zend/tests/generators/generator_method.phpt
index b64476dc89..b8196c171e 100644
--- a/Zend/tests/generators/generator_method.phpt
+++ b/Zend/tests/generators/generator_method.phpt
@@ -10,7 +10,7 @@ class Test implements IteratorAggregate {
$this->data = $data;
}
- public function *getIterator() {
+ public function getIterator() {
foreach ($this->data as $value) {
yield $value;
}
diff --git a/Zend/tests/generators/generator_method_by_ref.phpt b/Zend/tests/generators/generator_method_by_ref.phpt
index 108c2133f6..cfe52fe67f 100644
--- a/Zend/tests/generators/generator_method_by_ref.phpt
+++ b/Zend/tests/generators/generator_method_by_ref.phpt
@@ -14,7 +14,7 @@ class Test implements IteratorAggregate {
return $this->data;
}
- public function *&getIterator() {
+ public function &getIterator() {
foreach ($this->data as $key => &$value) {
yield $key => $value;
}
diff --git a/Zend/tests/generators/generator_returns_generator.phpt b/Zend/tests/generators/generator_returns_generator.phpt
index a3e2b29468..ad332a3be9 100644
--- a/Zend/tests/generators/generator_returns_generator.phpt
+++ b/Zend/tests/generators/generator_returns_generator.phpt
@@ -3,12 +3,14 @@ A generator function returns a Generator object
--FILE--
<?php
-function* foo() {
+function gen() {
// execution is suspended here, so the following never gets run:
echo "Foo";
+ // trigger a generator
+ yield;
}
-$generator = foo();
+$generator = gen();
var_dump($generator instanceof Generator);
?>
diff --git a/Zend/tests/generators/generator_send.phpt b/Zend/tests/generators/generator_send.phpt
index 11ac37f846..074d815389 100644
--- a/Zend/tests/generators/generator_send.phpt
+++ b/Zend/tests/generators/generator_send.phpt
@@ -3,7 +3,7 @@ Values can be sent back to the generator
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(yield "yield foo");
var_dump(yield "yield bar");
}
diff --git a/Zend/tests/generators/generator_throwing_during_function_call.phpt b/Zend/tests/generators/generator_throwing_during_function_call.phpt
index 5e40ef9483..bd0d2448b7 100644
--- a/Zend/tests/generators/generator_throwing_during_function_call.phpt
+++ b/Zend/tests/generators/generator_throwing_during_function_call.phpt
@@ -7,7 +7,7 @@ function throwException() {
throw new Exception('test');
}
-function *gen() {
+function gen() {
yield 'foo';
strlen("foo", "bar", throwException());
yield 'bar';
diff --git a/Zend/tests/generators/generator_throwing_exception.phpt b/Zend/tests/generators/generator_throwing_exception.phpt
index 5df4a81132..f537c3fc77 100644
--- a/Zend/tests/generators/generator_throwing_exception.phpt
+++ b/Zend/tests/generators/generator_throwing_exception.phpt
@@ -3,7 +3,7 @@ Generators can throw exceptions
--FILE--
<?php
-function *gen() {
+function gen() {
yield 'foo';
throw new Exception('test');
yield 'bar';
diff --git a/Zend/tests/generators/generator_with_keys.phpt b/Zend/tests/generators/generator_with_keys.phpt
index 43e3e5ecf7..efb377679e 100644
--- a/Zend/tests/generators/generator_with_keys.phpt
+++ b/Zend/tests/generators/generator_with_keys.phpt
@@ -3,7 +3,7 @@ Generators can also yield keys
--FILE--
<?php
-function *reverse(array $array) {
+function reverse(array $array) {
end($array);
while (null !== $key = key($array)) {
yield $key => current($array);
diff --git a/Zend/tests/generators/no_foreach_var_leaks.phpt b/Zend/tests/generators/no_foreach_var_leaks.phpt
index 36ab91bb15..62743895eb 100644
--- a/Zend/tests/generators/no_foreach_var_leaks.phpt
+++ b/Zend/tests/generators/no_foreach_var_leaks.phpt
@@ -3,7 +3,7 @@ foreach() (and other) variables aren't leaked on premature close
--FILE--
<?php
-function *gen(array $array) {
+function gen(array $array) {
foreach ($array as $value) {
yield $value;
}
diff --git a/Zend/tests/generators/send_after_close.phpt b/Zend/tests/generators/send_after_close.phpt
index 6a251b2481..806baf8cee 100644
--- a/Zend/tests/generators/send_after_close.phpt
+++ b/Zend/tests/generators/send_after_close.phpt
@@ -3,12 +3,12 @@ Calls to send() after close should do nothing
--FILE--
<?php
-function *gen() { }
+function gen() { var_dump(yield); }
$gen = gen();
-$gen->send("Test");
+$gen->send('foo');
+$gen->send('bar');
?>
-===DONE===
--EXPECT--
-===DONE===
+string(3) "foo"
diff --git a/Zend/tests/generators/send_returns_current.phpt b/Zend/tests/generators/send_returns_current.phpt
index d3a4afd53a..fc260c0af0 100644
--- a/Zend/tests/generators/send_returns_current.phpt
+++ b/Zend/tests/generators/send_returns_current.phpt
@@ -3,7 +3,7 @@ $generator->send() returns the yielded value
--FILE--
<?php
-function *reverseEchoGenerator() {
+function reverseEchoGenerator() {
$data = yield;
while (true) {
$data = yield strrev($data);
diff --git a/Zend/tests/generators/unused_return_value.phpt b/Zend/tests/generators/unused_return_value.phpt
index 8d6deefb95..ddce64542c 100644
--- a/Zend/tests/generators/unused_return_value.phpt
+++ b/Zend/tests/generators/unused_return_value.phpt
@@ -3,7 +3,7 @@ There shouldn't be any leaks when the genertor's return value isn't used
--FILE--
<?php
-function *gen($foo) {}
+function gen($foo) { yield; }
gen('foo'); // return value not used
diff --git a/Zend/tests/generators/xrange.phpt b/Zend/tests/generators/xrange.phpt
index 685c6b3b57..4d8b60fa90 100644
--- a/Zend/tests/generators/xrange.phpt
+++ b/Zend/tests/generators/xrange.phpt
@@ -3,7 +3,7 @@ Simple generator xrange() test
--FILE--
<?php
-function *xrange($start, $end, $step = 1) {
+function xrange($start, $end, $step = 1) {
for ($i = $start; $i <= $end; $i += $step) {
yield $i;
}
diff --git a/Zend/tests/generators/yield_by_reference.phpt b/Zend/tests/generators/yield_by_reference.phpt
index 86dd419bd6..5a6c169b3e 100644
--- a/Zend/tests/generators/yield_by_reference.phpt
+++ b/Zend/tests/generators/yield_by_reference.phpt
@@ -3,7 +3,7 @@ Generators can yield by-reference
--FILE--
<?php
-function *&iter(array &$array) {
+function &iter(array &$array) {
foreach ($array as $key => &$value) {
yield $key => $value;
}
diff --git a/Zend/tests/generators/yield_during_function_call.phpt b/Zend/tests/generators/yield_during_function_call.phpt
index 9727b8fd33..21071f9fb4 100644
--- a/Zend/tests/generators/yield_during_function_call.phpt
+++ b/Zend/tests/generators/yield_during_function_call.phpt
@@ -3,7 +3,7 @@
--FILE--
<?php
-function *gen() {
+function gen() {
var_dump(str_repeat("x", yield));
}
diff --git a/Zend/tests/generators/yield_during_method_call.phpt b/Zend/tests/generators/yield_during_method_call.phpt
index da987ab5b7..e8859ac0c2 100644
--- a/Zend/tests/generators/yield_during_method_call.phpt
+++ b/Zend/tests/generators/yield_during_method_call.phpt
@@ -9,7 +9,7 @@ class A {
}
}
-function *gen() {
+function gen() {
$a = new A;
$a->b(yield);
}
diff --git a/Zend/tests/generators/yield_ref_function_call_by_reference.phpt b/Zend/tests/generators/yield_ref_function_call_by_reference.phpt
index 88f72eabd1..e371affd92 100644
--- a/Zend/tests/generators/yield_ref_function_call_by_reference.phpt
+++ b/Zend/tests/generators/yield_ref_function_call_by_reference.phpt
@@ -7,7 +7,7 @@ function &nop(&$var) {
return $var;
}
-function *&gen(&$var) {
+function &gen(&$var) {
yield nop($var);
}
diff --git a/Zend/tests/generators/yield_without_value.phpt b/Zend/tests/generators/yield_without_value.phpt
index dc467a83bd..510c755bd3 100644
--- a/Zend/tests/generators/yield_without_value.phpt
+++ b/Zend/tests/generators/yield_without_value.phpt
@@ -3,7 +3,7 @@ yield can be used without a value
--FILE--
<?php
-function *recv() {
+function recv() {
while (true) {
var_dump(yield);
}
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 9264fde8e2..e030f94c78 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -1519,7 +1519,7 @@ int zend_do_verify_access_types(const znode *current_access_type, const znode *n
}
/* }}} */
-void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int is_generator, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
+void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC) /* {{{ */
{
zend_op_array op_array;
char *name = function_name->u.constant.value.str.val;
@@ -1553,9 +1553,6 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
CG(interactive) = orig_interactive;
op_array.function_name = name;
- if (is_generator) {
- op_array.fn_flags |= ZEND_ACC_GENERATOR;
- }
if (return_reference) {
op_array.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
}
@@ -1754,7 +1751,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
}
/* }}} */
-void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int is_generator, int return_reference, int is_static TSRMLS_DC) /* {{{ */
+void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC) /* {{{ */
{
znode function_name;
zend_op_array *current_op_array = CG(active_op_array);
@@ -1764,7 +1761,7 @@ void zend_do_begin_lambda_function_declaration(znode *result, znode *function_to
function_name.op_type = IS_CONST;
ZVAL_STRINGL(&function_name.u.constant, "{closure}", sizeof("{closure}")-1, 1);
- zend_do_begin_function_declaration(function_token, &function_name, 0, is_generator, return_reference, NULL TSRMLS_CC);
+ zend_do_begin_function_declaration(function_token, &function_name, 0, return_reference, NULL TSRMLS_CC);
result->op_type = IS_TMP_VAR;
result->u.op.var = get_temporary_variable(current_op_array);
@@ -2670,10 +2667,12 @@ void zend_do_yield(znode *result, const znode *value, const znode *key TSRMLS_DC
{
zend_op *opline;
- if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0) {
- zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a generator function");
+ if (!CG(active_op_array)->function_name) {
+ zend_error(E_COMPILE_ERROR, "The \"yield\" expression can only be used inside a function");
}
+ CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_YIELD;
@@ -2704,10 +2703,12 @@ void zend_do_delegate_yield(znode *result, const znode *value TSRMLS_DC) /* {{{
{
zend_op *opline;
- if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0) {
- zend_error(E_COMPILE_ERROR, "The \"yield*\" expression can only be used inside a generator function");
+ if (!CG(active_op_array)->function_name) {
+ zend_error(E_COMPILE_ERROR, "The \"yield*\" expression can only be used inside a function");
}
+ CG(active_op_array)->fn_flags |= ZEND_ACC_GENERATOR;
+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_DELEGATE_YIELD;
@@ -2721,23 +2722,6 @@ void zend_do_delegate_yield(znode *result, const znode *value TSRMLS_DC) /* {{{
}
/* }}} */
-void zend_do_suspend_if_generator(TSRMLS_D) /* {{{ */
-{
- zend_op *opline;
-
- // we only suspend execution if the current function is a generator
- if ((CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) == 0) {
- return;
- }
-
- opline = get_next_op(CG(active_op_array) TSRMLS_CC);
-
- opline->opcode = ZEND_SUSPEND_AND_RETURN_GENERATOR;
- SET_UNUSED(opline->op1);
- SET_UNUSED(opline->op2);
-}
-/* }}} */
-
static int zend_add_try_element(zend_uint try_op TSRMLS_DC) /* {{{ */
{
int try_catch_offset = CG(active_op_array)->last_try_catch++;
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index d0587d1faa..c4355e0dde 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -478,7 +478,7 @@ void zend_do_add_string(znode *result, const znode *op1, znode *op2 TSRMLS_DC);
void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRMLS_DC);
int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier);
-void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int is_generator, int return_reference, znode *fn_flags_znode TSRMLS_DC);
+void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_bool pass_by_reference TSRMLS_DC);
int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC);
@@ -492,10 +492,9 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode
void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC);
void zend_do_yield(znode *result, const znode *value, const znode *key TSRMLS_DC);
void zend_do_delegate_yield(znode *result, const znode *value TSRMLS_DC);
-void zend_do_suspend_if_generator(TSRMLS_D);
void zend_do_handle_exception(TSRMLS_D);
-void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int is_generator, int return_reference, int is_static TSRMLS_DC);
+void zend_do_begin_lambda_function_declaration(znode *result, znode *function_token, int return_reference, int is_static TSRMLS_DC);
void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC);
void zend_do_try(znode *try_token TSRMLS_DC);
diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h
index 92160b54eb..4cfc52b6a3 100644
--- a/Zend/zend_execute.h
+++ b/Zend/zend_execute.h
@@ -55,6 +55,7 @@ ZEND_API extern void (*zend_execute_internal)(zend_execute_data *execute_data_pt
void init_executor(TSRMLS_D);
void shutdown_executor(TSRMLS_D);
void shutdown_destructors(TSRMLS_D);
+zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC);
ZEND_API void execute(zend_op_array *op_array TSRMLS_DC);
ZEND_API void execute_ex(zend_execute_data *execute_data TSRMLS_DC);
ZEND_API void execute_internal(zend_execute_data *execute_data_ptr, int return_value_used TSRMLS_DC);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 1deee2a86c..fb0c18b27c 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -31,6 +31,7 @@
#include "zend_extensions.h"
#include "zend_exceptions.h"
#include "zend_closures.h"
+#include "zend_generators.h"
#include "zend_vm.h"
#include "zend_float.h"
#ifdef HAVE_SYS_TIME_H
@@ -955,7 +956,13 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
EG(return_value_ptr_ptr) = fci->retval_ptr_ptr;
EG(active_op_array) = (zend_op_array *) EX(function_state).function;
original_opline_ptr = EG(opline_ptr);
- zend_execute(EG(active_op_array) TSRMLS_CC);
+
+ if (EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ *fci->retval_ptr_ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
+ } else {
+ zend_execute(EG(active_op_array) TSRMLS_CC);
+ }
+
if (!fci->symbol_table && EG(active_symbol_table)) {
if (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
zend_hash_destroy(EG(active_symbol_table));
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 20ab9b16c6..b164fb835e 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -315,6 +315,56 @@ static zend_object_value zend_generator_create(zend_class_entry *class_type TSRM
}
/* }}} */
+/* Requires globals EG(scope), EG(current_scope), EG(This),
+ * EG(active_symbol_table) and EG(current_execute_data). */
+zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_DC) /* {{{ */
+{
+ zval *return_value;
+ zend_generator *generator;
+
+ /* Create new execution context. We have to back up and restore
+ * EG(current_execute_data) and EG(opline_ptr) here because the function
+ * modifies it. */
+ zend_execute_data *current_execute_data = EG(current_execute_data);
+ zend_op **opline_ptr = EG(opline_ptr);
+ zend_execute_data *execute_data = zend_create_execute_data_from_op_array(op_array, 0 TSRMLS_CC);
+ EG(current_execute_data) = current_execute_data;
+ EG(opline_ptr) = opline_ptr;
+
+ ALLOC_INIT_ZVAL(return_value);
+ object_init_ex(return_value, zend_ce_generator);
+
+ if (EG(This)) {
+ Z_ADDREF_P(EG(This));
+ }
+
+ /* Back up executor globals. */
+ execute_data->current_scope = EG(scope);
+ execute_data->current_called_scope = EG(called_scope);
+ execute_data->symbol_table = EG(active_symbol_table);
+ execute_data->current_this = EG(This);
+
+ /* Save execution context in generator object. */
+ generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
+ generator->execute_data = execute_data;
+
+ /* We have to add another stack frame so the generator function shows
+ * up in backtraces and func_get_all() can access the function
+ * arguments. */
+ execute_data->prev_execute_data = emalloc(sizeof(zend_execute_data));
+ if (EG(current_execute_data)) {
+ memcpy(execute_data->prev_execute_data, EG(current_execute_data), sizeof(zend_execute_data));
+ execute_data->prev_execute_data->function_state.arguments = zend_copy_arguments(EG(current_execute_data)->function_state.arguments);
+ } else {
+ memset(execute_data->prev_execute_data, 0, sizeof(zend_execute_data));
+ execute_data->prev_execute_data->function_state.function = (zend_function *) op_array;
+ execute_data->prev_execute_data->function_state.arguments = NULL;
+ }
+
+ return return_value;
+}
+/* }}} */
+
static zend_function *zend_generator_get_constructor(zval *object TSRMLS_DC) /* {{{ */
{
zend_error(E_RECOVERABLE_ERROR, "The \"Generator\" class is reserved for internal use and cannot be manually instantiated");
@@ -377,9 +427,6 @@ static void zend_generator_resume(zend_generator *generator TSRMLS_DC) /* {{{ */
* set the prev_execute_data of that prev_execute_data :) */
generator->execute_data->prev_execute_data->prev_execute_data = original_execute_data;
- /* Go to next opcode (we don't want to run the last one again) */
- generator->execute_data->opline++;
-
/* Resume execution */
execute_ex(generator->execute_data TSRMLS_CC);
diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
index 73d85287a7..d67ea4137b 100644
--- a/Zend/zend_generators.h
+++ b/Zend/zend_generators.h
@@ -55,6 +55,7 @@ typedef struct _zend_generator {
extern ZEND_API zend_class_entry *zend_ce_generator;
void zend_register_generator_ce(TSRMLS_D);
+zval *zend_generator_create_zval(zend_op_array *op_array TSRMLS_CC);
void zend_generator_close(zend_generator *generator, zend_bool finished_execution TSRMLS_DC);
END_EXTERN_C()
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 02aa694c6e..b705d60d9a 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -360,11 +360,6 @@ class_declaration_statement:
unticked_class_declaration_statement { DO_TICKS(); }
;
-is_generator:
- /* empty */ { $$.op_type = 0; }
- | '*' { $$.op_type = 1; }
-;
-
is_reference:
/* empty */ { $$.op_type = ZEND_RETURN_VAL; }
| '&' { $$.op_type = ZEND_RETURN_REF; }
@@ -372,8 +367,8 @@ is_reference:
unticked_function_declaration_statement:
- function is_generator is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$4, 0, $2.op_type, $3.op_type, NULL TSRMLS_CC); }
- '(' parameter_list ')' { zend_do_suspend_if_generator(TSRMLS_C); }
+ function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
+ '(' parameter_list ')'
'{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); }
;
@@ -584,9 +579,9 @@ class_statement:
variable_modifiers { CG(access_type) = Z_LVAL($1.u.constant); } class_variable_declaration ';'
| class_constant_declaration ';'
| trait_use_statement
- | method_modifiers function is_generator is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$5, 1, $3.op_type, $4.op_type, &$1 TSRMLS_CC); }
- '(' parameter_list ')' { zend_do_suspend_if_generator(TSRMLS_C); }
- method_body { zend_do_abstract_method(&$5, &$1, &$11 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
+ | method_modifiers function is_reference T_STRING { zend_do_begin_function_declaration(&$2, &$4, 1, $3.op_type, &$1 TSRMLS_CC); }
+ '(' parameter_list ')'
+ method_body { zend_do_abstract_method(&$4, &$1, &$9 TSRMLS_CC); zend_do_end_function_declaration(&$2 TSRMLS_CC); }
;
trait_use_statement:
@@ -805,12 +800,12 @@ expr_without_variable:
| T_YIELD { zend_do_yield(&$$, NULL, NULL TSRMLS_CC); }
| T_YIELD expr { zend_do_yield(&$$, &$2, NULL TSRMLS_CC); }
| T_YIELD '*' expr { zend_do_delegate_yield(&$$, &$3 TSRMLS_CC); }
- | function is_generator is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, $3.op_type, 0 TSRMLS_CC); }
- '(' parameter_list ')' lexical_vars { zend_do_suspend_if_generator(TSRMLS_C); }
- '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $4; }
- | T_STATIC function is_generator is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, $4.op_type, 1 TSRMLS_CC); }
- '(' parameter_list ')' lexical_vars { zend_do_suspend_if_generator(TSRMLS_C); }
- '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $5; }
+ | function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$1, $2.op_type, 0 TSRMLS_CC); }
+ '(' parameter_list ')' lexical_vars
+ '{' inner_statement_list '}' { zend_do_end_function_declaration(&$1 TSRMLS_CC); $$ = $3; }
+ | T_STATIC function is_reference { zend_do_begin_lambda_function_declaration(&$$, &$2, $3.op_type, 1 TSRMLS_CC); }
+ '(' parameter_list ')' lexical_vars
+ '{' inner_statement_list '}' { zend_do_end_function_declaration(&$2 TSRMLS_CC); $$ = $4; }
;
combined_scalar_offset:
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 4be644a332..e8b89a6db5 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2705,7 +2705,11 @@ ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
}
- if (EXPECTED(zend_execute == execute)) {
+ if (EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ if (RETURN_VALUE_USED(opline)) {
+ EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
+ }
+ } else if (EXPECTED(zend_execute == execute)) {
if (EXPECTED(EG(exception) == NULL)) {
ZEND_VM_ENTER();
}
@@ -5218,102 +5222,7 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
ZEND_VM_NEXT_OPCODE();
}
-ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR, ANY, ANY)
-{
- zend_bool nested = EX(nested);
- zend_execute_data *prev_execute_data = EX(prev_execute_data);
-
- if (EG(return_value_ptr_ptr)) {
- zval *return_value;
- zend_generator *generator;
-
- ALLOC_INIT_ZVAL(return_value);
- object_init_ex(return_value, zend_ce_generator);
-
- *EG(return_value_ptr_ptr) = return_value;
-
- /* back up some executor globals */
- SAVE_OPLINE();
-
- EX(current_scope) = EG(scope);
- EX(current_called_scope) = EG(called_scope);
-
- if (EG(This)) {
- Z_ADDREF_P(EG(This));
- }
- EX(current_this) = EG(This);
-
- /* back up the execution context */
- generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
- generator->execute_data = execute_data;
-
- /* We have to add another stack frame so the generator function shows
- * up in backtraces and func_get_all() can access the function
- * arguments. */
- EX(prev_execute_data) = emalloc(sizeof(zend_execute_data));
- if (prev_execute_data) {
- memcpy(EX(prev_execute_data), prev_execute_data, sizeof(zend_execute_data));
- EX(prev_execute_data)->function_state.arguments = zend_copy_arguments(prev_execute_data->function_state.arguments);
- } else {
- memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
- EX(prev_execute_data)->function_state.function = (zend_function *) EX(op_array);
- EX(prev_execute_data)->function_state.arguments = NULL;
- }
- }
-
- /* restore the previous execution context */
- EG(current_execute_data) = prev_execute_data;
-
- /* if there is no return value pointer we are responsible for freeing the
- * execution data */
- if (!EG(return_value_ptr_ptr)) {
- if (!EG(active_symbol_table)) {
- zend_free_compiled_variables(EX_CVs(), execute_data->op_array->last_var);
- } else {
- zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
- }
- efree(execute_data);
- }
-
-
- /* Happens whenever the function is invoked using call_user_function,
- * e.g. when doing a dynamic function call using call_user_func(). */
- if (!nested) {
- EG(opline_ptr) = NULL;
- ZEND_VM_RETURN();
- }
-
- /* Free $this and stack arguments */
- if (EG(This)) {
- zval_ptr_dtor(&EG(This));
- }
-
- zend_vm_stack_clear_multiple(TSRMLS_C);
-
- /* Bring back the previous execution context */
- execute_data = EG(current_execute_data);
-
- EG(opline_ptr) = &EX(opline);
- EG(active_op_array) = EX(op_array);
- EG(return_value_ptr_ptr) = EX(original_return_value);
- EG(active_symbol_table) = EX(symbol_table);
- EG(This) = EX(current_this);
- EG(scope) = EX(current_scope);
- EG(called_scope) = EX(current_called_scope);
-
- EX(function_state).function = (zend_function *) EX(op_array);
- EX(function_state).arguments = NULL;
-
- EX(object) = EX(current_object);
- EX(called_scope) = DECODE_CTOR(EX(called_scope));
-
- LOAD_REGS();
- LOAD_OPLINE();
- ZEND_VM_INC_OPCODE();
- ZEND_VM_LEAVE();
-}
-
-ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
+ZEND_VM_HANDLER(159, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSED)
{
USE_OPLINE
zend_free_op free_op1;
@@ -5454,6 +5363,10 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -5461,7 +5374,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
ZEND_VM_RETURN();
}
-ZEND_VM_HANDLER(161, ZEND_DELEGATE_YIELD, CONST|TMP|VAR|CV, ANY)
+ZEND_VM_HANDLER(160, ZEND_DELEGATE_YIELD, CONST|TMP|VAR|CV, ANY)
{
ZEND_VM_NEXT_OPCODE();
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index b1bcd74d23..0fcae113ba 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -339,7 +339,7 @@ static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* o
#define EX_Ts() EX(Ts)
-static zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
+zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
zend_execute_data *execute_data;
/*
@@ -689,7 +689,11 @@ static int ZEND_FASTCALL zend_do_fcall_common_helper_SPEC(ZEND_OPCODE_HANDLER_AR
ret->var.fcall_returned_reference = (fbc->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0;
}
- if (EXPECTED(zend_execute == execute)) {
+ if (EG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
+ if (RETURN_VALUE_USED(opline)) {
+ EX_T(opline->result.var).var.ptr = zend_generator_create_zval(EG(active_op_array) TSRMLS_CC);
+ }
+ } else if (EXPECTED(zend_execute == execute)) {
if (EXPECTED(EG(exception) == NULL)) {
ZEND_VM_ENTER();
}
@@ -1201,101 +1205,6 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
}
}
-static int ZEND_FASTCALL ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
-{
- zend_bool nested = EX(nested);
- zend_execute_data *prev_execute_data = EX(prev_execute_data);
-
- if (EG(return_value_ptr_ptr)) {
- zval *return_value;
- zend_generator *generator;
-
- ALLOC_INIT_ZVAL(return_value);
- object_init_ex(return_value, zend_ce_generator);
-
- *EG(return_value_ptr_ptr) = return_value;
-
- /* back up some executor globals */
- SAVE_OPLINE();
-
- EX(current_scope) = EG(scope);
- EX(current_called_scope) = EG(called_scope);
-
- if (EG(This)) {
- Z_ADDREF_P(EG(This));
- }
- EX(current_this) = EG(This);
-
- /* back up the execution context */
- generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC);
- generator->execute_data = execute_data;
-
- /* We have to add another stack frame so the generator function shows
- * up in backtraces and func_get_all() can access the function
- * arguments. */
- EX(prev_execute_data) = emalloc(sizeof(zend_execute_data));
- if (prev_execute_data) {
- memcpy(EX(prev_execute_data), prev_execute_data, sizeof(zend_execute_data));
- EX(prev_execute_data)->function_state.arguments = zend_copy_arguments(prev_execute_data->function_state.arguments);
- } else {
- memset(EX(prev_execute_data), 0, sizeof(zend_execute_data));
- EX(prev_execute_data)->function_state.function = (zend_function *) EX(op_array);
- EX(prev_execute_data)->function_state.arguments = NULL;
- }
- }
-
- /* restore the previous execution context */
- EG(current_execute_data) = prev_execute_data;
-
- /* if there is no return value pointer we are responsible for freeing the
- * execution data */
- if (!EG(return_value_ptr_ptr)) {
- if (!EG(active_symbol_table)) {
- zend_free_compiled_variables(EX_CVs(), execute_data->op_array->last_var);
- } else {
- zend_clean_and_cache_symbol_table(EG(active_symbol_table) TSRMLS_CC);
- }
- efree(execute_data);
- }
-
-
- /* Happens whenever the function is invoked using call_user_function,
- * e.g. when doing a dynamic function call using call_user_func(). */
- if (!nested) {
- EG(opline_ptr) = NULL;
- ZEND_VM_RETURN();
- }
-
- /* Free $this and stack arguments */
- if (EG(This)) {
- zval_ptr_dtor(&EG(This));
- }
-
- zend_vm_stack_clear_multiple(TSRMLS_C);
-
- /* Bring back the previous execution context */
- execute_data = EG(current_execute_data);
-
- EG(opline_ptr) = &EX(opline);
- EG(active_op_array) = EX(op_array);
- EG(return_value_ptr_ptr) = EX(original_return_value);
- EG(active_symbol_table) = EX(symbol_table);
- EG(This) = EX(current_this);
- EG(scope) = EX(current_scope);
- EG(called_scope) = EX(current_called_scope);
-
- EX(function_state).function = (zend_function *) EX(op_array);
- EX(function_state).arguments = NULL;
-
- EX(object) = EX(current_object);
- EX(called_scope) = DECODE_CTOR(EX(called_scope));
-
- LOAD_REGS();
- LOAD_OPLINE();
- ZEND_VM_INC_OPCODE();
- ZEND_VM_LEAVE();
-}
-
static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -4252,6 +4161,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -4937,6 +4850,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -5948,6 +5865,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -6652,6 +6573,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -7396,6 +7321,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -9448,6 +9377,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -10133,6 +10066,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -11144,6 +11081,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -11714,6 +11655,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -12396,6 +12341,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -16306,6 +16255,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -18379,6 +18332,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -20833,6 +20790,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -21964,6 +21925,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -24086,6 +24051,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -25565,6 +25534,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -26868,6 +26841,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -28172,6 +28149,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -28586,6 +28567,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -29886,6 +29871,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -33395,6 +33384,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -35337,6 +35330,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -37659,6 +37656,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -38649,6 +38650,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -40639,6 +40644,10 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
Z_ADDREF(EG(uninitialized_zval));
AI_SET_PTR(&EX_T(opline->result.var), &EG(uninitialized_zval));
+ /* We increment to the next op, so we are at the correct position when the
+ * generator is resumed. */
+ ZEND_VM_INC_OPCODE();
+
/* The GOTO VM uses a local opline variable. We need to set the opline
* variable in execute_data so we don't resume at an old position. */
SAVE_OPLINE();
@@ -44630,31 +44639,6 @@ void zend_init_opcodes_handlers(void)
ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
ZEND_JMP_SET_VAR_SPEC_CV_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
- ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER,
ZEND_YIELD_SPEC_CONST_CONST_HANDLER,
ZEND_YIELD_SPEC_CONST_TMP_HANDLER,
ZEND_YIELD_SPEC_CONST_VAR_HANDLER,
diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl
index e77c7cb3c6..909ec8ad7a 100644
--- a/Zend/zend_vm_execute.skl
+++ b/Zend/zend_vm_execute.skl
@@ -1,6 +1,6 @@
{%DEFINES%}
-static zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
+zend_execute_data *zend_create_execute_data_from_op_array(zend_op_array *op_array, zend_bool nested TSRMLS_DC) {
zend_execute_data *execute_data;
/*
diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h
index 46a711d179..87fabfc2ac 100644
--- a/Zend/zend_vm_opcodes.h
+++ b/Zend/zend_vm_opcodes.h
@@ -159,6 +159,5 @@
#define ZEND_SEPARATE 156
#define ZEND_QM_ASSIGN_VAR 157
#define ZEND_JMP_SET_VAR 158
-#define ZEND_SUSPEND_AND_RETURN_GENERATOR 159
-#define ZEND_YIELD 160
-#define ZEND_DELEGATE_YIELD 161
+#define ZEND_YIELD 159
+#define ZEND_DELEGATE_YIELD 160