diff options
| author | Nikita Popov <nikic@php.net> | 2012-05-23 14:20:25 +0200 | 
|---|---|---|
| committer | Nikita Popov <nikic@php.net> | 2012-05-23 14:20:25 +0200 | 
| commit | 9ce9a7e639bbb6c1c4bb34d542d2ac4e42e9457e (patch) | |
| tree | afbfe199e50e22ab3baac97a38a43d0faf8e8236 | |
| parent | 5e763d9420cbccbd8ee4f14a263b2439e6c5ae88 (diff) | |
| download | php-git-9ce9a7e639bbb6c1c4bb34d542d2ac4e42e9457e.tar.gz | |
Add initial code for suspending execution
This is just some initial code, which is still quite broken (and needs to be
moved so it can be reused.)
| -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) | 
