summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2016-11-28 12:20:19 +0300
committerDmitry Stogov <dmitry@zend.com>2016-11-28 12:20:19 +0300
commit970f21be97980a18153f13d653f4132cce676158 (patch)
treed6ea2a79e8c1d0cb76fa8505ee23b9273a02f45a
parentfe04f5494a0c1ae393ef55642a797c0a8df8d8f2 (diff)
downloadphp-git-970f21be97980a18153f13d653f4132cce676158.tar.gz
Fixed calling generators through magic __call()
-rw-r--r--Zend/tests/generators/generator_trampoline.phpt24
-rw-r--r--Zend/zend_vm_def.h30
-rw-r--r--Zend/zend_vm_execute.h30
3 files changed, 64 insertions, 20 deletions
diff --git a/Zend/tests/generators/generator_trampoline.phpt b/Zend/tests/generators/generator_trampoline.phpt
new file mode 100644
index 0000000000..a98dc9ee49
--- /dev/null
+++ b/Zend/tests/generators/generator_trampoline.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Calling generator through magic __call()
+--FILE--
+<?php
+class A {
+ public function __call($name, $args) {
+ for ($i = 0; $i < 5; $i++) {
+ yield $i;
+ }
+ }
+}
+
+$a = new A();
+foreach ($a->gen() as $n) {
+ var_dump($n);
+}
+$a->gen();
+?>
+--EXPECT--
+int(0)
+int(1)
+int(2)
+int(3)
+int(4)
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 6693ef316f..fdce0f973f 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -7928,17 +7928,27 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
- ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
-
- call->symbol_table = NULL;
- i_init_func_execute_data(call, &fbc->op_array,
- ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
-
- if (EXPECTED(zend_execute_ex == execute_ex)) {
- ZEND_VM_ENTER();
+ if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
+ if (ret) {
+ zend_generator_create_zval(call, &fbc->op_array, ret);
+ Z_VAR_FLAGS_P(ret) = 0;
+ } else {
+ if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
+ }
+ zend_vm_stack_free_args(call);
+ }
} else {
- ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
- zend_execute_ex(call);
+ call->symbol_table = NULL;
+ i_init_func_execute_data(call, &fbc->op_array,
+ ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
+
+ if (EXPECTED(zend_execute_ex == execute_ex)) {
+ ZEND_VM_ENTER();
+ } else {
+ ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
+ zend_execute_ex(call);
+ }
}
} else {
zval retval;
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 2c90e0073e..c97525e0f4 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1737,17 +1737,27 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
if (EXPECTED(fbc->type == ZEND_USER_FUNCTION)) {
- ZEND_ASSERT(!(fbc->common.fn_flags & ZEND_ACC_GENERATOR));
-
- call->symbol_table = NULL;
- i_init_func_execute_data(call, &fbc->op_array,
- ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
-
- if (EXPECTED(zend_execute_ex == execute_ex)) {
- ZEND_VM_ENTER();
+ if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_GENERATOR) != 0)) {
+ if (ret) {
+ zend_generator_create_zval(call, &fbc->op_array, ret);
+ Z_VAR_FLAGS_P(ret) = 0;
+ } else {
+ if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_CLOSURE)) {
+ OBJ_RELEASE((zend_object*)fbc->op_array.prototype);
+ }
+ zend_vm_stack_free_args(call);
+ }
} else {
- ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
- zend_execute_ex(call);
+ call->symbol_table = NULL;
+ i_init_func_execute_data(call, &fbc->op_array,
+ ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0);
+
+ if (EXPECTED(zend_execute_ex == execute_ex)) {
+ ZEND_VM_ENTER();
+ } else {
+ ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
+ zend_execute_ex(call);
+ }
}
} else {
zval retval;