Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:38133 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 58195 invoked from network); 10 Jun 2008 11:12:05 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 10 Jun 2008 11:12:05 -0000 Authentication-Results: pb1.pair.com smtp.mail=dmitry@zend.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=dmitry@zend.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain zend.com designates 212.25.124.162 as permitted sender) X-PHP-List-Original-Sender: dmitry@zend.com X-Host-Fingerprint: 212.25.124.162 mail.zend.com Windows 2000 SP4, XP SP1 Received: from [212.25.124.162] ([212.25.124.162:43541] helo=mx1.zend.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id A6/77-15621-4816E484 for ; Tue, 10 Jun 2008 07:12:05 -0400 Received: from ws.home ([10.1.1.1]) by mx1.zend.com with Microsoft SMTPSVC(6.0.3790.3959); Tue, 10 Jun 2008 14:12:03 +0300 Message-ID: <484E617D.6080508@zend.com> Date: Tue, 10 Jun 2008 15:11:57 +0400 User-Agent: Thunderbird 2.0.0.14 (X11/20080501) MIME-Version: 1.0 To: PHP Internals List CC: Andi Gutmans , Stanislav Malyshev Content-Type: multipart/mixed; boundary="------------030906060507040305060908" X-OriginalArrivalTime: 10 Jun 2008 11:12:03.0859 (UTC) FILETIME=[CFDD1630:01C8CAEA] Subject: [PATCH] Executor improvements From: dmitry@zend.com (Dmitry Stogov) --------------030906060507040305060908 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit 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). 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. --------------030906060507040305060908 Content-Type: text/plain; name="recursion.diff.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="recursion.diff.txt" 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 + #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'); } } --------------030906060507040305060908--