Allow CALL executor to keep few very often used vaiables in CPU registers.

This is disabled by default yet, but may be enabled compiling zend_execute.c with -DHAVE_GCC_GLOBAL_REGS.
Only tested on Linux x86 and x86_64 with GCC 4.9.2.
This commit is contained in:
Dmitry Stogov 2015-03-13 03:28:21 +03:00
parent 6289f7e52f
commit 249c2323f4
5 changed files with 1756 additions and 1637 deletions

View File

@ -2035,6 +2035,16 @@ static zend_always_inline void zend_vm_stack_extend_call_frame(zend_execute_data
}
/* }}} */
#if HAVE_GCC_GLOBAL_REGS
# if defined(__GNUC__) && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"
# define ZEND_VM_IP_GLOBAL_REG "%edi"
# elif defined(__GNUC__) && defined(__x86_64__)
# define ZEND_VM_FP_GLOBAL_REG "%r14"
# define ZEND_VM_IP_GLOBAL_REG "%r15"
# endif
#endif
#define ZEND_VM_NEXT_OPCODE() \
CHECK_SYMBOL_TABLES() \
ZEND_VM_INC_OPCODE(); \

View File

@ -2018,10 +2018,10 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
EG(scope) = EX(func)->op_array.scope;
if (UNEXPECTED(EG(exception) != NULL)) {
const zend_op *opline = EX(opline);
const zend_op *old_opline = EX(opline);
zend_throw_exception_internal(NULL);
if (RETURN_VALUE_USED(opline)) {
zval_ptr_dtor(EX_VAR(opline->result.var));
if (RETURN_VALUE_USED(old_opline)) {
zval_ptr_dtor(EX_VAR(old_opline->result.var));
}
HANDLE_EXCEPTION_LEAVE();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{%DEFINES%}
ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *execute_data)
ZEND_API void {%EXECUTOR_NAME%}_ex(zend_execute_data *ex)
{
DCL_OPLINE

View File

@ -532,7 +532,7 @@ function gen_code($f, $spec, $kind, $export, $code, $op1, $op2, $name) {
} else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HANDLER", strlen("ZEND_VM_DISPATCH_TO_HANDLER")) == 0) {
return "return " . $matches[1] . ($spec?"_SPEC":"") . $prefix[$op1] . $prefix[$op2] . "_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
} else if (strncasecmp($matches[0], "ZEND_VM_DISPATCH_TO_HELPER_EX", strlen("ZEND_VM_DISPATCH_TO_HELPER_EX")) == 0) {
return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. ", ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);";
return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(" . $matches[2]. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC);";
} else {
return "return " . helper_name($matches[1], $spec, $op1, $op2) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)";
}
@ -635,7 +635,7 @@ function gen_handler($f, $spec, $kind, $name, $op1, $op2, $use, $code, $lineno)
// Generate opcode handler's entry point according to selected threading model
switch($kind) {
case ZEND_VM_KIND_CALL:
out($f,"static int ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
break;
case ZEND_VM_KIND_SWITCH:
if ($spec) {
@ -672,10 +672,10 @@ function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno)
case ZEND_VM_KIND_CALL:
if ($param == null) {
// Helper without parameters
out($f, "static int ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
out($f, "static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(ZEND_OPCODE_HANDLER_ARGS)\n");
} else {
// Helper with parameter
out($f, "static int ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param.", ZEND_OPCODE_HANDLER_ARGS)\n");
out($f, "static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ".$name.($spec?"_SPEC":"").$prefix[$op1].$prefix[$op2]."(".$param." ZEND_OPCODE_HANDLER_ARGS_DC)\n");
}
break;
case ZEND_VM_KIND_SWITCH:
@ -847,7 +847,7 @@ 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_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS)\n");
out($f,"{\n");
out($f,"\tzend_error_noreturn(E_ERROR, \"Invalid opcode %d/%d/%d.\", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type);\n");
out($f,"\tZEND_VM_NEXT_OPCODE(); /* Never reached */\n");
@ -957,21 +957,47 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
switch ($kind) {
case ZEND_VM_KIND_CALL:
out($f,"\n");
out($f,"#define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n");
out($f,"#define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n");
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
out($f,"register zend_execute_data *execute_data __asm__(ZEND_VM_FP_GLOBAL_REG);\n");
out($f,"#endif\n");
out($f,"\n");
out($f,"typedef int (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n");
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
out($f,"register const zend_op *opline __asm__(ZEND_VM_IP_GLOBAL_REG);\n");
out($f,"#endif\n");
out($f,"\n");
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
out($f,"# define ZEND_OPCODE_HANDLER_RET int\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS void\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC\n");
out($f,"#else\n");
out($f,"# define ZEND_OPCODE_HANDLER_RET int\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_DC , ZEND_OPCODE_HANDLER_ARGS\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC , ZEND_OPCODE_HANDLER_ARGS_PASSTHRU\n");
out($f,"#endif\n");
out($f,"\n");
out($f,"typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_HANDLER_ARGS);\n");
out($f,"\n");
out($f,"#undef OPLINE\n");
out($f,"#undef DCL_OPLINE\n");
out($f,"#undef USE_OPLINE\n");
out($f,"#undef LOAD_OPLINE\n");
out($f,"#undef SAVE_OPLINE\n");
out($f,"#define OPLINE EX(opline)\n");
out($f,"#define DCL_OPLINE\n");
out($f,"#define USE_OPLINE const zend_op *opline = EX(opline);\n");
out($f,"#define LOAD_OPLINE()\n");
out($f,"#define SAVE_OPLINE()\n");
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
out($f,"# define OPLINE opline\n");
out($f,"# define USE_OPLINE\n");
out($f,"# define LOAD_OPLINE() opline = EX(opline)\n");
out($f,"# define SAVE_OPLINE() EX(opline) = opline\n");
out($f,"#else\n");
out($f,"# define OPLINE EX(opline)\n");
out($f,"# define USE_OPLINE const zend_op *opline = EX(opline);\n");
out($f,"# define LOAD_OPLINE()\n");
out($f,"# define SAVE_OPLINE()\n");
out($f,"#endif\n");
out($f,"#undef CHECK_EXCEPTION\n");
out($f,"#undef HANDLE_EXCEPTION\n");
out($f,"#undef HANDLE_EXCEPTION_LEAVE\n");
@ -980,8 +1006,16 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"#define HANDLE_EXCEPTION_LEAVE() LOAD_OPLINE(); ZEND_VM_LEAVE()\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 1\n");
out($f,"#define ZEND_VM_LEAVE() return 2\n");
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n");
out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n");
out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; return 1\n");
out($f,"# define ZEND_VM_LEAVE() return 2\n");
out($f,"#else\n");
out($f,"# define ZEND_VM_ENTER() return 1\n");
out($f,"# define ZEND_VM_LEAVE() return 2\n");
out($f,"#endif\n");
out($f,"#define ZEND_VM_DISPATCH(opcode, opline) return ((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f,"\n");
break;
@ -1051,12 +1085,21 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
if ($kind == ZEND_VM_KIND_SWITCH) {
out($f,$m[1]."const void *dispatch_handler;\n");
}
// Emit local variables those are used for helpers' parameters
// Emit local variables those are used for helpers' parameters
foreach ($params as $param => $x) {
out($f,$m[1].$param.";\n");
}
out($f,$m[1]."zend_execute_data *execute_data = ex;\n");
} else {
skip_blanks($f, $m[1], $m[3]."\n");
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
out($f,$m[1]."const zend_op *orig_opline = opline;\n");
out($f,"#endif\n");
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n");
out($f,$m[1]."zend_execute_data *orig_execute_data = execute_data;\n");
out($f,$m[1]."execute_data = ex;\n");
out($f,"#else\n");
out($f,$m[1]."zend_execute_data *execute_data = ex;\n");
out($f,"#endif\n");
}
break;
case "INTERNAL_LABELS":
@ -1090,7 +1133,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
// Emit code that dispatches to opcode handler
switch ($kind) {
case ZEND_VM_KIND_CALL:
out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(execute_data)) != 0))".$m[3]."\n");
out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f, $m[1]."dispatch_handler = OPLINE->handler;\nzend_vm_dispatch:\n".$m[1]."switch ((int)(uintptr_t)dispatch_handler)".$m[3]."\n");
@ -1103,11 +1146,23 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
case "INTERNAL_EXECUTOR":
if ($kind == ZEND_VM_KIND_CALL) {
// Executor is defined as a set of functions
out($f, $m[1]."if (EXPECTED(ret > 0)) {\n" .
out($f,
"#ifdef ZEND_VM_FP_GLOBAL_REG\n" .
$m[1]."execute_data = orig_execute_data;\n" .
"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
$m[1]."opline = orig_opline;\n" .
"# endif\n" .
$m[1]."return;\n" .
"#else\n" .
$m[1]."if (EXPECTED(ret > 0)) {\n" .
$m[1]."\texecute_data = EG(current_execute_data);\n".
$m[1]."} else {\n" .
"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
$m[1]."\topline = orig_opline;\n" .
"# endif\n".
$m[1]."\treturn;\n".
$m[1]."}".$m[3]."\n");
$m[1]."}\n".
"#endif\n");
} else {
// Emit executor code
gen_executor_code($f, $spec, $kind, $m[1]);
@ -1455,7 +1510,7 @@ function gen_vm($def, $skel) {
if ($h['param'] == null) {
out($f, "ZEND_OPCODE_HANDLER_ARGS)\n");
} else {
out($f, $h['param']. ", ZEND_OPCODE_HANDLER_ARGS)\n");
out($f, $h['param']. " ZEND_OPCODE_HANDLER_ARGS_DC)\n");
}
$code = $h['code'];
}