summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2015-02-19 20:17:37 +0100
committerNikita Popov <nikic@php.net>2015-03-17 21:51:53 +0100
commit5c230baf75fb17d1d0b8ec407a7479d02b25068a (patch)
tree866ca1a75f62398d13996c383f403a5e942a319e
parentf1a6c06f14834c0f3ef7769aef3917538f1f693b (diff)
downloadphp-git-5c230baf75fb17d1d0b8ec407a7479d02b25068a.tar.gz
Implement Generator::getReturn()
Conflicts: Zend/zend_vm_execute.h
-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.c32
-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, 523 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 f0aab0428d..1ec0539a71 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -186,6 +186,7 @@ static void zend_generator_free_storage(zend_object *object) /* {{{ */
zend_generator_close(generator, 0);
+ zval_ptr_dtor(&generator->retval);
zend_object_std_dtor(&generator->std);
if (generator->iterator) {
@@ -204,6 +205,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;
@@ -537,6 +540,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)
@@ -670,6 +701,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 fbfadfa871..526f9e2952 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -798,11 +798,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 079231b8cc..995fabc17d 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -3698,11 +3698,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);
@@ -6799,7 +6824,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);
}
@@ -6830,7 +6858,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);
}
@@ -7120,7 +7151,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 9dcf0ad462..3f7defc088 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -915,18 +915,6 @@ fcall_end:
ZEND_VM_NEXT_OPCODE();
}
-static ZEND_OPCODE_HANDLER_RET 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 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -1651,7 +1639,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_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);
}
@@ -1682,7 +1673,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_
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);
}
@@ -1758,7 +1752,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPC
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);
}
@@ -2895,6 +2892,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CONST_HANDL
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
+static ZEND_OPCODE_HANDLER_RET 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 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -10351,6 +10385,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_TMP_HANDLER
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
+static ZEND_OPCODE_HANDLER_RET 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 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -13157,6 +13228,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_VAR_HANDLER
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
+static ZEND_OPCODE_HANDLER_RET 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 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -26133,6 +26241,43 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_BY_REF_SPEC_CV_HANDLER(
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
}
+static ZEND_OPCODE_HANDLER_RET 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 ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@@ -45445,31 +45590,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,