Hi,
The proposed patch for PHP improves the executor.
At first it eliminates direct execute() recursion so the following
script won't produce SIGSEGV anymore (It'll produce memory overflow
error instead).
<?php
function foo() {
foo();
}
foo();
?>
Note that in case some extension (e.q. xdebug) override zend_execute(),
VM will use recursive calls.
At second executor now uses "fastcall" calling convention, and as result
it gives ~5% speedup on bench.php (~3.8 sec instead of ~4.0 sec)
Any objections?
Thanks. Dmitry.
Out of curiosity, what's the slowdown without fastcall?
Despite the potential slowdown, I still think this is the way to go. The
engine isn't supposed to crash!
Nuno
----- Original Message -----
From: "Dmitry Stogov" dmitry@zend.com
To: "PHP Internals List" internals@lists.php.net
Cc: "Andi Gutmans" andi@zend.com; "Stanislav Malyshev" stas@zend.com
Sent: Tuesday, June 10, 2008 12:11 PM
Subject: [PHP-DEV] [PATCH] Executor improvements
Hi,
The proposed patch for PHP improves the executor.
At first it eliminates direct execute() recursion so the following
script won't produceSIGSEGVanymore (It'll produce memory overflow
error instead).<?php
function foo() {
foo();
}
foo();
?>Note that in case some extension (e.q. xdebug) override zend_execute(),
VM will use recursive calls.At second executor now uses "fastcall" calling convention, and as result
it gives ~5% speedup on bench.php (~3.8 sec instead of ~4.0 sec)Any objections?
Thanks. Dmitry.
Nuno Lopes wrote:
Out of curiosity, what's the slowdown without fastcall?
fastcall calling convention assumes passing parameters in registers
instead of pushing them on stack.
Thanks. Dmitry.
Despite the potential slowdown, I still think this is the way to go. The
engine isn't supposed to crash!
Nuno----- Original Message ----- From: "Dmitry Stogov" dmitry@zend.com
To: "PHP Internals List" internals@lists.php.net
Cc: "Andi Gutmans" andi@zend.com; "Stanislav Malyshev" stas@zend.com
Sent: Tuesday, June 10, 2008 12:11 PM
Subject: [PHP-DEV] [PATCH] Executor improvementsHi,
The proposed patch for PHP improves the executor.
At first it eliminates direct execute() recursion so the following
script won't produceSIGSEGVanymore (It'll produce memory overflow
error instead).<?php
function foo() {
foo();
}
foo();
?>Note that in case some extension (e.q. xdebug) override zend_execute(),
VM will use recursive calls.At second executor now uses "fastcall" calling convention, and as result
it gives ~5% speedup on bench.php (~3.8 sec instead of ~4.0 sec)Any objections?
Thanks. Dmitry.
Nuno Lopes wrote:
Out of curiosity, what's the slowdown without fastcall?
fastcall calling convention assumes passing parameters in registers
instead of pushing them on stack.
yeah, I know. I was asking what's the slowdown that this patch introduces
without the fastcall bits.
I'm asking this because you are mixing two different things on the same
patch. I was just curious on what's hidden in the patch.
Nuno
The recursion elimination itself doesn't show any significant speed
difference.
Thanks. Dmitry.
Nuno Lopes wrote:
Nuno Lopes wrote:
Out of curiosity, what's the slowdown without fastcall?
fastcall calling convention assumes passing parameters in registers
instead of pushing them on stack.yeah, I know. I was asking what's the slowdown that this patch
introduces without the fastcall bits.
I'm asking this because you are mixing two different things on the same
patch. I was just curious on what's hidden in the patch.Nuno
Dmitry Stogov wrote:
The proposed patch for PHP improves the executor.
ZEND_GCC_VERSION >= 3400 means >= GCC 3.4.0, right?
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Exactly. The "fastcall" attribute wasn't supported before.
Thanks. Dmitry.
Sebastian Bergmann wrote:
Dmitry Stogov wrote:
The proposed patch for PHP improves the executor.
ZEND_GCC_VERSION >= 3400 means >= GCC 3.4.0, right?
Dmitry Stogov wrote:
Exactly. The "fastcall" attribute wasn't supported before.
As 3.4 is quite old this should not be a problem. I somehow read 4.3
initially ;-)
--
Sebastian Bergmann http://sebastian-bergmann.de/
GnuPG Key: 0xB85B5D69 / 27A7 2B14 09E4 98CD 6277 0E5B 6867 C514 B85B 5D69
Tuesday, June 10, 2008, 1:11:57 PM, you wrote:
> Index: Zend/zend.h
> ===================================================================
> RCS file: /repository/ZendEngine2/zend.h,v
> retrieving revision 1.293.2.11.2.9.2.20
> diff -u -p -d -r1.293.2.11.2.9.2.20 zend.h
> --- Zend/zend.h 18 Mar 2008 21:14:27 -0000 1.293.2.11.2.9.2.20
> +++ Zend/zend.h 10 Jun 2008 10:53:48 -0000
> @@ -176,6 +176,12 @@ char *alloca ();
> # define ZEND_ATTRIBUTE_PTR_FORMAT(type, idx, first)
> #endif
>
> +#if defined(__GNUC__) && ZEND_GCC_VERSION >= 3400 && defined(__i386__)
> +# define ZEND_FASTCALL __attribute__((fastcall))
> +#else
> +# define ZEND_FASTCALL
> +#endif
Is this like __fastcall under windows? If so, please add it when _MSC_VER
is defined.
> +
> #if (HAVE_ALLOCA || (defined (__GNUC__) && __GNUC__ >= 2)) &&
> !(defined(ZTS) && defined(ZEND_WIN32)) && !(defined(ZTS) &&
> defined(NETWARE)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN)
> # define ZEND_ALLOCA_MAX_SIZE (32 * 1024)
> # define ALLOCA_FLAG(name) \
> Index: Zend/zend_compile.h
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_compile.h,v
> retrieving revision 1.316.2.8.2.12.2.24
> diff -u -p -d -r1.316.2.8.2.12.2.24 zend_compile.h
> --- Zend/zend_compile.h 12 May 2008 09:09:05 -0000 1.316.2.8.2.12.2.24
> +++ Zend/zend_compile.h 10 Jun 2008 10:53:48 -0000
> @@ -73,7 +73,8 @@ typedef struct _zend_execute_data zend_e
> #define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data TSRMLS_DC
> #define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data TSRMLS_CC
>
> -typedef int (*opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
> +typedef int (*user_opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
> +typedef int (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
>
> extern ZEND_API opcode_handler_t *zend_opcode_handlers;
>
> @@ -309,10 +310,16 @@ struct _zend_execute_data {
> zval *object;
> union _temp_variable *Ts;
> zval ***CVs;
> - zend_bool original_in_execution;
> HashTable *symbol_table;
> struct _zend_execute_data *prev_execute_data;
> zval *old_error_reporting;
> + zend_bool nested;
> + zval **original_return_value;
> + zend_class_entry *current_scope;
> + zend_class_entry *current_called_scope;
> + zval *current_this;
> + zval *current_object;
> + struct _zend_op *call_opline;
> };
>
> #define EX(element) execute_data.element
> Index: Zend/zend_execute.c
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_execute.c,v
> retrieving revision 1.716.2.12.2.24.2.29
> diff -u -p -d -r1.716.2.12.2.24.2.29 zend_execute.c
> --- Zend/zend_execute.c 9 May 2008 09:23:03 -0000 1.716.2.12.2.24.2.29
> +++ Zend/zend_execute.c 10 Jun 2008 10:53:48 -0000
> @@ -1314,29 +1314,9 @@ ZEND_API void execute_internal(zend_exec
> #define ZEND_VM_INC_OPCODE() \
> EX(opline)++
>
> -#define ZEND_VM_EXIT_FROM_EXECUTE_LOOP() do { \
> - EG(in_execution) = EX(original_in_execution); \
> - EG(current_execute_data) = EX(prev_execute_data); \
> - EG(opline_ptr) = NULL; \
> - if (!EG(active_symbol_table)) { \
> - int n = EX(op_array)->last_var; \
> - while (n > 0) { \
> - --n; \
> - if (EX(CVs)[n]) { \
> - zval_ptr_dtor(EX(CVs)[n]); \
> - } \
> - } \
> - } \
> - zend_vm_stack_free(execute_data TSRMLS_CC); \
> - } while (0);
> -
> -#define ZEND_VM_RETURN_FROM_EXECUTE_LOOP() \
> - ZEND_VM_EXIT_FROM_EXECUTE_LOOP() \
> - ZEND_VM_RETURN()
> -
> #include "zend_vm_execute.h"
>
> -ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, opcode_handler_t handler)
> +ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
> {
> if (opcode != ZEND_USER_OPCODE) {
> zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
> @@ -1346,7 +1326,7 @@ ZEND_API int zend_set_user_opcode_handle
> return FAILURE;
> }
>
> -ZEND_API opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
> +ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
> {
> return zend_user_opcode_handlers[opcode];
> }
> Index: Zend/zend_execute.h
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_execute.h,v
> retrieving revision 1.84.2.4.2.8.2.9
> diff -u -p -d -r1.84.2.4.2.8.2.9 zend_execute.h
> --- Zend/zend_execute.h 15 Apr 2008 15:52:36 -0000 1.84.2.4.2.8.2.9
> +++ Zend/zend_execute.h 10 Jun 2008 10:53:48 -0000
> @@ -331,8 +331,8 @@ ZEND_API zval** zend_get_compiled_variab
>
> #define ZEND_USER_OPCODE_DISPATCH_TO 0x100 /* call original handler of returned opcode */
>
> -ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, opcode_handler_t handler);
> -ZEND_API opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode);
> +ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler);
> +ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode);
>
> /* former zend_execute_locks.h */
> typedef struct _zend_free_op {
> Index: Zend/zend_vm_def.h
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_vm_def.h,v
> retrieving revision 1.59.2.29.2.48.2.57
> diff -u -p -d -r1.59.2.29.2.48.2.57 zend_vm_def.h
> --- Zend/zend_vm_def.h 3 Jun 2008 18:11:11 -0000 1.59.2.29.2.48.2.57
> +++ Zend/zend_vm_def.h 10 Jun 2008 10:53:49 -0000
> @@ -2073,15 +2073,116 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_B
> ZEND_VM_NEXT_OPCODE();
> }
>
> +ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
> +{
> + zend_bool nested;
> + zend_op_array *op_array = EX(op_array);
> +
> + EG(current_execute_data) = EX(prev_execute_data);
> + EG(opline_ptr) = NULL;
> + if (!EG(active_symbol_table)) {
> + zval ***cv = EX(CVs);
> + zval ***end = cv + EX(op_array)->last_var;
> + while (cv != end) {
> + if (*cv) {
> + zval_ptr_dtor(*cv);
> + }
> + cv++;
> + }
> + }
> +
> + nested = EX(nested);
> +
> + zend_vm_stack_free(execute_data TSRMLS_CC);
> +
> + if (nested) {
> + execute_data = EG(current_execute_data);
> +
> + if (EX(call_opline)->opcode == ZEND_INCLUDE_OR_EVAL) {
> +
> + EX(function_state).function = (zend_function *) EX(op_array);
> + EX(function_state).arguments = NULL;
> + EX(object) = EX(current_object);
> +
> + if (RETURN_VALUE_USED(EX(call_opline))) {
> + if
> (!EX_T(EX(call_opline)->result.u.var).var.ptr) { /* there was no return statement */
> +
> ALLOC_ZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr);
> +
> INIT_PZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr);
> +
> Z_LVAL_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = 1;
> +
> Z_TYPE_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = IS_BOOL;
> + }
> + }
> +
> + EG(opline_ptr) = &EX(opline);
> + EG(active_op_array) = EX(op_array);
> + EG(return_value_ptr_ptr) = EX(original_return_value);
> + destroy_op_array(op_array TSRMLS_CC);
> + efree(op_array);
> + if (EG(exception)) {
> + zend_throw_exception_internal(NULL TSRMLS_CC);
> + }
> +
> + EX(opline)++;
> + ZEND_VM_LEAVE();
> + } else {
> +
> + EG(opline_ptr) = &EX(opline);
> + EG(active_op_array) = EX(op_array);
> + EG(return_value_ptr_ptr) = EX(original_return_value);
> + if (EG(active_symbol_table)) {
> + if
> (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
> +
> zend_hash_destroy(EG(active_symbol_table));
> +
> FREE_HASHTABLE(EG(active_symbol_table));
> + } else {
> + /* clean before putting into the cache, since clean
> + could call dtors, which could use cached hash */
> +
> zend_hash_clean(EG(active_symbol_table));
> + *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
> + }
> + }
> + EG(active_symbol_table) = EX(symbol_table);
> +
> + EX(function_state).function = (zend_function *) EX(op_array);
> + EX(function_state).arguments = NULL;
> +
> + if (EG(This)) {
> + if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) {
> + if (IS_CTOR_USED(EX(called_scope))) {
> + Z_DELREF_P(EG(This));
> + }
> + if (Z_REFCOUNT_P(EG(This)) == 1) {
> +
> zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
> + }
> + }
> + zval_ptr_dtor(&EG(This));
> + }
> + EG(This) = EX(current_this);
> + EG(scope) = EX(current_scope);
> + EG(called_scope) = EX(current_called_scope);
> +
> + EX(object) = EX(current_object);
> + EX(called_scope) = DECODE_CTOR(EX(called_scope));
> +
> + zend_vm_stack_clear_multiple(TSRMLS_C);
> +
> + if (EG(exception)) {
> + zend_throw_exception_internal(NULL TSRMLS_CC);
> + if (RETURN_VALUE_USED(EX(call_opline))
> && EX_T(EX(call_opline)->result.u.var).var.ptr) {
> +
> zval_ptr_dtor(&EX_T(EX(call_opline)->result.u.var).var.ptr);
> + }
> + }
> +
> + EX(opline)++;
> + ZEND_VM_LEAVE();
> + }
> + }
> + ZEND_VM_RETURN();
> +}
>
> ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
> {
> zend_op *opline = EX(opline);
> - zend_class_entry *current_scope;
> - zend_class_entry *current_called_scope;
> - zval *current_this;
> - zend_bool should_change_scope;
> - zval *ex_object;
> + zend_bool should_change_scope = 0;
>
> if (EX(function_state).function->common.fn_flags &
> (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
> if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
> @@ -2112,17 +2213,15 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
> if (EX(function_state).function->type == ZEND_USER_FUNCTION ||
> EX(function_state).function->common.scope) {
> should_change_scope = 1;
> - current_this = EG(This);
> - current_scope = EG(scope);
> - current_called_scope = EG(called_scope);
> + EX(current_this) = EG(This);
> + EX(current_scope) = EG(scope);
> + EX(current_called_scope) = EG(called_scope);
> EG(This) = EX(object);
> EG(scope) = (EX(function_state).function->type ==
> ZEND_USER_FUNCTION || !EX(object)) ?
> EX(function_state).function->common.scope : NULL;
> EG(called_scope) = EX(called_scope);
> - } else {
> - should_change_scope = 0;
> }
>
> - zend_ptr_stack_3_pop(&EG(arg_types_stack),
> (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc));
> + zend_ptr_stack_3_pop(&EG(arg_types_stack),
> (void*)&EX(called_scope), (void**)&EX(current_object), (void**)&EX(fbc));
> EX(function_state).arguments =
> zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
>
> if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
> @@ -2151,8 +2250,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
> zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
> }
> } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
> - zval **original_return_value = EG(return_value_ptr_ptr);
> -
> + EX(original_return_value) = EG(return_value_ptr_ptr);
> EG(active_symbol_table) = NULL;
> EG(active_op_array) =
> &EX(function_state).function->op_array;
> EG(return_value_ptr_ptr) = NULL;
> @@ -2163,11 +2261,20 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
>
> EX_T(opline->result.u.var).var.fcall_returned_reference =
> EX(function_state).function->common.return_reference;
> }
>
> +#ifndef ZEND_VM_EXPORT
> + if (zend_execute == execute && !EG(exception)) {
> + EX(call_opline) = opline;
> + ZEND_VM_ENTER();
> + } else {
> + zend_execute(EG(active_op_array) TSRMLS_CC);
> + }
> +#else
> zend_execute(EG(active_op_array) TSRMLS_CC);
> +#endif
>
> EG(opline_ptr) = &EX(opline);
> EG(active_op_array) = EX(op_array);
> - EG(return_value_ptr_ptr)=original_return_value;
> + EG(return_value_ptr_ptr) = EX(original_return_value);
> if (EG(active_symbol_table)) {
> if
> (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
> zend_hash_destroy(EG(active_symbol_table));
> @@ -2220,12 +2327,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
> }
> zval_ptr_dtor(&EG(This));
> }
> - EG(This) = current_this;
> - EG(scope) = current_scope;
> - EG(called_scope) = current_called_scope;
> + EG(This) = EX(current_this);
> + EG(scope) = EX(current_scope);
> + EG(called_scope) = EX(current_called_scope);
> }
>
> - EX(object) = ex_object;
> + EX(object) = EX(current_object);
> EX(called_scope) = DECODE_CTOR(EX(called_scope));
>
> zend_vm_stack_clear_multiple(TSRMLS_C);
> @@ -2335,7 +2442,7 @@ ZEND_VM_C_LABEL(return_by_value):
> }
> }
> FREE_OP1_IF_VAR();
> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
> }
>
> ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
> @@ -3030,7 +3137,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
> {
> zend_op *opline = EX(opline);
> zend_op_array *new_op_array=NULL;
> - zval **original_return_value = EG(return_value_ptr_ptr);
> int return_value_used;
> zend_free_op free_op1;
> zval *inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R);
> @@ -3102,17 +3208,15 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
> if (inc_filename==&tmp_inc_filename) {
> zval_dtor(&tmp_inc_filename);
> }
> + FREE_OP1();
> EX_T(opline->result.u.var).var.ptr_ptr =
> &EX_T(opline->result.u.var).var.ptr;
> - if (new_op_array) {
> - zval *saved_object;
> - zend_function *saved_function;
> -
> + if (new_op_array && !EG(exception)) {
> + EX(original_return_value) = EG(return_value_ptr_ptr);
> EG(return_value_ptr_ptr) = return_value_used ?
> EX_T(opline->result.u.var).var.ptr_ptr : NULL;
> EG(active_op_array) = new_op_array;
> EX_T(opline->result.u.var).var.ptr = NULL;
>
> - saved_object = EX(object);
> - saved_function = EX(function_state).function;
> + EX(current_object) = EX(object);
>
> EX(function_state).function = (zend_function *) new_op_array;
> EX(object) = NULL;
> @@ -3121,10 +3225,15 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
> zend_rebuild_symbol_table(TSRMLS_C);
> }
>
> - zend_execute(new_op_array TSRMLS_CC);
> + if (zend_execute == execute) {
> + EX(call_opline) = opline;
> + ZEND_VM_ENTER();
> + } else {
> + zend_execute(new_op_array TSRMLS_CC);
> + }
>
> - EX(function_state).function = saved_function;
> - EX(object) = saved_object;
> + EX(function_state).function = (zend_function *) EX(op_array);
> + EX(object) = EX(current_object);
>
> if (return_value_used) {
> if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
> @@ -3137,6 +3246,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>
> EG(opline_ptr) = &EX(opline);
> EG(active_op_array) = EX(op_array);
> + EG(return_value_ptr_ptr) = EX(original_return_value);
> destroy_op_array(new_op_array TSRMLS_CC);
> efree(new_op_array);
> if (EG(exception)) {
> @@ -3150,8 +3260,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
> Z_TYPE_P(EX_T(opline->result.u.var).var.ptr) = IS_BOOL;
> }
> }
> - FREE_OP1();
> - EG(return_value_ptr_ptr) = original_return_value;
> ZEND_VM_NEXT_OPCODE();
> }
>
> @@ -3885,7 +3993,6 @@ ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP
> FREE_OP1();
> }
> #endif
> - ZEND_VM_EXIT_FROM_EXECUTE_LOOP();
> zend_bailout();
> ZEND_VM_NEXT_OPCODE();
> }
> @@ -4156,7 +4263,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTI
> EX(old_error_reporting) = NULL;
>
> if (!catched) {
> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
> } else {
> ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
> ZEND_VM_CONTINUE();
> @@ -4177,7 +4284,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, A
> case ZEND_USER_OPCODE_CONTINUE:
> ZEND_VM_CONTINUE();
> case ZEND_USER_OPCODE_RETURN:
> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
> case ZEND_USER_OPCODE_DISPATCH:
> ZEND_VM_DISPATCH(EX(opline)->opcode, EX(opline));
> default:
> Index: Zend/zend_vm_execute.skl
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_vm_execute.skl,v
> retrieving revision 1.2.2.2.2.1.2.8
> diff -u -p -d -r1.2.2.2.2.1.2.8 zend_vm_execute.skl
> --- Zend/zend_vm_execute.skl 7 May 2008 12:04:39 -0000 1.2.2.2.2.1.2.8
> +++ Zend/zend_vm_execute.skl 10 Jun 2008 10:53:49 -0000
> @@ -3,6 +3,8 @@
> ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
> {
> zend_execute_data *execute_data;
> + zend_bool nested = 0;
> + zend_bool original_in_execution = EG(in_execution);
> {%HELPER_VARS%}
>
> {%INTERNAL_LABELS%}
> @@ -11,6 +13,9 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
> return;
> }
>
> + EG(in_execution) = 1;
> +
> +zend_vm_enter:
> /* Initialize execute_data */
> execute_data = (zend_execute_data *)zend_vm_stack_alloc(
> sizeof(zend_execute_data) +
> @@ -25,12 +30,12 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
> EX(object) = NULL;
> EX(old_error_reporting) = NULL;
> EX(op_array) = op_array;
> - EX(original_in_execution) = EG(in_execution);
> EX(symbol_table) = EG(active_symbol_table);
> EX(prev_execute_data) = EG(current_execute_data);
> EG(current_execute_data) = execute_data;
> + EX(nested) = nested;
> + nested = 1;
>
> - EG(in_execution) = 1;
> if (op_array->start_op) {
> ZEND_VM_SET_OPCODE(op_array->start_op);
> } else {
> Index: Zend/zend_vm_gen.php
> ===================================================================
> RCS file: /repository/ZendEngine2/zend_vm_gen.php,v
> retrieving revision 1.12.2.5.2.4.2.2
> diff -u -p -d -r1.12.2.5.2.4.2.2 zend_vm_gen.php
> --- Zend/zend_vm_gen.php 24 Jan 2008 09:41:39 -0000 1.12.2.5.2.4.2.2
> +++ Zend/zend_vm_gen.php 10 Jun 2008 10:53:49 -0000
> @@ -304,7 +304,7 @@ function helper_name($name, $spec, $op1,
> }
>
> // Generates code for opcode handler or helper
> -function gen_code($f, $spec, $kind, $code, $op1, $op2) {
> +function gen_code($f, $spec, $kind, $export, $code, $op1, $op2) {
> global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr,
> $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr,
> $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr,
> @@ -343,7 +343,9 @@ function gen_code($f, $spec, $kind, $cod
> "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m",
> "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m",
> "/^#if\s+1\s*\\|\\|.*[^\\\\]$/m",
> - "/^#if\s+0\s*&&.*[^\\\\]$/m"
> + "/^#if\s+0\s*&&.*[^\\\\]$/m",
> + "/^#ifdef\s+ZEND_VM_EXPORT\s*\n/m",
> + "/^#ifndef\s+ZEND_VM_EXPORT\s*\n/m"
> ),
> array(
> $op1_type[$op1],
> @@ -374,6 +376,8 @@ function gen_code($f, $spec, $kind, $cod
> "goto \\1".(($spec && $kind !=
> ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""),
> "#if 1",
> "#if 0",
> + $export?"#if 1\n":"#if 0\n",
> + $export?"#if 0\n":"#if 1\n"
> ),
> $code);
>
> @@ -481,7 +485,7 @@ function gen_handler($f, $spec, $kind, $
> // Generate opcode handler's entry point according to selected threading model
> switch($kind) {
> case ZEND_VM_KIND_CALL:
> - out($f,"static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
> + out($f,"ZEND_FASTCALL static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
> break;
> case ZEND_VM_KIND_SWITCH:
> if ($spec) {
> @@ -502,7 +506,7 @@ function gen_handler($f, $spec, $kind, $
> }
>
> // Generate opcode handler's code
> - gen_code($f, $spec, $kind, $code, $op1, $op2);
> + gen_code($f, $spec, $kind, 0, $code, $op1, $op2);
> }
>
> // Generates helper
> @@ -518,10 +522,10 @@ function gen_helper($f, $spec, $kind, $n
> case ZEND_VM_KIND_CALL:
> if ($param == null) {
> // Helper without parameters
> - out($f, "static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
> + out($f, "ZEND_FASTCALL static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
> } else {
> // Helper with parameter
> - out($f, "static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
> + out($f, "ZEND_FASTCALL static int
> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
> }
> break;
> case ZEND_VM_KIND_SWITCH:
> @@ -533,7 +537,7 @@ function gen_helper($f, $spec, $kind, $n
> }
>
> // Generate helper's code
> - gen_code($f, $spec, $kind, $code, $op1, $op2);
> + gen_code($f, $spec, $kind, 0, $code, $op1, $op2);
> }
>
> // Generates array of opcode handlers (specialized or unspecialized)
> @@ -685,10 +689,9 @@ function gen_null_handler($f) {
> // for undefined opcodes, do we emit code for it only once
> if (!$done) {
> $done = 1;
> - out($f,"static int
> ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
> + out($f,"ZEND_FASTCALL static int
> ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
> out($f,"{\n");
> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode
> %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
> out($f,"}\n\n");
> }
> }
> @@ -763,12 +766,10 @@ function gen_executor_code($f, $spec, $k
> case ZEND_VM_KIND_SWITCH:
> out($f,"default:\n");
> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid
> opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
> break;
> case ZEND_VM_KIND_GOTO:
> out($f,"ZEND_NULL_HANDLER:\n");
> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid
> opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
> break;
> }
> }
> @@ -790,7 +791,7 @@ function gen_executor($f, $skl, $spec, $
> if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
> switch ($m[2]) {
> case "DEFINES":
> - if (ZEND_VM_OLD_EXECUTOR) {
> + if (ZEND_VM_OLD_EXECUTOR && $spec) {
> out($f,"static int zend_vm_old_executor = 0;\n\n");
> }
> out($f,"static opcode_handler_t
> zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op);\n\n");
> @@ -799,6 +800,8 @@ function gen_executor($f, $skl, $spec, $
> out($f,"\n");
> out($f,"#define ZEND_VM_CONTINUE() return 0\n");
> out($f,"#define ZEND_VM_RETURN() return 1\n");
> + out($f,"#define ZEND_VM_ENTER() return 2\n");
> + out($f,"#define ZEND_VM_LEAVE() return 3\n");
> out($f,"#define
> ZEND_VM_DISPATCH(opcode, opline) return
> zend_vm_get_opcode_handler(opcode,
> opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
> out($f,"#define
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
> out($f,"#undef EX\n");
> @@ -807,7 +810,9 @@ function gen_executor($f, $skl, $spec, $
> case ZEND_VM_KIND_SWITCH:
> out($f,"\n");
> out($f,"#define
> ZEND_VM_CONTINUE() goto zend_vm_continue\n");
> - out($f,"#define ZEND_VM_RETURN() return\n");
> + out($f,"#define
> ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n");
> + out($f,"#define
> ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n");
> + out($f,"#define
> ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
> out($f,"#define
> ZEND_VM_DISPATCH(opcode, opline) dispatch_handler =
> zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n\n");
> out($f,"#define
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
> out($f,"#undef EX\n");
> @@ -816,7 +821,9 @@ function gen_executor($f, $skl, $spec, $
> case ZEND_VM_KIND_GOTO:
> out($f,"\n");
> out($f,"#define
> ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n");
> - out($f,"#define ZEND_VM_RETURN() return\n");
> + out($f,"#define
> ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n");
> + out($f,"#define
> ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n");
> + out($f,"#define
> ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
> out($f,"#define
> ZEND_VM_DISPATCH(opcode, opline) goto
> *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n\n");
> out($f,"#define
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
> out($f,"#undef EX\n");
> @@ -857,7 +864,10 @@ function gen_executor($f, $skl, $spec, $
> }
> break;
> case "ZEND_VM_CONTINUE_LABEL":
> - if ($kind == ZEND_VM_KIND_SWITCH) {
> + if ($kind == ZEND_VM_KIND_CALL) {
> + // Only SWITCH dispatch method use it
> + out($f,$m[1]."\tint ret;".$m[3]."\n");
> + } else if ($kind == ZEND_VM_KIND_SWITCH) {
> // Only SWITCH dispatch method use it
>
> out($f,"zend_vm_continue:".$m[3]."\n");
> } else {
> @@ -868,7 +878,7 @@ function gen_executor($f, $skl, $spec, $
> // Emit code that dispatches to opcode handler
> switch ($kind) {
> case ZEND_VM_KIND_CALL:
> - out($f,
> $m[1]."if (EX(opline)->handler(execute_data TSRMLS_CC) > 0)".$m[3]."\n");
> + out($f,
> $m[1]."if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0)".$m[3]."\n");
> break;
> case ZEND_VM_KIND_SWITCH:
> out($f,
> $m[1]."dispatch_handler =
> EX(opline)->handler;\nzend_vm_dispatch:\n".$m[1]."switch
> ((int)dispatch_handler)".$m[3]."\n");
> @@ -881,7 +891,18 @@ function gen_executor($f, $skl, $spec, $
> case "INTERNAL_EXECUTOR":
> if ($kind == ZEND_VM_KIND_CALL) {
> // Executor is defined as a set of functions
> - out($f, $m[1]."return;".$m[3]."\n");
> + out($f, $m[1]."switch (ret) {\n" .
> + $m[1]."\tcase 1:\n" .
> +
> $m[1]."\t\tEG(in_execution) = original_in_execution;\n".
> + $m[1]."\t\treturn;\n".
> + $m[1]."\tcase 2:\n" .
> +
> $m[1]."\t\top_array = EG(active_op_array);\n".
> + $m[1]."\t\tgoto zend_vm_enter;\n".
> + $m[1]."\tcase 3:\n" .
> +
> $m[1]."\t\texecute_data = EG(current_execute_data);\n".
> + $m[1]."\tdefault:\n".
> + $m[1]."\t\tbreak;\n".
> + $m[1]."}".$m[3]."\n");
> } else {
> // Emit executor code
> gen_executor_code($f, $spec, $kind, $m[1]);
> @@ -1102,11 +1123,11 @@ function gen_vm($def, $skel) {
> out($f, $GLOBALS['header_text']);
>
> // Support for ZEND_USER_OPCODE
> - out($f, "static opcode_handler_t zend_user_opcode_handlers[256] = {");
> + out($f, "static user_opcode_handler_t
> zend_user_opcode_handlers[256] = {");
> for ($i = 0; $i < 255; ++$i) {
> - out($f, "(opcode_handler_t)NULL,");
> + out($f, "(user_opcode_handler_t)NULL,");
> }
> - out($f, "(opcode_handler_t)NULL};\n\n");
> + out($f, "(user_opcode_handler_t)NULL};\n\n");
>
> out($f, "static zend_uchar zend_user_opcodes[256] = {");
> for ($i = 0; $i < 255; ++$i) {
> @@ -1124,6 +1145,8 @@ function gen_vm($def, $skel) {
> out($f,"#define EX(element) execute_data.element\n\n");
> out($f,"#undef ZEND_VM_CONTINUE\n\n");
> out($f,"#undef ZEND_VM_RETURN\n\n");
> + out($f,"#undef ZEND_VM_ENTER\n\n");
> + out($f,"#undef ZEND_VM_LEAVE\n\n");
> out($f,"#undef ZEND_VM_DISPATCH\n\n");
> out($f,"#undef
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
> gen_executor($f, $skl, 0, ZEND_VM_KIND_CALL,
> "old_execute", "zend_vm_use_old_executor", 1);
> @@ -1180,10 +1203,14 @@ function gen_vm($def, $skel) {
> out($f,"#define EX(element) execute_data->element\n\n");
> out($f,"#undef ZEND_VM_CONTINUE\n");
> out($f,"#undef ZEND_VM_RETURN\n");
> + out($f,"#undef ZEND_VM_ENTER\n");
> + out($f,"#undef ZEND_VM_LEAVE\n");
> out($f,"#undef ZEND_VM_DISPATCH\n");
> out($f,"#undef
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
> out($f,"#define ZEND_VM_CONTINUE() return 0\n");
> out($f,"#define ZEND_VM_RETURN() return 1\n");
> + out($f,"#define ZEND_VM_ENTER() return 2\n");
> + out($f,"#define ZEND_VM_LEAVE() return 3\n");
> out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return
> zend_vm_get_opcode_handler(opcode,
> opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
> out($f,"#define
> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n\n");
> }
> @@ -1227,7 +1254,7 @@ function gen_vm($def, $skel) {
> }
> }
> if (!$done) {
> - gen_code($f, 0, ZEND_VM_KIND_CALL, $code, 'ANY', 'ANY');
> + gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY');
> }
> }
>
Best regards,
Marcus
Thanks. Dmitry.
Marcus Boerger wrote:
> Hello Dmitry,
>
> Tuesday, June 10, 2008, 1:11:57 PM, you wrote:
>
>> Index: Zend/zend.h
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend.h,v
>> retrieving revision 1.293.2.11.2.9.2.20
>> diff -u -p -d -r1.293.2.11.2.9.2.20 zend.h
>> --- Zend/zend.h 18 Mar 2008 21:14:27 -0000 1.293.2.11.2.9.2.20
>> +++ Zend/zend.h 10 Jun 2008 10:53:48 -0000
>> @@ -176,6 +176,12 @@ char *alloca ();
>> # define ZEND_ATTRIBUTE_PTR_FORMAT(type, idx, first)
>> #endif
>>
>> +#if defined(__GNUC__) && ZEND_GCC_VERSION >= 3400 && defined(__i386__)
>> +# define ZEND_FASTCALL __attribute__((fastcall))
>> +#else
>> +# define ZEND_FASTCALL
>> +#endif
>
> Is this like __fastcall under windows? If so, please add it when _MSC_VER
> is defined.
>
>> +
>> #if (HAVE_ALLOCA || (defined (__GNUC__) && __GNUC__ >= 2)) &&
>> !(defined(ZTS) && defined(ZEND_WIN32)) && !(defined(ZTS) &&
>> defined(NETWARE)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN)
>> # define ZEND_ALLOCA_MAX_SIZE (32 * 1024)
>> # define ALLOCA_FLAG(name) \
>> Index: Zend/zend_compile.h
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_compile.h,v
>> retrieving revision 1.316.2.8.2.12.2.24
>> diff -u -p -d -r1.316.2.8.2.12.2.24 zend_compile.h
>> --- Zend/zend_compile.h 12 May 2008 09:09:05 -0000 1.316.2.8.2.12.2.24
>> +++ Zend/zend_compile.h 10 Jun 2008 10:53:48 -0000
>> @@ -73,7 +73,8 @@ typedef struct _zend_execute_data zend_e
>> #define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data TSRMLS_DC
>> #define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data TSRMLS_CC
>>
>> -typedef int (*opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
>> +typedef int (*user_opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
>> +typedef int (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);
>>
>> extern ZEND_API opcode_handler_t *zend_opcode_handlers;
>>
>> @@ -309,10 +310,16 @@ struct _zend_execute_data {
>> zval *object;
>> union _temp_variable *Ts;
>> zval ***CVs;
>> - zend_bool original_in_execution;
>> HashTable *symbol_table;
>> struct _zend_execute_data *prev_execute_data;
>> zval *old_error_reporting;
>> + zend_bool nested;
>> + zval **original_return_value;
>> + zend_class_entry *current_scope;
>> + zend_class_entry *current_called_scope;
>> + zval *current_this;
>> + zval *current_object;
>> + struct _zend_op *call_opline;
>> };
>>
>> #define EX(element) execute_data.element
>> Index: Zend/zend_execute.c
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_execute.c,v
>> retrieving revision 1.716.2.12.2.24.2.29
>> diff -u -p -d -r1.716.2.12.2.24.2.29 zend_execute.c
>> --- Zend/zend_execute.c 9 May 2008 09:23:03 -0000 1.716.2.12.2.24.2.29
>> +++ Zend/zend_execute.c 10 Jun 2008 10:53:48 -0000
>> @@ -1314,29 +1314,9 @@ ZEND_API void execute_internal(zend_exec
>> #define ZEND_VM_INC_OPCODE() \
>> EX(opline)++
>>
>> -#define ZEND_VM_EXIT_FROM_EXECUTE_LOOP() do { \
>> - EG(in_execution) = EX(original_in_execution); \
>> - EG(current_execute_data) = EX(prev_execute_data); \
>> - EG(opline_ptr) = NULL; \
>> - if (!EG(active_symbol_table)) { \
>> - int n = EX(op_array)->last_var; \
>> - while (n > 0) { \
>> - --n; \
>> - if (EX(CVs)[n]) { \
>> - zval_ptr_dtor(EX(CVs)[n]); \
>> - } \
>> - } \
>> - } \
>> - zend_vm_stack_free(execute_data TSRMLS_CC); \
>> - } while (0);
>> -
>> -#define ZEND_VM_RETURN_FROM_EXECUTE_LOOP() \
>> - ZEND_VM_EXIT_FROM_EXECUTE_LOOP() \
>> - ZEND_VM_RETURN()
>> -
>> #include "zend_vm_execute.h"
>>
>> -ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, opcode_handler_t handler)
>> +ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler)
>> {
>> if (opcode != ZEND_USER_OPCODE) {
>> zend_user_opcodes[opcode] = ZEND_USER_OPCODE;
>> @@ -1346,7 +1326,7 @@ ZEND_API int zend_set_user_opcode_handle
>> return FAILURE;
>> }
>>
>> -ZEND_API opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
>> +ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode)
>> {
>> return zend_user_opcode_handlers[opcode];
>> }
>> Index: Zend/zend_execute.h
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_execute.h,v
>> retrieving revision 1.84.2.4.2.8.2.9
>> diff -u -p -d -r1.84.2.4.2.8.2.9 zend_execute.h
>> --- Zend/zend_execute.h 15 Apr 2008 15:52:36 -0000 1.84.2.4.2.8.2.9
>> +++ Zend/zend_execute.h 10 Jun 2008 10:53:48 -0000
>> @@ -331,8 +331,8 @@ ZEND_API zval** zend_get_compiled_variab
>>
>> #define ZEND_USER_OPCODE_DISPATCH_TO 0x100 /* call original handler of returned opcode */
>>
>> -ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, opcode_handler_t handler);
>> -ZEND_API opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode);
>> +ZEND_API int zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler);
>> +ZEND_API user_opcode_handler_t zend_get_user_opcode_handler(zend_uchar opcode);
>>
>> /* former zend_execute_locks.h */
>> typedef struct _zend_free_op {
>> Index: Zend/zend_vm_def.h
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_vm_def.h,v
>> retrieving revision 1.59.2.29.2.48.2.57
>> diff -u -p -d -r1.59.2.29.2.48.2.57 zend_vm_def.h
>> --- Zend/zend_vm_def.h 3 Jun 2008 18:11:11 -0000 1.59.2.29.2.48.2.57
>> +++ Zend/zend_vm_def.h 10 Jun 2008 10:53:49 -0000
>> @@ -2073,15 +2073,116 @@ ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_B
>> ZEND_VM_NEXT_OPCODE();
>> }
>>
>> +ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
>> +{
>> + zend_bool nested;
>> + zend_op_array *op_array = EX(op_array);
>> +
>> + EG(current_execute_data) = EX(prev_execute_data);
>> + EG(opline_ptr) = NULL;
>> + if (!EG(active_symbol_table)) {
>> + zval ***cv = EX(CVs);
>> + zval ***end = cv + EX(op_array)->last_var;
>> + while (cv != end) {
>> + if (*cv) {
>> + zval_ptr_dtor(*cv);
>> + }
>> + cv++;
>> + }
>> + }
>> +
>> + nested = EX(nested);
>> +
>> + zend_vm_stack_free(execute_data TSRMLS_CC);
>> +
>> + if (nested) {
>> + execute_data = EG(current_execute_data);
>> +
>> + if (EX(call_opline)->opcode == ZEND_INCLUDE_OR_EVAL) {
>> +
>> + EX(function_state).function = (zend_function *) EX(op_array);
>> + EX(function_state).arguments = NULL;
>> + EX(object) = EX(current_object);
>> +
>> + if (RETURN_VALUE_USED(EX(call_opline))) {
>> + if
>> (!EX_T(EX(call_opline)->result.u.var).var.ptr) { /* there was no return statement */
>> +
>> ALLOC_ZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr);
>> +
>> INIT_PZVAL(EX_T(EX(call_opline)->result.u.var).var.ptr);
>> +
>> Z_LVAL_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = 1;
>> +
>> Z_TYPE_P(EX_T(EX(call_opline)->result.u.var).var.ptr) = IS_BOOL;
>> + }
>> + }
>> +
>> + EG(opline_ptr) = &EX(opline);
>> + EG(active_op_array) = EX(op_array);
>> + EG(return_value_ptr_ptr) = EX(original_return_value);
>> + destroy_op_array(op_array TSRMLS_CC);
>> + efree(op_array);
>> + if (EG(exception)) {
>> + zend_throw_exception_internal(NULL TSRMLS_CC);
>> + }
>> +
>> + EX(opline)++;
>> + ZEND_VM_LEAVE();
>> + } else {
>> +
>> + EG(opline_ptr) = &EX(opline);
>> + EG(active_op_array) = EX(op_array);
>> + EG(return_value_ptr_ptr) = EX(original_return_value);
>> + if (EG(active_symbol_table)) {
>> + if
>> (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
>> +
>> zend_hash_destroy(EG(active_symbol_table));
>> +
>> FREE_HASHTABLE(EG(active_symbol_table));
>> + } else {
>> + /* clean before putting into the cache, since clean
>> + could call dtors, which could use cached hash */
>> +
>> zend_hash_clean(EG(active_symbol_table));
>> + *(++EG(symtable_cache_ptr)) = EG(active_symbol_table);
>> + }
>> + }
>> + EG(active_symbol_table) = EX(symbol_table);
>> +
>> + EX(function_state).function = (zend_function *) EX(op_array);
>> + EX(function_state).arguments = NULL;
>> +
>> + if (EG(This)) {
>> + if (EG(exception) && IS_CTOR_CALL(EX(called_scope))) {
>> + if (IS_CTOR_USED(EX(called_scope))) {
>> + Z_DELREF_P(EG(This));
>> + }
>> + if (Z_REFCOUNT_P(EG(This)) == 1) {
>> +
>> zend_object_store_ctor_failed(EG(This) TSRMLS_CC);
>> + }
>> + }
>> + zval_ptr_dtor(&EG(This));
>> + }
>> + EG(This) = EX(current_this);
>> + EG(scope) = EX(current_scope);
>> + EG(called_scope) = EX(current_called_scope);
>> +
>> + EX(object) = EX(current_object);
>> + EX(called_scope) = DECODE_CTOR(EX(called_scope));
>> +
>> + zend_vm_stack_clear_multiple(TSRMLS_C);
>> +
>> + if (EG(exception)) {
>> + zend_throw_exception_internal(NULL TSRMLS_CC);
>> + if (RETURN_VALUE_USED(EX(call_opline))
>> && EX_T(EX(call_opline)->result.u.var).var.ptr) {
>> +
>> zval_ptr_dtor(&EX_T(EX(call_opline)->result.u.var).var.ptr);
>> + }
>> + }
>> +
>> + EX(opline)++;
>> + ZEND_VM_LEAVE();
>> + }
>> + }
>> + ZEND_VM_RETURN();
>> +}
>>
>> ZEND_VM_HELPER(zend_do_fcall_common_helper, ANY, ANY)
>> {
>> zend_op *opline = EX(opline);
>> - zend_class_entry *current_scope;
>> - zend_class_entry *current_called_scope;
>> - zval *current_this;
>> - zend_bool should_change_scope;
>> - zval *ex_object;
>> + zend_bool should_change_scope = 0;
>>
>> if (EX(function_state).function->common.fn_flags &
>> (ZEND_ACC_ABSTRACT|ZEND_ACC_DEPRECATED)) {
>> if (EX(function_state).function->common.fn_flags & ZEND_ACC_ABSTRACT) {
>> @@ -2112,17 +2213,15 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
>> if (EX(function_state).function->type == ZEND_USER_FUNCTION ||
>> EX(function_state).function->common.scope) {
>> should_change_scope = 1;
>> - current_this = EG(This);
>> - current_scope = EG(scope);
>> - current_called_scope = EG(called_scope);
>> + EX(current_this) = EG(This);
>> + EX(current_scope) = EG(scope);
>> + EX(current_called_scope) = EG(called_scope);
>> EG(This) = EX(object);
>> EG(scope) = (EX(function_state).function->type ==
>> ZEND_USER_FUNCTION || !EX(object)) ?
>> EX(function_state).function->common.scope : NULL;
>> EG(called_scope) = EX(called_scope);
>> - } else {
>> - should_change_scope = 0;
>> }
>>
>> - zend_ptr_stack_3_pop(&EG(arg_types_stack),
>> (void*)&EX(called_scope), (void**)&ex_object, (void**)&EX(fbc));
>> + zend_ptr_stack_3_pop(&EG(arg_types_stack),
>> (void*)&EX(called_scope), (void**)&EX(current_object), (void**)&EX(fbc));
>> EX(function_state).arguments =
>> zend_vm_stack_push_args(opline->extended_value TSRMLS_CC);
>>
>> if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION) {
>> @@ -2151,8 +2250,7 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
>> zval_ptr_dtor(&EX_T(opline->result.u.var).var.ptr);
>> }
>> } else if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
>> - zval **original_return_value = EG(return_value_ptr_ptr);
>> -
>> + EX(original_return_value) = EG(return_value_ptr_ptr);
>> EG(active_symbol_table) = NULL;
>> EG(active_op_array) =
>> &EX(function_state).function->op_array;
>> EG(return_value_ptr_ptr) = NULL;
>> @@ -2163,11 +2261,20 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
>>
>> EX_T(opline->result.u.var).var.fcall_returned_reference =
>> EX(function_state).function->common.return_reference;
>> }
>>
>> +#ifndef ZEND_VM_EXPORT
>> + if (zend_execute == execute && !EG(exception)) {
>> + EX(call_opline) = opline;
>> + ZEND_VM_ENTER();
>> + } else {
>> + zend_execute(EG(active_op_array) TSRMLS_CC);
>> + }
>> +#else
>> zend_execute(EG(active_op_array) TSRMLS_CC);
>> +#endif
>>
>> EG(opline_ptr) = &EX(opline);
>> EG(active_op_array) = EX(op_array);
>> - EG(return_value_ptr_ptr)=original_return_value;
>> + EG(return_value_ptr_ptr) = EX(original_return_value);
>> if (EG(active_symbol_table)) {
>> if
>> (EG(symtable_cache_ptr)>=EG(symtable_cache_limit)) {
>> zend_hash_destroy(EG(active_symbol_table));
>> @@ -2220,12 +2327,12 @@ ZEND_VM_HELPER(zend_do_fcall_common_help
>> }
>> zval_ptr_dtor(&EG(This));
>> }
>> - EG(This) = current_this;
>> - EG(scope) = current_scope;
>> - EG(called_scope) = current_called_scope;
>> + EG(This) = EX(current_this);
>> + EG(scope) = EX(current_scope);
>> + EG(called_scope) = EX(current_called_scope);
>> }
>>
>> - EX(object) = ex_object;
>> + EX(object) = EX(current_object);
>> EX(called_scope) = DECODE_CTOR(EX(called_scope));
>>
>> zend_vm_stack_clear_multiple(TSRMLS_C);
>> @@ -2335,7 +2442,7 @@ ZEND_VM_C_LABEL(return_by_value):
>> }
>> }
>> FREE_OP1_IF_VAR();
>> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
>> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
>> }
>>
>> ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
>> @@ -3030,7 +3137,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>> {
>> zend_op *opline = EX(opline);
>> zend_op_array *new_op_array=NULL;
>> - zval **original_return_value = EG(return_value_ptr_ptr);
>> int return_value_used;
>> zend_free_op free_op1;
>> zval *inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R);
>> @@ -3102,17 +3208,15 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>> if (inc_filename==&tmp_inc_filename) {
>> zval_dtor(&tmp_inc_filename);
>> }
>> + FREE_OP1();
>> EX_T(opline->result.u.var).var.ptr_ptr =
>> &EX_T(opline->result.u.var).var.ptr;
>> - if (new_op_array) {
>> - zval *saved_object;
>> - zend_function *saved_function;
>> -
>> + if (new_op_array && !EG(exception)) {
>> + EX(original_return_value) = EG(return_value_ptr_ptr);
>> EG(return_value_ptr_ptr) = return_value_used ?
>> EX_T(opline->result.u.var).var.ptr_ptr : NULL;
>> EG(active_op_array) = new_op_array;
>> EX_T(opline->result.u.var).var.ptr = NULL;
>>
>> - saved_object = EX(object);
>> - saved_function = EX(function_state).function;
>> + EX(current_object) = EX(object);
>>
>> EX(function_state).function = (zend_function *) new_op_array;
>> EX(object) = NULL;
>> @@ -3121,10 +3225,15 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>> zend_rebuild_symbol_table(TSRMLS_C);
>> }
>>
>> - zend_execute(new_op_array TSRMLS_CC);
>> + if (zend_execute == execute) {
>> + EX(call_opline) = opline;
>> + ZEND_VM_ENTER();
>> + } else {
>> + zend_execute(new_op_array TSRMLS_CC);
>> + }
>>
>> - EX(function_state).function = saved_function;
>> - EX(object) = saved_object;
>> + EX(function_state).function = (zend_function *) EX(op_array);
>> + EX(object) = EX(current_object);
>>
>> if (return_value_used) {
>> if (!EX_T(opline->result.u.var).var.ptr) { /* there was no return statement */
>> @@ -3137,6 +3246,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>>
>> EG(opline_ptr) = &EX(opline);
>> EG(active_op_array) = EX(op_array);
>> + EG(return_value_ptr_ptr) = EX(original_return_value);
>> destroy_op_array(new_op_array TSRMLS_CC);
>> efree(new_op_array);
>> if (EG(exception)) {
>> @@ -3150,8 +3260,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL
>> Z_TYPE_P(EX_T(opline->result.u.var).var.ptr) = IS_BOOL;
>> }
>> }
>> - FREE_OP1();
>> - EG(return_value_ptr_ptr) = original_return_value;
>> ZEND_VM_NEXT_OPCODE();
>> }
>>
>> @@ -3885,7 +3993,6 @@ ZEND_VM_HANDLER(79, ZEND_EXIT, CONST|TMP
>> FREE_OP1();
>> }
>> #endif
>> - ZEND_VM_EXIT_FROM_EXECUTE_LOOP();
>> zend_bailout();
>> ZEND_VM_NEXT_OPCODE();
>> }
>> @@ -4156,7 +4263,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTI
>> EX(old_error_reporting) = NULL;
>>
>> if (!catched) {
>> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
>> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
>> } else {
>> ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
>> ZEND_VM_CONTINUE();
>> @@ -4177,7 +4284,7 @@ ZEND_VM_HANDLER(150, ZEND_USER_OPCODE, A
>> case ZEND_USER_OPCODE_CONTINUE:
>> ZEND_VM_CONTINUE();
>> case ZEND_USER_OPCODE_RETURN:
>> - ZEND_VM_RETURN_FROM_EXECUTE_LOOP();
>> + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
>> case ZEND_USER_OPCODE_DISPATCH:
>> ZEND_VM_DISPATCH(EX(opline)->opcode, EX(opline));
>> default:
>> Index: Zend/zend_vm_execute.skl
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_vm_execute.skl,v
>> retrieving revision 1.2.2.2.2.1.2.8
>> diff -u -p -d -r1.2.2.2.2.1.2.8 zend_vm_execute.skl
>> --- Zend/zend_vm_execute.skl 7 May 2008 12:04:39 -0000 1.2.2.2.2.1.2.8
>> +++ Zend/zend_vm_execute.skl 10 Jun 2008 10:53:49 -0000
>> @@ -3,6 +3,8 @@
>> ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC)
>> {
>> zend_execute_data *execute_data;
>> + zend_bool nested = 0;
>> + zend_bool original_in_execution = EG(in_execution);
>> {%HELPER_VARS%}
>>
>> {%INTERNAL_LABELS%}
>> @@ -11,6 +13,9 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
>> return;
>> }
>>
>> + EG(in_execution) = 1;
>> +
>> +zend_vm_enter:
>> /* Initialize execute_data */
>> execute_data = (zend_execute_data *)zend_vm_stack_alloc(
>> sizeof(zend_execute_data) +
>> @@ -25,12 +30,12 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_
>> EX(object) = NULL;
>> EX(old_error_reporting) = NULL;
>> EX(op_array) = op_array;
>> - EX(original_in_execution) = EG(in_execution);
>> EX(symbol_table) = EG(active_symbol_table);
>> EX(prev_execute_data) = EG(current_execute_data);
>> EG(current_execute_data) = execute_data;
>> + EX(nested) = nested;
>> + nested = 1;
>>
>> - EG(in_execution) = 1;
>> if (op_array->start_op) {
>> ZEND_VM_SET_OPCODE(op_array->start_op);
>> } else {
>> Index: Zend/zend_vm_gen.php
>> ===================================================================
>> RCS file: /repository/ZendEngine2/zend_vm_gen.php,v
>> retrieving revision 1.12.2.5.2.4.2.2
>> diff -u -p -d -r1.12.2.5.2.4.2.2 zend_vm_gen.php
>> --- Zend/zend_vm_gen.php 24 Jan 2008 09:41:39 -0000 1.12.2.5.2.4.2.2
>> +++ Zend/zend_vm_gen.php 10 Jun 2008 10:53:49 -0000
>> @@ -304,7 +304,7 @@ function helper_name($name, $spec, $op1,
>> }
>>
>> // Generates code for opcode handler or helper
>> -function gen_code($f, $spec, $kind, $code, $op1, $op2) {
>> +function gen_code($f, $spec, $kind, $export, $code, $op1, $op2) {
>> global $op1_type, $op2_type, $op1_get_zval_ptr, $op2_get_zval_ptr,
>> $op1_get_zval_ptr_ptr, $op2_get_zval_ptr_ptr,
>> $op1_get_obj_zval_ptr, $op2_get_obj_zval_ptr,
>> @@ -343,7 +343,9 @@ function gen_code($f, $spec, $kind, $cod
>> "/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m",
>> "/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m",
>> "/^#if\s+1\s*\\|\\|.*[^\\\\]$/m",
>> - "/^#if\s+0\s*&&.*[^\\\\]$/m"
>> + "/^#if\s+0\s*&&.*[^\\\\]$/m",
>> + "/^#ifdef\s+ZEND_VM_EXPORT\s*\n/m",
>> + "/^#ifndef\s+ZEND_VM_EXPORT\s*\n/m"
>> ),
>> array(
>> $op1_type[$op1],
>> @@ -374,6 +376,8 @@ function gen_code($f, $spec, $kind, $cod
>> "goto \\1".(($spec && $kind !=
>> ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2]):""),
>> "#if 1",
>> "#if 0",
>> + $export?"#if 1\n":"#if 0\n",
>> + $export?"#if 0\n":"#if 1\n"
>> ),
>> $code);
>>
>> @@ -481,7 +485,7 @@ function gen_handler($f, $spec, $kind, $
>> // Generate opcode handler's entry point according to selected threading model
>> switch($kind) {
>> case ZEND_VM_KIND_CALL:
>> - out($f,"static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
>> + out($f,"ZEND_FASTCALL static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
>> break;
>> case ZEND_VM_KIND_SWITCH:
>> if ($spec) {
>> @@ -502,7 +506,7 @@ function gen_handler($f, $spec, $kind, $
>> }
>>
>> // Generate opcode handler's code
>> - gen_code($f, $spec, $kind, $code, $op1, $op2);
>> + gen_code($f, $spec, $kind, 0, $code, $op1, $op2);
>> }
>>
>> // Generates helper
>> @@ -518,10 +522,10 @@ function gen_helper($f, $spec, $kind, $n
>> case ZEND_VM_KIND_CALL:
>> if ($param == null) {
>> // Helper without parameters
>> - out($f, "static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
>> + out($f, "ZEND_FASTCALL static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
>> } else {
>> // Helper with parameter
>> - out($f, "static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
>> + out($f, "ZEND_FASTCALL static int
>> ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
>> }
>> break;
>> case ZEND_VM_KIND_SWITCH:
>> @@ -533,7 +537,7 @@ function gen_helper($f, $spec, $kind, $n
>> }
>>
>> // Generate helper's code
>> - gen_code($f, $spec, $kind, $code, $op1, $op2);
>> + gen_code($f, $spec, $kind, 0, $code, $op1, $op2);
>> }
>>
>> // Generates array of opcode handlers (specialized or unspecialized)
>> @@ -685,10 +689,9 @@ function gen_null_handler($f) {
>> // for undefined opcodes, do we emit code for it only once
>> if (!$done) {
>> $done = 1;
>> - out($f,"static int
>> ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
>> + out($f,"ZEND_FASTCALL static int
>> ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
>> out($f,"{\n");
>> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode
>> %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
>> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
>> out($f,"}\n\n");
>> }
>> }
>> @@ -763,12 +766,10 @@ function gen_executor_code($f, $spec, $k
>> case ZEND_VM_KIND_SWITCH:
>> out($f,"default:\n");
>> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid
>> opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
>> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
>> break;
>> case ZEND_VM_KIND_GOTO:
>> out($f,"ZEND_NULL_HANDLER:\n");
>> out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid
>> opcode %d/%d/%d.\", EX(opline)->opcode, EX(opline)->op1.op_type, EX(opline)->op2.op_type);\n");
>> - out($f,"\tZEND_VM_RETURN_FROM_EXECUTE_LOOP();\n");
>> break;
>> }
>> }
>> @@ -790,7 +791,7 @@ function gen_executor($f, $skl, $spec, $
>> if (preg_match("/(.*)[{][%]([A-Z_]*)[%][}](.*)/", $line, $m)) {
>> switch ($m[2]) {
>> case "DEFINES":
>> - if (ZEND_VM_OLD_EXECUTOR) {
>> + if (ZEND_VM_OLD_EXECUTOR && $spec) {
>> out($f,"static int zend_vm_old_executor = 0;\n\n");
>> }
>> out($f,"static opcode_handler_t
>> zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op);\n\n");
>> @@ -799,6 +800,8 @@ function gen_executor($f, $skl, $spec, $
>> out($f,"\n");
>> out($f,"#define ZEND_VM_CONTINUE() return 0\n");
>> out($f,"#define ZEND_VM_RETURN() return 1\n");
>> + out($f,"#define ZEND_VM_ENTER() return 2\n");
>> + out($f,"#define ZEND_VM_LEAVE() return 3\n");
>> out($f,"#define
>> ZEND_VM_DISPATCH(opcode, opline) return
>> zend_vm_get_opcode_handler(opcode,
>> opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
>> out($f,"#define
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
>> out($f,"#undef EX\n");
>> @@ -807,7 +810,9 @@ function gen_executor($f, $skl, $spec, $
>> case ZEND_VM_KIND_SWITCH:
>> out($f,"\n");
>> out($f,"#define
>> ZEND_VM_CONTINUE() goto zend_vm_continue\n");
>> - out($f,"#define ZEND_VM_RETURN() return\n");
>> + out($f,"#define
>> ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n");
>> + out($f,"#define
>> ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n");
>> + out($f,"#define
>> ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
>> out($f,"#define
>> ZEND_VM_DISPATCH(opcode, opline) dispatch_handler =
>> zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n\n");
>> out($f,"#define
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
>> out($f,"#undef EX\n");
>> @@ -816,7 +821,9 @@ function gen_executor($f, $skl, $spec, $
>> case ZEND_VM_KIND_GOTO:
>> out($f,"\n");
>> out($f,"#define
>> ZEND_VM_CONTINUE() goto *(void**)(EX(opline)->handler)\n");
>> - out($f,"#define ZEND_VM_RETURN() return\n");
>> + out($f,"#define
>> ZEND_VM_RETURN() EG(in_execution) = original_in_execution; return\n");
>> + out($f,"#define
>> ZEND_VM_ENTER() op_array = EG(active_op_array); goto zend_vm_enter\n");
>> + out($f,"#define
>> ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
>> out($f,"#define
>> ZEND_VM_DISPATCH(opcode, opline) goto
>> *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n\n");
>> out($f,"#define
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n");
>> out($f,"#undef EX\n");
>> @@ -857,7 +864,10 @@ function gen_executor($f, $skl, $spec, $
>> }
>> break;
>> case "ZEND_VM_CONTINUE_LABEL":
>> - if ($kind == ZEND_VM_KIND_SWITCH) {
>> + if ($kind == ZEND_VM_KIND_CALL) {
>> + // Only SWITCH dispatch method use it
>> + out($f,$m[1]."\tint ret;".$m[3]."\n");
>> + } else if ($kind == ZEND_VM_KIND_SWITCH) {
>> // Only SWITCH dispatch method use it
>>
>> out($f,"zend_vm_continue:".$m[3]."\n");
>> } else {
>> @@ -868,7 +878,7 @@ function gen_executor($f, $skl, $spec, $
>> // Emit code that dispatches to opcode handler
>> switch ($kind) {
>> case ZEND_VM_KIND_CALL:
>> - out($f,
>> $m[1]."if (EX(opline)->handler(execute_data TSRMLS_CC) > 0)".$m[3]."\n");
>> + out($f,
>> $m[1]."if ((ret = EX(opline)->handler(execute_data TSRMLS_CC)) > 0)".$m[3]."\n");
>> break;
>> case ZEND_VM_KIND_SWITCH:
>> out($f,
>> $m[1]."dispatch_handler =
>> EX(opline)->handler;\nzend_vm_dispatch:\n".$m[1]."switch
>> ((int)dispatch_handler)".$m[3]."\n");
>> @@ -881,7 +891,18 @@ function gen_executor($f, $skl, $spec, $
>> case "INTERNAL_EXECUTOR":
>> if ($kind == ZEND_VM_KIND_CALL) {
>> // Executor is defined as a set of functions
>> - out($f, $m[1]."return;".$m[3]."\n");
>> + out($f, $m[1]."switch (ret) {\n" .
>> + $m[1]."\tcase 1:\n" .
>> +
>> $m[1]."\t\tEG(in_execution) = original_in_execution;\n".
>> + $m[1]."\t\treturn;\n".
>> + $m[1]."\tcase 2:\n" .
>> +
>> $m[1]."\t\top_array = EG(active_op_array);\n".
>> + $m[1]."\t\tgoto zend_vm_enter;\n".
>> + $m[1]."\tcase 3:\n" .
>> +
>> $m[1]."\t\texecute_data = EG(current_execute_data);\n".
>> + $m[1]."\tdefault:\n".
>> + $m[1]."\t\tbreak;\n".
>> + $m[1]."}".$m[3]."\n");
>> } else {
>> // Emit executor code
>> gen_executor_code($f, $spec, $kind, $m[1]);
>> @@ -1102,11 +1123,11 @@ function gen_vm($def, $skel) {
>> out($f, $GLOBALS['header_text']);
>>
>> // Support for ZEND_USER_OPCODE
>> - out($f, "static opcode_handler_t zend_user_opcode_handlers[256] = {");
>> + out($f, "static user_opcode_handler_t
>> zend_user_opcode_handlers[256] = {");
>> for ($i = 0; $i < 255; ++$i) {
>> - out($f, "(opcode_handler_t)NULL,");
>> + out($f, "(user_opcode_handler_t)NULL,");
>> }
>> - out($f, "(opcode_handler_t)NULL};\n\n");
>> + out($f, "(user_opcode_handler_t)NULL};\n\n");
>>
>> out($f, "static zend_uchar zend_user_opcodes[256] = {");
>> for ($i = 0; $i < 255; ++$i) {
>> @@ -1124,6 +1145,8 @@ function gen_vm($def, $skel) {
>> out($f,"#define EX(element) execute_data.element\n\n");
>> out($f,"#undef ZEND_VM_CONTINUE\n\n");
>> out($f,"#undef ZEND_VM_RETURN\n\n");
>> + out($f,"#undef ZEND_VM_ENTER\n\n");
>> + out($f,"#undef ZEND_VM_LEAVE\n\n");
>> out($f,"#undef ZEND_VM_DISPATCH\n\n");
>> out($f,"#undef
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
>> gen_executor($f, $skl, 0, ZEND_VM_KIND_CALL,
>> "old_execute", "zend_vm_use_old_executor", 1);
>> @@ -1180,10 +1203,14 @@ function gen_vm($def, $skel) {
>> out($f,"#define EX(element) execute_data->element\n\n");
>> out($f,"#undef ZEND_VM_CONTINUE\n");
>> out($f,"#undef ZEND_VM_RETURN\n");
>> + out($f,"#undef ZEND_VM_ENTER\n");
>> + out($f,"#undef ZEND_VM_LEAVE\n");
>> out($f,"#undef ZEND_VM_DISPATCH\n");
>> out($f,"#undef
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL\n\n");
>> out($f,"#define ZEND_VM_CONTINUE() return 0\n");
>> out($f,"#define ZEND_VM_RETURN() return 1\n");
>> + out($f,"#define ZEND_VM_ENTER() return 2\n");
>> + out($f,"#define ZEND_VM_LEAVE() return 3\n");
>> out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return
>> zend_vm_get_opcode_handler(opcode,
>> opline)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n\n");
>> out($f,"#define
>> ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_INTERNAL execute_data TSRMLS_CC\n\n");
>> }
>> @@ -1227,7 +1254,7 @@ function gen_vm($def, $skel) {
>> }
>> }
>> if (!$done) {
>> - gen_code($f, 0, ZEND_VM_KIND_CALL, $code, 'ANY', 'ANY');
>> + gen_code($f, 0, ZEND_VM_KIND_CALL, 1, $code, 'ANY', 'ANY');
>> }
>> }
>>
>
>
>
>
> Best regards,
> Marcus