Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ php
**/tests/**/*.exp
**/tests/**/*.log
**/tests/**/*.sh
**/tests/**/*.stdin

# Generated by some test cases
**/tests/**/*.db
Expand Down
3 changes: 1 addition & 2 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -5656,11 +5656,10 @@ ZEND_VM_HOT_HANDLER(199, ZEND_CHECK_UNDEF_ARGS, UNUSED, UNUSED)

ZEND_VM_COLD_HELPER(zend_missing_arg_helper, ANY, ANY)
{
#ifdef ZEND_VM_IP_GLOBAL_REG
USE_OPLINE

SAVE_OPLINE();
#endif

zend_missing_arg_error(execute_data);
HANDLE_EXCEPTION();
}
Expand Down
372 changes: 195 additions & 177 deletions Zend/zend_vm_execute.h

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions Zend/zend_vm_execute.skl
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#include "Zend/zend_vm_opcodes.h"

{%DEFINES%}

#if (ZEND_VM_KIND != ZEND_VM_KIND_CALL) && (ZEND_GCC_VERSION >= 4000) && !defined(__clang__)
Expand Down
92 changes: 55 additions & 37 deletions Zend/zend_vm_gen.php
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec) {
if (isset($matches[2])) {
// extra args
$args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2);
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))";
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX " . $args . "))";
}
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
}
Expand Down Expand Up @@ -852,7 +852,7 @@ function($matches) use ($spec, $prefix, $op1, $op2, $extra_spec, $name) {
if (isset($matches[2])) {
// extra args
$args = substr(preg_replace("/,\s*[A-Za-z0-9_]*\s*,\s*([^,)\s]*)\s*/", ", $1", $matches[2]), 2);
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(" . $args. " ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC))";
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX " . $args . "))";
}
return "ZEND_VM_TAIL_CALL(" . helper_name($matches[1], $spec, $op1, $op2, $extra_spec) . "(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))";
}
Expand Down Expand Up @@ -1164,7 +1164,7 @@ function gen_helper($f, $spec, $kind, $name, $op1, $op2, $param, $code, $lineno,
out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS)\n");
} else {
// Helper with parameter
out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name($param ZEND_OPCODE_HANDLER_ARGS_DC)\n");
out($f, "static$zend_attributes ZEND_OPCODE_HANDLER_RET$zend_fastcall $spec_name(ZEND_OPCODE_HANDLER_ARGS_EX $param)\n");
}
break;
case ZEND_VM_KIND_SWITCH:
Expand Down Expand Up @@ -1870,13 +1870,13 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\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,"# define ZEND_OPCODE_HANDLER_ARGS_EX\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX\n");
out($f,"#else\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,"# define ZEND_OPCODE_HANDLER_ARGS zend_execute_data *execute_data, const zend_op *opline\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU execute_data, opline\n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_EX ZEND_OPCODE_HANDLER_ARGS, \n");
out($f,"# define ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX ZEND_OPCODE_HANDLER_ARGS_PASSTHRU, \n");
out($f,"#endif\n");
out($f,"\n");
out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
Expand All @@ -1902,10 +1902,10 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"# define ZEND_VM_COLD ZEND_COLD ZEND_OPT_SIZE\n");
}
out($f,"#else\n");
out($f,"# define ZEND_OPCODE_HANDLER_RET int\n");
out($f,"# define ZEND_OPCODE_HANDLER_RET const zend_op *\n");
out($f,"# define ZEND_VM_TAIL_CALL(call) return call\n");
out($f,"# define ZEND_VM_CONTINUE() return 0\n");
out($f,"# define ZEND_VM_RETURN() return -1\n");
out($f,"# define ZEND_VM_CONTINUE() return opline\n");
out($f,"# define ZEND_VM_RETURN() return (const zend_op*)ZEND_VM_ENTER_BIT\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"# define ZEND_VM_HOT\n");
}
Expand All @@ -1914,8 +1914,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
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,"#define DCL_OPLINE\n");
out($f,"#ifdef ZEND_VM_IP_GLOBAL_REG\n");
out($f,"# define DCL_OPLINE\n");
out($f,"# define OPLINE opline\n");
out($f,"# define USE_OPLINE\n");
out($f,"# define LOAD_OPLINE() opline = EX(opline)\n");
Expand All @@ -1924,12 +1924,13 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"# define SAVE_OPLINE() EX(opline) = opline\n");
out($f,"# define SAVE_OPLINE_EX() SAVE_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 LOAD_OPLINE_EX()\n");
out($f,"# define LOAD_NEXT_OPLINE() ZEND_VM_INC_OPCODE()\n");
out($f,"# define SAVE_OPLINE()\n");
out($f,"# define DCL_OPLINE const zend_op *opline;\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 LOAD_OPLINE_EX() opline = EX(opline)\n");
out($f,"# define LOAD_NEXT_OPLINE() opline = EX(opline) + 1\n");
out($f,"# define SAVE_OPLINE() EX(opline) = opline\n");
out($f,"# define SAVE_OPLINE_EX()\n");
out($f,"#endif\n");
out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n");
Expand All @@ -1943,9 +1944,10 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"# define ZEND_VM_ENTER() opline = EG(current_execute_data)->opline; ZEND_VM_ENTER_EX()\n");
out($f,"# define ZEND_VM_LEAVE() return 2\n");
out($f,"#else\n");
out($f,"# define ZEND_VM_ENTER_EX() return 1\n");
out($f,"# define ZEND_VM_ENTER() return 1\n");
out($f,"# define ZEND_VM_LEAVE() return 2\n");
out($f,"# define ZEND_VM_ENTER_BIT 1ULL\n");
out($f,"# define ZEND_VM_ENTER_EX() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT)\n");
out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n");
out($f,"# define ZEND_VM_LEAVE() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT)\n");
out($f,"#endif\n");
out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n");
out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
Expand Down Expand Up @@ -2119,12 +2121,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
}
break;
case "ZEND_VM_CONTINUE_LABEL":
if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) {
// Only SWITCH dispatch method use it
out($f,"#if !defined(ZEND_VM_FP_GLOBAL_REG) || !defined(ZEND_VM_IP_GLOBAL_REG)\n");
out($f,$m[1]."\tint ret;".$m[3]."\n");
out($f,"#endif\n");
} else if ($kind == ZEND_VM_KIND_SWITCH) {
if ($kind == ZEND_VM_KIND_SWITCH) {
// Only SWITCH dispatch method use it
out($f,"zend_vm_continue:".$m[3]."\n");
} else {
Expand All @@ -2143,16 +2140,17 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
case ZEND_VM_KIND_HYBRID:
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f, $m[1]."HYBRID_SWITCH()".$m[3]."\n");
out($f,"#else\n");
out($f,"#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n");
case ZEND_VM_KIND_CALL:
out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG) && defined(ZEND_VM_IP_GLOBAL_REG)\n");
out($f, $m[1]."((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f, $m[1]."if (UNEXPECTED(!OPLINE))".$m[3]."\n");
out($f,"#else\n");
out($f, $m[1]."if (UNEXPECTED((ret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) != 0))".$m[3]."\n");
out($f, $m[1]."opline = ((opcode_handler_t)opline->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f, $m[1]."if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT)))".$m[3]."\n");
out($f,"#endif\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#endif\n");
out($f,"#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n");
}
break;
}
Expand All @@ -2168,7 +2166,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
if ($kind == ZEND_VM_KIND_CALL || $kind == ZEND_VM_KIND_HYBRID) {
// Executor is defined as a set of functions
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#else\n");
out($f,"#else /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n");
}
out($f,
"#ifdef ZEND_VM_FP_GLOBAL_REG\n" .
Expand All @@ -2178,18 +2176,19 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
"# endif\n" .
$m[1]."return;\n" .
"#else\n" .
$m[1]."if (EXPECTED(ret > 0)) {\n" .
$m[1]."opline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT);\n".
$m[1]."if (EXPECTED(opline != NULL)) {\n" .
$m[1]."\texecute_data = EG(current_execute_data);\n".
$m[1]."\tZEND_VM_LOOP_INTERRUPT_CHECK();\n".
$m[1]."} else {\n" .
"# ifdef ZEND_VM_IP_GLOBAL_REG\n" .
$m[1]."\topline = vm_stack_data.orig_opline;\n" .
"# endif\n".
"# endif\n" .
$m[1]."\treturn;\n".
$m[1]."}\n".
"#endif\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#endif\n");
out($f,"#endif /* ZEND_VM_KIND != ZEND_VM_KIND_HYBRID */\n");
}
}
break;
Expand Down Expand Up @@ -2335,6 +2334,8 @@ function gen_vm_opcodes_header(
): string {
$str = HEADER_TEXT;
$str .= "#ifndef ZEND_VM_OPCODES_H\n#define ZEND_VM_OPCODES_H\n\n";
$str .= "#include \"Zend/zend_portability.h\"\n";
$str .= "\n";
$str .= "#define ZEND_VM_SPEC\t\t" . ZEND_VM_SPEC . "\n";
$str .= "#define ZEND_VM_LINES\t\t" . ZEND_VM_LINES . "\n";
$str .= "#define ZEND_VM_KIND_CALL\t" . ZEND_VM_KIND_CALL . "\n";
Expand Down Expand Up @@ -2968,6 +2969,7 @@ function gen_vm($def, $skel) {
out($f, "\topcode_handler_t handler;\n");
out($f,"#endif\n");
}
out($f, "\tDCL_OPLINE;\n");
out($f, "\tint ret;\n");
out($f, "#ifdef ZEND_VM_IP_GLOBAL_REG\n");
out($f, "\tconst zend_op *orig_opline = opline;\n");
Expand Down Expand Up @@ -3001,8 +3003,24 @@ function gen_vm($def, $skel) {
out($f, "\t\tret = -1;\n");
out($f, "\t}\n");
out($f, "#else\n");
out($f, "\tret = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");
out($f, "\tSAVE_OPLINE();\n");
out($f, "\topline = ((opcode_handler_t)OPLINE->handler)(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n");

out($f, "if (UNEXPECTED(((uintptr_t)opline & ZEND_VM_ENTER_BIT))) {\n");
out($f, "\t\topline = (const zend_op*)((uintptr_t)opline & ~ZEND_VM_ENTER_BIT);\n");
out($f, "\t\tif (EXPECTED(opline)) {\n");
out($f, "\t\t\t/* ZEND_VM_ENTER() or ZEND_VM_LEAVE() */\n");
out($f, "\t\t\tret = EG(current_execute_data) != ex ? (int)(EG(current_execute_data)->prev_execute_data != ex) + 1 : 0;\n");
out($f, "\t\t\texecute_data = EG(current_execute_data);\n");
out($f, "\t\t\tSAVE_OPLINE();\n");
out($f, "\t\t} else {\n");
out($f, "\t\t\t/* ZEND_VM_RETURN() */\n");
out($f, "\t\t\tret = -1;\n");
out($f, "\t\t}\n");
out($f, "\t} else {\n");
out($f, "\t\t/* ZEND_VM_CONTINUE() */\n");
out($f, "\t\tSAVE_OPLINE();\n");
out($f, "\t\tret = 0;\n");
out($f, "\t}\n");
out($f, "#endif\n");
out($f, "#ifdef ZEND_VM_FP_GLOBAL_REG\n");
out($f, "\texecute_data = orig_execute_data;\n");
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_vm_opcodes.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 20 additions & 7 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ static const void *zend_jit_func_trace_counter_handler = NULL;
static const void *zend_jit_ret_trace_counter_handler = NULL;
static const void *zend_jit_loop_trace_counter_handler = NULL;

static int ZEND_FASTCALL zend_runtime_jit(void);
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS);

static int zend_jit_trace_op_len(const zend_op *opline);
static int zend_jit_trace_may_exit(const zend_op_array *op_array, const zend_op *opline);
Expand Down Expand Up @@ -2871,7 +2871,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
if (GCC_GLOBAL_REGS) {
ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
} else {
ir_RETURN(ir_CONST_I32(1)); /* ZEND_VM_ENTER */
zend_jit_vm_enter(jit, jit_IP(jit));
}
ir_IF_TRUE(if_hook_enter);
}
Expand Down Expand Up @@ -3074,11 +3074,18 @@ static int zend_real_jit_func(zend_op_array *op_array, zend_script *script, cons
}

/* Run-time JIT handler */
static int ZEND_FASTCALL zend_runtime_jit(void)
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS)
{
zend_execute_data *execute_data = EG(current_execute_data);
#if GCC_GLOBAL_REGS
zend_execute_data *execute_data;
zend_op *opline;
#else
const zend_op *orig_opline = opline;
#endif

execute_data = EG(current_execute_data);
zend_op_array *op_array = &EX(func)->op_array;
zend_op *opline = op_array->opcodes;
opline = op_array->opcodes;
zend_jit_op_array_extension *jit_extension;
bool do_bailout = 0;

Expand All @@ -3097,7 +3104,7 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
}
}
jit_extension = (zend_jit_op_array_extension*)ZEND_FUNC_INFO(op_array);
opline->handler = jit_extension->orig_handler;
((zend_op*)opline)->handler = jit_extension->orig_handler;

/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, NULL, ZEND_JIT_ON_FIRST_EXEC);
Expand All @@ -3116,7 +3123,11 @@ static int ZEND_FASTCALL zend_runtime_jit(void)
}

/* JIT-ed code is going to be called by VM */
return 0;
#if GCC_GLOBAL_REGS
return; // ZEND_VM_CONTINUE
#else
return orig_opline; // ZEND_VM_CONTINUE
#endif
}

void zend_jit_check_funcs(HashTable *function_table, bool is_method) {
Expand Down Expand Up @@ -3171,6 +3182,8 @@ void ZEND_FASTCALL zend_jit_hot_func(zend_execute_data *execute_data, const zend
op_array->opcodes[i].handler = jit_extension->orig_handlers[i];
}

EX(opline) = opline;

/* perform real JIT for this function */
zend_real_jit_func(op_array, NULL, opline, ZEND_JIT_ON_HOT_COUNTERS);
} zend_catch {
Expand Down
Loading
Loading