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).
This commit is contained in:
Nikita Popov 2012-07-20 00:49:50 +02:00
parent 85f077cea1
commit c9709bfbd7
45 changed files with 247 additions and 324 deletions

View file

@ -3,7 +3,7 @@ Generator keys are auto-incrementing by default
--FILE--
<?php
function *gen() {
function gen() {
yield 'foo';
yield 'bar';
yield 5 => 'rab';

View file

@ -7,8 +7,9 @@ function f1() {
debug_print_backtrace();
}
function *f2($arg1, $arg2) {
function f2($arg1, $arg2) {
f1();
yield; // force generator
}
function f3($gen) {

View file

@ -3,7 +3,7 @@ Generators can be cloned
--FILE--
<?php
function *firstN($end) {
function firstN($end) {
for ($i = 0; $i < $end; ++$i) {
yield $i;
}

View file

@ -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;
}

View file

@ -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));
}

View file

@ -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';

View file

@ -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);

View file

@ -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;

View file

@ -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;
}

View file

@ -3,7 +3,8 @@ Generators cannot return values
--FILE--
<?php
function *gen() {
function gen() {
yield;
return $abc;
}

View file

@ -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) { }

View file

@ -3,7 +3,7 @@ A notice is thrown when yielding a constant value by reference
--FILE--
<?php
function *&gen() {
function &gen() {
yield "foo";
}

View file

@ -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

View file

@ -7,7 +7,7 @@ function foo() {
return "bar";
}
function *&gen() {
function &gen() {
yield foo();
}

View file

@ -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

View file

@ -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");

View file

@ -3,7 +3,7 @@ Generator can be closed by calling ->close()
--FILE--
<?php
function *allNumbers() {
function allNumbers() {
for ($i = 0; true; ++$i) {
yield $i;
}

View file

@ -10,7 +10,7 @@ class Test implements IteratorAggregate {
$this->data = $data;
}
public function *getIterator() {
public function getIterator() {
foreach ($this->data as $value) {
yield $value;
}

View file

@ -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;
}

View file

@ -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);
?>

View file

@ -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");
}

View file

@ -7,7 +7,7 @@ function throwException() {
throw new Exception('test');
}
function *gen() {
function gen() {
yield 'foo';
strlen("foo", "bar", throwException());
yield 'bar';

View file

@ -3,7 +3,7 @@ Generators can throw exceptions
--FILE--
<?php
function *gen() {
function gen() {
yield 'foo';
throw new Exception('test');
yield 'bar';

View file

@ -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);

View file

@ -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;
}

View file

@ -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"

View file

@ -3,7 +3,7 @@ $generator->send() returns the yielded value
--FILE--
<?php
function *reverseEchoGenerator() {
function reverseEchoGenerator() {
$data = yield;
while (true) {
$data = yield strrev($data);

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -3,7 +3,7 @@
--FILE--
<?php
function *gen() {
function gen() {
var_dump(str_repeat("x", yield));
}

View file

@ -9,7 +9,7 @@ class A {
}
}
function *gen() {
function gen() {
$a = new A;
$a->b(yield);
}

View file

@ -7,7 +7,7 @@ function &nop(&$var) {
return $var;
}
function *&gen(&$var) {
function &gen(&$var) {
yield nop($var);
}

View file

@ -3,7 +3,7 @@ yield can be used without a value
--FILE--
<?php
function *recv() {
function recv() {
while (true) {
var_dump(yield);
}

View file

@ -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++;

View file

@ -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);

View file

@ -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);

View file

@ -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));

View file

@ -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);

View file

@ -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()

View file

@ -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:

View file

@ -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();
}

View file

@ -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,

View file

@ -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;
/*

View file

@ -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