Fixed calling generators through magic __call()
authorDmitry Stogov <dmitry@zend.com>
Mon, 28 Nov 2016 09:20:19 +0000 (12:20 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 28 Nov 2016 09:20:19 +0000 (12:20 +0300)
Zend/tests/generators/generator_trampoline.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/generators/generator_trampoline.phpt b/Zend/tests/generators/generator_trampoline.phpt
new file mode 100644 (file)
index 0000000..a98dc9e
--- /dev/null
@@ -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)
index 6693ef316ff11d4526c6dc44d5c0a04ad340b74a..fdce0f973f54568b21b7d5d4ec7aa808fc05f373 100644 (file)
@@ -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;
index 2c90e0073ee28ee381cb2b93204ca7eb36e92ec7..c97525e0f41e54686f75bb4054de792f548b345a 100644 (file)
@@ -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;