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 produceSIGSEGV
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.
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 produceSIGSEGV
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.
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