diff options
author | Nikita Popov <nikic@php.net> | 2012-07-20 00:49:50 +0200 |
---|---|---|
committer | Nikita Popov <nikic@php.net> | 2012-07-20 16:09:06 +0200 |
commit | c9709bfbd7a71a42e0472abaf9c7d30598e264bf (patch) | |
tree | 995cb4d438093a87c887f1de4319be4d49a05136 | |
parent | 85f077cea13b3cb4927453b8a2f8ce51a9461bbb (diff) | |
download | php-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).
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 |