mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Implement Generator::getReturn()
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
--TEST--
|
||||
Generators cannot return values (even before yield)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
return $foo;
|
||||
yield;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Generators cannot return values using "return" in %s on line 4
|
||||
@@ -1,13 +0,0 @@
|
||||
--TEST--
|
||||
Generators cannot return values
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen() {
|
||||
yield;
|
||||
return $abc;
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: Generators cannot return values using "return" in %s on line 5
|
||||
81
Zend/tests/generators/get_return.phpt
Normal file
81
Zend/tests/generators/get_return.phpt
Normal file
@@ -0,0 +1,81 @@
|
||||
--TEST--
|
||||
Generator::getReturn() success cases
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen1() {
|
||||
return 42;
|
||||
yield 24;
|
||||
}
|
||||
|
||||
$gen = gen1();
|
||||
// Calling getReturn() directly here is okay due to auto-priming
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen2() {
|
||||
yield 24;
|
||||
return 42;
|
||||
}
|
||||
|
||||
$gen = gen2();
|
||||
var_dump($gen->current());
|
||||
$gen->next();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
// & for generators specifies by-reference yield, not return
|
||||
// so it's okay to return a literal
|
||||
function &gen3() {
|
||||
$var = 24;
|
||||
yield $var;
|
||||
return 42;
|
||||
}
|
||||
|
||||
$gen = gen3();
|
||||
var_dump($gen->current());
|
||||
$gen->next();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
// Return types for generators specify the return of the function,
|
||||
// not of the generator return value, so this code is okay
|
||||
function gen4() : Generator {
|
||||
yield 24;
|
||||
return 42;
|
||||
}
|
||||
|
||||
$gen = gen4();
|
||||
var_dump($gen->current());
|
||||
$gen->next();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
// Has no explicit return, but implicitly return NULL at the end
|
||||
function gen5() {
|
||||
yield 24;
|
||||
}
|
||||
|
||||
$gen = gen5();
|
||||
var_dump($gen->current());
|
||||
$gen->next();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
// Explicit value-less return also results in a NULL generator
|
||||
// return value and there is no interference with type hints
|
||||
function gen6() : Generator {
|
||||
return;
|
||||
yield 24;
|
||||
}
|
||||
|
||||
$gen = gen6();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
int(42)
|
||||
int(24)
|
||||
int(42)
|
||||
int(24)
|
||||
int(42)
|
||||
int(24)
|
||||
int(42)
|
||||
int(24)
|
||||
NULL
|
||||
NULL
|
||||
47
Zend/tests/generators/get_return_and_finally.phpt
Normal file
47
Zend/tests/generators/get_return_and_finally.phpt
Normal file
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
Test interaction of Generator::getReturn() and finally
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen1() {
|
||||
try {
|
||||
throw new Exception("gen1() throw");
|
||||
} finally {
|
||||
return 42;
|
||||
}
|
||||
yield;
|
||||
}
|
||||
|
||||
// The exception was discarded, so this works
|
||||
$gen = gen1();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen2() {
|
||||
try {
|
||||
return 42;
|
||||
} finally {
|
||||
throw new Exception("gen2() throw");
|
||||
}
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen2();
|
||||
try {
|
||||
// This will throw an exception (from the finally)
|
||||
// during auto-priming, so fails
|
||||
var_dump($gen->getReturn());
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
// This fails, because the return value was discarded
|
||||
var_dump($gen->getReturn());
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(42)
|
||||
gen2() throw
|
||||
Cannot get return value of a generator that hasn't returned
|
||||
79
Zend/tests/generators/get_return_errors.phpt
Normal file
79
Zend/tests/generators/get_return_errors.phpt
Normal file
@@ -0,0 +1,79 @@
|
||||
--TEST--
|
||||
Generator::getReturn() error cases
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen1() {
|
||||
yield 1;
|
||||
yield 2;
|
||||
return 3;
|
||||
}
|
||||
|
||||
$gen = gen1();
|
||||
try {
|
||||
// Generator hasn't reached the "return" yet
|
||||
$gen->getReturn();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
function gen2() {
|
||||
throw new Exception("gen2() throw");
|
||||
yield 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
$gen = gen2();
|
||||
try {
|
||||
$gen->next();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
// Generator has been aborted as a result of an exception
|
||||
$gen->getReturn();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
function gen3() {
|
||||
throw new Exception("gen3() throw");
|
||||
return 1;
|
||||
yield 2;
|
||||
}
|
||||
|
||||
$gen = gen3();
|
||||
try {
|
||||
// Generator throws during auto-priming of getReturn() call
|
||||
$gen->getReturn();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
function gen4() {
|
||||
yield;
|
||||
return 1;
|
||||
}
|
||||
|
||||
$gen = gen4();
|
||||
try {
|
||||
$gen->throw(new Exception("gen4() throw"));
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
try {
|
||||
// Generator has been aborted as a result of an exception
|
||||
// that was injected using throw()
|
||||
$gen->getReturn();
|
||||
} catch (Exception $e) {
|
||||
echo $e->getMessage(), "\n";
|
||||
}
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
Cannot get return value of a generator that hasn't returned
|
||||
gen2() throw
|
||||
Cannot get return value of a generator that hasn't returned
|
||||
gen3() throw
|
||||
gen4() throw
|
||||
Cannot get return value of a generator that hasn't returned
|
||||
59
Zend/tests/generators/get_return_types.phpt
Normal file
59
Zend/tests/generators/get_return_types.phpt
Normal file
@@ -0,0 +1,59 @@
|
||||
--TEST--
|
||||
Test different types of generator return values (VM operands)
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function gen1() {
|
||||
return; // CONST
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen1();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen2() {
|
||||
return "str"; // CONST
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen2();
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen3($var) {
|
||||
return $var; // CV
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen3([1, 2, 3]);
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen4($obj) {
|
||||
return $obj->prop; // VAR
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen4((object) ['prop' => 321]);
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
function gen5($val) {
|
||||
return (int) $val; // TMP
|
||||
yield;
|
||||
}
|
||||
|
||||
$gen = gen5("42");
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
NULL
|
||||
string(3) "str"
|
||||
array(3) {
|
||||
[0]=>
|
||||
int(1)
|
||||
[1]=>
|
||||
int(2)
|
||||
[2]=>
|
||||
int(3)
|
||||
}
|
||||
int(321)
|
||||
int(42)
|
||||
@@ -186,6 +186,10 @@ static void zend_generator_free_storage(zend_object *object) /* {{{ */
|
||||
|
||||
zend_generator_close(generator, 0);
|
||||
|
||||
if (!Z_ISUNDEF(generator->retval)) {
|
||||
zval_ptr_dtor(&generator->retval);
|
||||
}
|
||||
|
||||
zend_object_std_dtor(&generator->std);
|
||||
|
||||
if (generator->iterator) {
|
||||
@@ -204,6 +208,8 @@ static zend_object *zend_generator_create(zend_class_entry *class_type) /* {{{ *
|
||||
/* The key will be incremented on first use, so it'll start at 0 */
|
||||
generator->largest_used_integer_key = -1;
|
||||
|
||||
ZVAL_UNDEF(&generator->retval);
|
||||
|
||||
zend_object_std_init(&generator->std, class_type);
|
||||
generator->std.handlers = &zend_generator_handlers;
|
||||
|
||||
@@ -535,6 +541,34 @@ ZEND_METHOD(Generator, throw)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto mixed Generator::getReturn()
|
||||
* Retrieves the return value of the generator */
|
||||
ZEND_METHOD(Generator, getReturn)
|
||||
{
|
||||
zend_generator *generator;
|
||||
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
generator = (zend_generator *) Z_OBJ_P(getThis());
|
||||
|
||||
zend_generator_ensure_initialized(generator);
|
||||
if (EG(exception)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Z_ISUNDEF(generator->retval)) {
|
||||
/* Generator hasn't returned yet -> error! */
|
||||
zend_throw_exception(NULL,
|
||||
"Cannot get return value of a generator that hasn't returned", 0);
|
||||
return;
|
||||
}
|
||||
|
||||
ZVAL_COPY(return_value, &generator->retval);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto void Generator::__wakeup()
|
||||
* Throws an Exception as generators can't be serialized */
|
||||
ZEND_METHOD(Generator, __wakeup)
|
||||
@@ -668,6 +702,7 @@ static const zend_function_entry generator_functions[] = {
|
||||
ZEND_ME(Generator, next, arginfo_generator_void, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Generator, send, arginfo_generator_send, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Generator, throw, arginfo_generator_throw, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Generator, getReturn,arginfo_generator_void, ZEND_ACC_PUBLIC)
|
||||
ZEND_ME(Generator, __wakeup, arginfo_generator_void, ZEND_ACC_PUBLIC)
|
||||
ZEND_FE_END
|
||||
};
|
||||
|
||||
@@ -40,6 +40,8 @@ typedef struct _zend_generator {
|
||||
zval value;
|
||||
/* Current key */
|
||||
zval key;
|
||||
/* Return value */
|
||||
zval retval;
|
||||
/* Variable to put sent value into */
|
||||
zval *send_target;
|
||||
/* Largest used integer key for auto-incrementing keys */
|
||||
|
||||
@@ -780,11 +780,6 @@ ZEND_API int pass_two(zend_op_array *op_array)
|
||||
case ZEND_RETURN:
|
||||
case ZEND_RETURN_BY_REF:
|
||||
if (op_array->fn_flags & ZEND_ACC_GENERATOR) {
|
||||
if (opline->op1_type != IS_CONST || Z_TYPE_P(RT_CONSTANT(op_array, opline->op1)) != IS_NULL) {
|
||||
CG(zend_lineno) = opline->lineno;
|
||||
zend_error_noreturn(E_COMPILE_ERROR, "Generators cannot return values using \"return\"");
|
||||
}
|
||||
|
||||
opline->opcode = ZEND_GENERATOR_RETURN;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -3076,11 +3076,36 @@ ZEND_VM_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY)
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, ANY, ANY)
|
||||
ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *retval;
|
||||
zend_free_op free_op1;
|
||||
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
SAVE_OPLINE();
|
||||
retval = GET_OP1_ZVAL_PTR(BP_VAR_R);
|
||||
|
||||
/* Copy return value into generator->retval */
|
||||
if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (OP1_TYPE == IS_CONST) {
|
||||
if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
|
||||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
FREE_OP1_IF_VAR();
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (OP1_TYPE == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
@@ -6085,7 +6110,10 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
@@ -6116,7 +6144,10 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, ANY, ANY)
|
||||
ZEND_VM_CONTINUE();
|
||||
case ZEND_USER_OPCODE_RETURN:
|
||||
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
@@ -6400,7 +6431,10 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
|
||||
@@ -675,18 +675,6 @@ fcall_end:
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
/* Pass execution back to handling code */
|
||||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -1396,7 +1384,10 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[catch_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
@@ -1427,7 +1418,10 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
|
||||
ZEND_VM_CONTINUE();
|
||||
case ZEND_USER_OPCODE_RETURN:
|
||||
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
@@ -1502,7 +1496,10 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
zend_generator_close(generator, 1);
|
||||
ZEND_VM_RETURN();
|
||||
} else {
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
@@ -2608,6 +2605,43 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *retval;
|
||||
|
||||
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
SAVE_OPLINE();
|
||||
retval = EX_CONSTANT(opline->op1);
|
||||
|
||||
/* Copy return value into generator->retval */
|
||||
if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_CONST == IS_CONST) {
|
||||
if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
|
||||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_CONST == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
/* Pass execution back to handling code */
|
||||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -8878,6 +8912,43 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *retval;
|
||||
zend_free_op free_op1;
|
||||
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
SAVE_OPLINE();
|
||||
retval = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
|
||||
|
||||
/* Copy return value into generator->retval */
|
||||
if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_TMP_VAR == IS_CONST) {
|
||||
if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
|
||||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_TMP_VAR == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
/* Pass execution back to handling code */
|
||||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -11555,6 +11626,43 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *retval;
|
||||
zend_free_op free_op1;
|
||||
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
SAVE_OPLINE();
|
||||
retval = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1);
|
||||
|
||||
/* Copy return value into generator->retval */
|
||||
if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_VAR == IS_CONST) {
|
||||
if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
|
||||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
zval_ptr_dtor_nogc(free_op1);
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_VAR == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
/* Pass execution back to handling code */
|
||||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -23874,6 +23982,43 @@ static int ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
zval *retval;
|
||||
|
||||
|
||||
/* The generator object is stored in EX(return_value) */
|
||||
zend_generator *generator = (zend_generator *) EX(return_value);
|
||||
|
||||
SAVE_OPLINE();
|
||||
retval = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var);
|
||||
|
||||
/* Copy return value into generator->retval */
|
||||
if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_CV == IS_CONST) {
|
||||
if (UNEXPECTED(Z_OPT_COPYABLE(generator->retval))) {
|
||||
zval_copy_ctor_func(&generator->retval);
|
||||
}
|
||||
}
|
||||
} else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(retval)) {
|
||||
ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval));
|
||||
|
||||
} else {
|
||||
ZVAL_COPY_VALUE(&generator->retval, retval);
|
||||
if (IS_CV == IS_CV) {
|
||||
if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the generator to free up resources */
|
||||
zend_generator_close(generator, 1);
|
||||
|
||||
/* Pass execution back to handling code */
|
||||
ZEND_VM_RETURN();
|
||||
}
|
||||
|
||||
static int ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
@@ -40838,31 +40983,31 @@ void zend_init_opcodes_handlers(void)
|
||||
ZEND_YIELD_SPEC_CV_VAR_HANDLER,
|
||||
ZEND_YIELD_SPEC_CV_UNUSED_HANDLER,
|
||||
ZEND_YIELD_SPEC_CV_CV_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CONST_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_TMP_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_VAR_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_NULL_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER,
|
||||
ZEND_GENERATOR_RETURN_SPEC_CV_HANDLER,
|
||||
ZEND_FAST_CALL_SPEC_HANDLER,
|
||||
ZEND_FAST_CALL_SPEC_HANDLER,
|
||||
ZEND_FAST_CALL_SPEC_HANDLER,
|
||||
|
||||
Reference in New Issue
Block a user