mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
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:
parent
85f077cea1
commit
c9709bfbd7
45 changed files with 247 additions and 324 deletions
|
@ -3,7 +3,7 @@ Generator keys are auto-incrementing by default
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
yield 'foo';
|
||||
yield 'bar';
|
||||
yield 5 => 'rab';
|
||||
|
|
|
@ -7,8 +7,9 @@ function f1() {
|
|||
debug_print_backtrace();
|
||||
}
|
||||
|
||||
function *f2($arg1, $arg2) {
|
||||
function f2($arg1, $arg2) {
|
||||
f1();
|
||||
yield; // force generator
|
||||
}
|
||||
|
||||
function f3($gen) {
|
||||
|
|
|
@ -3,7 +3,7 @@ Generators can be cloned
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *firstN($end) {
|
||||
function firstN($end) {
|
||||
for ($i = 0; $i < $end; ++$i) {
|
||||
yield $i;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,8 @@ Generators cannot return values
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
yield;
|
||||
return $abc;
|
||||
}
|
||||
|
||||
|
|
|
@ -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) { }
|
||||
|
|
|
@ -3,7 +3,7 @@ A notice is thrown when yielding a constant value by reference
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *&gen() {
|
||||
function &gen() {
|
||||
yield "foo";
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -7,7 +7,7 @@ function foo() {
|
|||
return "bar";
|
||||
}
|
||||
|
||||
function *&gen() {
|
||||
function &gen() {
|
||||
yield foo();
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -3,7 +3,7 @@ Generator can be closed by calling ->close()
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *allNumbers() {
|
||||
function allNumbers() {
|
||||
for ($i = 0; true; ++$i) {
|
||||
yield $i;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class Test implements IteratorAggregate {
|
|||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function *getIterator() {
|
||||
public function getIterator() {
|
||||
foreach ($this->data as $value) {
|
||||
yield $value;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
?>
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ function throwException() {
|
|||
throw new Exception('test');
|
||||
}
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
yield 'foo';
|
||||
strlen("foo", "bar", throwException());
|
||||
yield 'bar';
|
||||
|
|
|
@ -3,7 +3,7 @@ Generators can throw exceptions
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
yield 'foo';
|
||||
throw new Exception('test');
|
||||
yield 'bar';
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -3,7 +3,7 @@ $generator->send() returns the yielded value
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *reverseEchoGenerator() {
|
||||
function reverseEchoGenerator() {
|
||||
$data = yield;
|
||||
while (true) {
|
||||
$data = yield strrev($data);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
var_dump(str_repeat("x", yield));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class A {
|
|||
}
|
||||
}
|
||||
|
||||
function *gen() {
|
||||
function gen() {
|
||||
$a = new A;
|
||||
$a->b(yield);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ function &nop(&$var) {
|
|||
return $var;
|
||||
}
|
||||
|
||||
function *&gen(&$var) {
|
||||
function &gen(&$var) {
|
||||
yield nop($var);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ yield can be used without a value
|
|||
--FILE--
|
||||
<?php
|
||||
|
||||
function *recv() {
|
||||
function recv() {
|
||||
while (true) {
|
||||
var_dump(yield);
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue