diff options
author | Dmitry Stogov <dmitry@zend.com> | 2016-11-28 12:20:19 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2016-11-28 12:20:19 +0300 |
commit | 970f21be97980a18153f13d653f4132cce676158 (patch) | |
tree | d6ea2a79e8c1d0cb76fa8505ee23b9273a02f45a | |
parent | fe04f5494a0c1ae393ef55642a797c0a8df8d8f2 (diff) | |
download | php-git-970f21be97980a18153f13d653f4132cce676158.tar.gz |
Fixed calling generators through magic __call()
-rw-r--r-- | Zend/tests/generators/generator_trampoline.phpt | 24 | ||||
-rw-r--r-- | Zend/zend_vm_def.h | 30 | ||||
-rw-r--r-- | Zend/zend_vm_execute.h | 30 |
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; |