summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-02-19 20:17:37 +0100
committerNikita Popov <nikic@php.net>2015-02-19 20:25:49 +0100
commit79f26e9ca562cc4e692913432299cb9bbf906478 (patch)
treed333901d478f18e628d9cd1884c097e69fe64053 /Zend
parentd428bf2d4edab232690b64977aaf0a3b15585843 (diff)
downloadphp-git-79f26e9ca562cc4e692913432299cb9bbf906478.tar.gz
Implement Generator::getReturn()
Diffstat (limited to 'Zend')
-rw-r--r--Zend/tests/generators/errors/generator_cannot_return_before_yield_error.phpt13
-rw-r--r--Zend/tests/generators/errors/generator_cannot_return_error.phpt13
-rw-r--r--Zend/tests/generators/get_return.phpt81
-rw-r--r--Zend/tests/generators/get_return_and_finally.phpt47
-rw-r--r--Zend/tests/generators/get_return_errors.phpt79
-rw-r--r--Zend/tests/generators/get_return_types.phpt59
-rw-r--r--Zend/zend_generators.c35
-rw-r--r--Zend/zend_generators.h2
-rw-r--r--Zend/zend_opcode.c5
-rw-r--r--Zend/zend_vm_def.h42
-rw-r--r--Zend/zend_vm_execute.h225
11 files changed, 526 insertions, 75 deletions
diff --git a/Zend/tests/generators/errors/generator_cannot_return_before_yield_error.phpt b/Zend/tests/generators/errors/generator_cannot_return_before_yield_error.phpt
deleted file mode 100644
index ad618d20ba..0000000000
--- a/Zend/tests/generators/errors/generator_cannot_return_before_yield_error.phpt
+++ /dev/null
@@ -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
diff --git a/Zend/tests/generators/errors/generator_cannot_return_error.phpt b/Zend/tests/generators/errors/generator_cannot_return_error.phpt
deleted file mode 100644
index 51149062a7..0000000000
--- a/Zend/tests/generators/errors/generator_cannot_return_error.phpt
+++ /dev/null
@@ -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
diff --git a/Zend/tests/generators/get_return.phpt b/Zend/tests/generators/get_return.phpt
new file mode 100644
index 0000000000..c996eb4101
--- /dev/null
+++ b/Zend/tests/generators/get_return.phpt
@@ -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
diff --git a/Zend/tests/generators/get_return_and_finally.phpt b/Zend/tests/generators/get_return_and_finally.phpt
new file mode 100644
index 0000000000..150e5b83c4
--- /dev/null
+++ b/Zend/tests/generators/get_return_and_finally.phpt
@@ -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
diff --git a/Zend/tests/generators/get_return_errors.phpt b/Zend/tests/generators/get_return_errors.phpt
new file mode 100644
index 0000000000..f8d50aa3de
--- /dev/null
+++ b/Zend/tests/generators/get_return_errors.phpt
@@ -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
diff --git a/Zend/tests/generators/get_return_types.phpt b/Zend/tests/generators/get_return_types.phpt
new file mode 100644
index 0000000000..fa7f286814
--- /dev/null
+++ b/Zend/tests/generators/get_return_types.phpt
@@ -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)
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index 971d4e7bc8..7ebbca1030 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -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
};
diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
index 91408ea4b1..2e70bc5a2f 100644
--- a/Zend/zend_generators.h
+++ b/Zend/zend_generators.h
@@ -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 */
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index c1e3adb3ec..e44e586d9c 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -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;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 0285f77038..76d7f4774c 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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);
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 1e1f62e16e..8e7094fed7 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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,