From 247bb737d552508829c5de7770ed0b15c3d8f7fd Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 27 May 2012 03:50:31 +0200 Subject: [PATCH] Add support for generator methods --- Zend/zend_generators.c | 63 +++++++++++++++++++++++++++--------------- Zend/zend_vm_def.h | 5 ++++ Zend/zend_vm_execute.h | 5 ++++ 3 files changed, 51 insertions(+), 22 deletions(-) diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 36a9727722d51..ae706f19a5799 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -48,6 +48,10 @@ void zend_generator_close(zend_generator *generator TSRMLS_DC) /* {{{ */ } } + if (execute_data->current_this) { + zval_ptr_dtor(&execute_data->current_this); + } + efree(execute_data); generator->execute_data = NULL; } @@ -105,28 +109,43 @@ static void zend_generator_resume(zval *object, zend_generator *generator TSRMLS return; } - /* Backup executor globals */ - zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); - zend_op **original_opline_ptr = EG(opline_ptr); - zend_op_array *original_active_op_array = EG(active_op_array); - - /* We (mis) use the return_value_ptr_ptr to provide the generator object - * to the executor. This way YIELD will be able to set the yielded value */ - EG(return_value_ptr_ptr) = &object; - - EG(opline_ptr) = &generator->execute_data->opline; - EG(active_op_array) = generator->execute_data->op_array; - - /* Go to next opcode (we don't want to run the last one again) */ - generator->execute_data->opline++; - - /* Resume execution */ - execute_ex(generator->execute_data TSRMLS_CC); - - /* Restore executor globals */ - EG(return_value_ptr_ptr) = original_return_value_ptr_ptr; - EG(opline_ptr) = original_opline_ptr; - EG(active_op_array) = original_active_op_array; + { + /* Backup executor globals */ + zval **original_return_value_ptr_ptr = EG(return_value_ptr_ptr); + zend_op **original_opline_ptr = EG(opline_ptr); + zend_op_array *original_active_op_array = EG(active_op_array); + HashTable *original_active_symbol_table = EG(active_symbol_table); + zval *original_This = EG(This); + zend_class_entry *original_scope = EG(scope); + zend_class_entry *original_called_scope = EG(called_scope); + + /* We (mis)use the return_value_ptr_ptr to provide the generator object + * to the executor, so YIELD will be able to set the yielded value */ + EG(return_value_ptr_ptr) = &object; + + /* Set executor globals */ + EG(opline_ptr) = &generator->execute_data->opline; + EG(active_op_array) = generator->execute_data->op_array; + EG(active_symbol_table) = generator->execute_data->symbol_table; + EG(This) = generator->execute_data->current_this; + EG(scope) = generator->execute_data->current_scope; + EG(called_scope) = generator->execute_data->current_called_scope; + + /* Go to next opcode (we don't want to run the last one again) */ + generator->execute_data->opline++; + + /* Resume execution */ + execute_ex(generator->execute_data TSRMLS_CC); + + /* Restore executor globals */ + EG(return_value_ptr_ptr) = original_return_value_ptr_ptr; + EG(opline_ptr) = original_opline_ptr; + EG(active_op_array) = original_active_op_array; + EG(active_symbol_table) = original_active_symbol_table; + EG(This) = original_This; + EG(scope) = original_scope; + EG(called_scope) = original_called_scope; + } } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 781bd9fdd1c43..42397ed278d56 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5225,6 +5225,11 @@ ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR, ANY, ANY) *EG(return_value_ptr_ptr) = return_value; + /* back up some executor globals */ + EX(current_this) = EG(This); + EX(current_scope) = EG(scope); + EX(current_called_scope) = EG(called_scope); + /* back up the execution context */ generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC); generator->execute_data = execute_data; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 1eac10512d7c4..fa802c652b645 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1207,6 +1207,11 @@ static int ZEND_FASTCALL ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER(ZEND_OP *EG(return_value_ptr_ptr) = return_value; + /* back up some executor globals */ + EX(current_this) = EG(This); + EX(current_scope) = EG(scope); + EX(current_called_scope) = EG(called_scope); + /* back up the execution context */ generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC); generator->execute_data = execute_data;