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.
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');
}
}
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php