diff options
| -rw-r--r-- | Zend/zend_generators.c | 28 | ||||
| -rw-r--r-- | Zend/zend_generators.h | 7 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 43 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 43 |
4 files changed, 112 insertions, 9 deletions
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 21581db2c0..d9ddd75ffb 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -25,15 +25,33 @@ ZEND_API zend_class_entry *zend_ce_generator; static zend_object_handlers zend_generator_handlers; -typedef struct _zend_generator { - zend_object std; - /* nothing more for now */ -} zend_generator; - static void zend_generator_free_storage(zend_generator *generator TSRMLS_DC) /* {{{ */ { zend_object_std_dtor(&generator->std TSRMLS_CC); + if (generator->execute_data) { + zend_execute_data *execute_data = generator->execute_data; + + if (!execute_data->symbol_table) { + int i; + for (i = 0; i < execute_data->op_array->last_var; ++i) { + if (execute_data->CVs[i]) { + zval_ptr_dtor(execute_data->CVs[i]); + } + } + } else { + if (EG(symtable_cache_ptr) >= EG(symtable_cache_limit)) { + zend_hash_destroy(execute_data->symbol_table); + FREE_HASHTABLE(execute_data->symbol_table); + } else { + zend_hash_clean(execute_data->symbol_table); + *(++EG(symtable_cache_ptr)) = execute_data->symbol_table; + } + } + + efree(execute_data); + } + efree(generator); } /* }}} */ diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index 60899072df..c3b8f455f6 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -27,6 +27,13 @@ void zend_register_generator_ce(TSRMLS_D); extern ZEND_API zend_class_entry *zend_ce_generator; +typedef struct _zend_generator { + zend_object std; + + /* The suspended execution context. */ + zend_execute_data *execute_data; +} zend_generator; + END_EXTERN_C() #endif diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 20b5633b8a..f4d16be7f9 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5203,17 +5203,56 @@ ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED) ZEND_VM_HANDLER(159, ZEND_SUSPEND_AND_RETURN_GENERATOR, ANY, ANY) { + zend_bool nested; + if (EG(return_value_ptr_ptr)) { zval *return_value; + zend_generator *generator; ALLOC_INIT_ZVAL(return_value); object_init_ex(return_value, zend_ce_generator); *EG(return_value_ptr_ptr) = return_value; + + /* back up the execution context */ + generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC); + generator->execute_data = execute_data; } - /* for now we just do a normal return without suspension */ - ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); + /* restore the previous execution context */ + EG(current_execute_data) = EX(prev_execute_data); + nested = EX(nested); + + /* if there is no return value pointer we are responsible for freeing the + * execution data */ + if (!EG(return_value_ptr_ptr)) { + /* something has to be done in here, not sure yet what exactly */ + } + + EG(opline_ptr) = NULL; + if (nested) { + /* so we can use EX() again */ + execute_data = EG(current_execute_data); + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = EX(op_array); + EG(return_value_ptr_ptr) = EX(original_return_value); + EG(active_symbol_table) = EX(symbol_table); + EG(This) = EX(current_this); + EG(scope) = EX(current_scope); + EG(called_scope) = EX(current_called_scope); + + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + + EX(object) = EX(current_object); + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + + zend_vm_stack_clear_multiple(TSRMLS_C); + } + + ZEND_VM_INC_OPCODE(); + ZEND_VM_LEAVE(); } ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper) diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d351067cb7..8316a0afb1 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1188,17 +1188,56 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS static int ZEND_FASTCALL ZEND_SUSPEND_AND_RETURN_GENERATOR_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { + zend_bool nested; + if (EG(return_value_ptr_ptr)) { zval *return_value; + zend_generator *generator; ALLOC_INIT_ZVAL(return_value); object_init_ex(return_value, zend_ce_generator); *EG(return_value_ptr_ptr) = return_value; + + /* back up the execution context */ + generator = (zend_generator *) zend_object_store_get_object(return_value TSRMLS_CC); + generator->execute_data = execute_data; } - /* for now we just do a normal return without suspension */ - return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); + /* restore the previous execution context */ + EG(current_execute_data) = EX(prev_execute_data); + nested = EX(nested); + + /* if there is no return value pointer we are responsible for freeing the + * execution data */ + if (!EG(return_value_ptr_ptr)) { + /* something has to be done in here, not sure yet what exactly */ + } + + EG(opline_ptr) = NULL; + if (nested) { + /* so we can use EX() again */ + execute_data = EG(current_execute_data); + + EG(opline_ptr) = &EX(opline); + EG(active_op_array) = EX(op_array); + EG(return_value_ptr_ptr) = EX(original_return_value); + EG(active_symbol_table) = EX(symbol_table); + EG(This) = EX(current_this); + EG(scope) = EX(current_scope); + EG(called_scope) = EX(current_called_scope); + + EX(function_state).function = (zend_function *) EX(op_array); + EX(function_state).arguments = NULL; + + EX(object) = EX(current_object); + EX(called_scope) = DECODE_CTOR(EX(called_scope)); + + zend_vm_stack_clear_multiple(TSRMLS_C); + } + + ZEND_VM_INC_OPCODE(); + ZEND_VM_LEAVE(); } static int ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) |
