summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_generators.c28
-rw-r--r--Zend/zend_generators.h7
-rw-r--r--Zend/zend_vm_def.h43
-rw-r--r--Zend/zend_vm_execute.h43
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)