Introduce zend_vm_opcode_handler_t / zend_vm_opcode_handler_func_t

This reduces the chances of confusion between opcode handlers used by the
VM, and opcode handler functions used for tracing or debugging. Depending
on the VM, zend_vm_opcode_handler_t may not be a function. For instance in
the HYBRID VM this is a label pointer.

Closes GH-19006
This commit is contained in:
Arnaud Le Blanc 2025-07-02 09:23:16 +02:00
parent 747ecce51f
commit 7f7b3cdb90
No known key found for this signature in database
10 changed files with 130 additions and 99 deletions

View file

@ -24,6 +24,7 @@
#include "zend_types.h"
#include "zend_map_ptr.h"
#include "zend_alloc.h"
#include "zend_vm_opcodes.h"
#include <stdarg.h>
#include <stdint.h>
@ -135,7 +136,7 @@ void zend_const_expr_to_zval(zval *result, zend_ast **ast_ptr, bool allow_dynami
typedef int (*user_opcode_handler_t) (zend_execute_data *execute_data);
struct _zend_op {
const void *handler;
zend_vm_opcode_handler_t handler;
znode_op op1;
znode_op op2;
znode_op result;

22
Zend/zend_vm_execute.h generated
View file

@ -321,14 +321,14 @@ static uint8_t zend_user_opcodes[256] = {0,
#define SPEC_RULE_OBSERVER 0x02000000
static const uint32_t *zend_spec_handlers;
static const void * const *zend_opcode_handlers;
static zend_vm_opcode_handler_t const *zend_opcode_handlers;
static int zend_handlers_count;
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
static const void * const * zend_opcode_handler_funcs;
static zend_vm_opcode_handler_func_t const * zend_opcode_handler_funcs;
static zend_op hybrid_halt_op;
#endif
#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC
static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);
static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);
#endif
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
@ -58666,8 +58666,8 @@ ZEND_API void execute_ex(zend_execute_data *ex)
(void*)&&ZEND_FE_FETCH_R_SIMPLE_SPEC_VAR_CV_RETVAL_USED_LABEL,
(void*)&&ZEND_NULL_LABEL
};
zend_opcode_handlers = (const void **) labels;
zend_handlers_count = sizeof(labels) / sizeof(void*);
zend_opcode_handlers = (zend_vm_opcode_handler_t*) labels;
zend_handlers_count = sizeof(labels) / sizeof(labels[0]);
memset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));
hybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;
#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE
@ -64398,7 +64398,11 @@ ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value)
void zend_vm_init(void)
{
static const void * const labels[] = {
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
static zend_vm_opcode_handler_func_t const labels[] = {
#else
static zend_vm_opcode_handler_t const labels[] = {
#endif
ZEND_NOP_SPEC_HANDLER,
ZEND_ADD_SPEC_CONST_CONST_HANDLER,
ZEND_ADD_SPEC_CONST_TMPVARCV_HANDLER,
@ -68158,7 +68162,7 @@ void zend_vm_init(void)
execute_ex(NULL);
#else
zend_opcode_handlers = labels;
zend_handlers_count = sizeof(labels) / sizeof(void*);
zend_handlers_count = sizeof(labels) / sizeof(labels[0]);
zend_spec_handlers = specs;
#endif
VM_TRACE_START();
@ -68200,7 +68204,7 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op)
}
zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler);
ZEND_ASSERT(zv != NULL);
op->handler = (const void *)(uintptr_t)Z_LVAL_P(zv);
op->handler = (zend_vm_opcode_handler_t)(uintptr_t)Z_LVAL_P(zv);
}
ZEND_API void ZEND_FASTCALL zend_deserialize_opcode_handler(zend_op *op)
@ -68286,7 +68290,7 @@ static uint32_t ZEND_FASTCALL zend_vm_get_opcode_handler_idx(uint32_t spec, cons
}
#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC
static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)
static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)
{
return zend_opcode_handlers[zend_vm_get_opcode_handler_idx(zend_spec_handlers[opcode], op)];
}

View file

@ -126,7 +126,7 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op)
}
zv = zend_hash_index_find(zend_handlers_table, (zend_long)(uintptr_t)op->handler);
ZEND_ASSERT(zv != NULL);
op->handler = (const void *)(uintptr_t)Z_LVAL_P(zv);
op->handler = (zend_vm_opcode_handler_t)(uintptr_t)Z_LVAL_P(zv);
}
ZEND_API void ZEND_FASTCALL zend_deserialize_opcode_handler(zend_op *op)

View file

@ -1186,7 +1186,7 @@ function gen_null_label($f, $kind, $prolog) {
out($f,$prolog."ZEND_NULL_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1,\n");
out($f,$prolog."-1,\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n");
@ -1388,7 +1388,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
out($f,"$prolog{$spec_name}_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)$switch_labels[$spec_name],\n");
out($f,$prolog."$switch_labels[$spec_name],\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&{$spec_name}_LABEL,\n");
@ -1436,7 +1436,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
out($f,$prolog."ZEND_NULL_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1,\n");
out($f,$prolog."-1,\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n");
@ -1467,7 +1467,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
out($f,$prolog.$dsc["op"]."_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)".((string)$num).",\n");
out($f,$prolog.((string)$num).",\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&".$dsc["op"]."_LABEL,\n");
@ -1480,7 +1480,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
out($f,$prolog."ZEND_NULL_HANDLER,\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1,\n");
out($f,$prolog."-1,\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_LABEL,\n");
@ -1497,7 +1497,7 @@ function gen_labels($f, $spec, $kind, $prolog, &$specs, $switch_labels = array()
out($f,$prolog."ZEND_NULL_HANDLER\n");
break;
case ZEND_VM_KIND_SWITCH:
out($f,$prolog."(void*)(uintptr_t)-1\n");
out($f,$prolog."-1\n");
break;
case ZEND_VM_KIND_GOTO:
out($f,$prolog."(void*)&&ZEND_NULL_LABEL\n");
@ -1813,16 +1813,16 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"#define SPEC_RULE_OBSERVER 0x02000000\n");
out($f,"\n");
out($f,"static const uint32_t *zend_spec_handlers;\n");
out($f,"static const void * const *zend_opcode_handlers;\n");
out($f,"static zend_vm_opcode_handler_t const *zend_opcode_handlers;\n");
out($f,"static int zend_handlers_count;\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,"static const void * const * zend_opcode_handler_funcs;\n");
out($f,"static zend_vm_opcode_handler_func_t const * zend_opcode_handler_funcs;\n");
out($f,"static zend_op hybrid_halt_op;\n");
out($f,"#endif\n");
}
out($f,"#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n");
out($f,"static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);\n");
out($f,"static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op);\n");
out($f,"#endif\n\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
@ -2040,7 +2040,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
break;
case "HELPER_VARS":
if ($kind == ZEND_VM_KIND_SWITCH) {
out($f,$m[1]."const void *dispatch_handler;\n");
out($f,$m[1]."zend_vm_opcode_handler_t dispatch_handler;\n");
}
if ($kind != ZEND_VM_KIND_CALL && count($params)) {
if ($kind == ZEND_VM_KIND_HYBRID) {
@ -2097,8 +2097,8 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,$prolog."\tstatic const void * const labels[] = {\n");
gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_GOTO : $kind, $prolog."\t\t", $specs);
out($f,$prolog."\t};\n");
out($f,$prolog."\tzend_opcode_handlers = (const void **) labels;\n");
out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(void*);\n");
out($f,$prolog."\tzend_opcode_handlers = (zend_vm_opcode_handler_t*) labels;\n");
out($f,$prolog."\tzend_handlers_count = sizeof(labels) / sizeof(labels[0]);\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,$prolog."\tmemset(&hybrid_halt_op, 0, sizeof(hybrid_halt_op));\n");
out($f,$prolog."\thybrid_halt_op.handler = (void*)&&HYBRID_HALT_LABEL;\n");
@ -2212,7 +2212,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,$prolog."zend_spec_handlers = specs;\n");
out($f,$prolog.$executor_name."_ex(NULL);\n");
} else {
out($f,$prolog."static const void * const labels[] = {\n");
out($f,"#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)\n");
out($f,$prolog."static zend_vm_opcode_handler_func_t const labels[] = {\n");
out($f,"#else\n");
out($f,$prolog."static zend_vm_opcode_handler_t const labels[] = {\n");
out($f,"#endif\n");
gen_labels($f, $spec, ($kind == ZEND_VM_KIND_HYBRID) ? ZEND_VM_KIND_CALL : $kind, $prolog."\t", $specs, $switch_labels);
out($f,$prolog."};\n");
out($f,$prolog."static const uint32_t specs[] = {\n");
@ -2226,7 +2230,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name)
out($f,"#else\n");
}
out($f,$prolog."zend_opcode_handlers = labels;\n");
out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(void*);\n");
out($f,$prolog."zend_handlers_count = sizeof(labels) / sizeof(labels[0]);\n");
out($f,$prolog."zend_spec_handlers = specs;\n");
if ($kind == ZEND_VM_KIND_HYBRID) {
out($f,"#endif\n");
@ -2359,6 +2363,20 @@ function gen_vm_opcodes_header(
$str .= "# endif\n";
$str .= "#endif\n";
$str .= "\n";
$str .= "#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID\n";
$str .= "typedef const void* zend_vm_opcode_handler_t;\n";
$str .= "typedef void (ZEND_FASTCALL *zend_vm_opcode_handler_func_t)(void);\n";
$str .= "#elif ZEND_VM_KIND == ZEND_VM_KIND_CALL\n";
$str .= "typedef const struct _zend_op *(ZEND_FASTCALL *zend_vm_opcode_handler_t)(struct _zend_execute_data *execute_data, const struct _zend_op *opline);\n";
$str .= "typedef const struct _zend_op *(ZEND_FASTCALL *zend_vm_opcode_handler_func_t)(struct _zend_execute_data *execute_data, const struct _zend_op *opline);\n";
$str .= "#elif ZEND_VM_KIND == ZEND_VM_KIND_SWITCH\n";
$str .= "typedef int zend_vm_opcode_handler_t;\n";
$str .= "#elif ZEND_VM_KIND == ZEND_VM_KIND_GOTO\n";
$str .= "typedef const void* zend_vm_opcode_handler_t;\n";
$str .= "#else\n";
$str .= "# error\n";
$str .= "#endif\n";
$str .= "\n";
foreach ($vm_op_flags as $name => $val) {
$str .= sprintf("#define %-24s 0x%08x\n", $name, $val);
}
@ -2840,7 +2858,7 @@ function gen_vm($def, $skel) {
}
out($f, "}\n\n");
out($f, "#if (ZEND_VM_KIND != ZEND_VM_KIND_HYBRID) || !ZEND_VM_SPEC\n");
out($f, "static const void *zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)\n");
out($f, "static zend_vm_opcode_handler_t zend_vm_get_opcode_handler(uint8_t opcode, const zend_op* op)\n");
out($f, "{\n");
if (!ZEND_VM_SPEC) {
out($f, "\treturn zend_opcode_handlers[zend_vm_get_opcode_handler_idx(opcode, op)];\n");

14
Zend/zend_vm_opcodes.h generated
View file

@ -42,6 +42,20 @@
# endif
#endif
#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID
typedef const void* zend_vm_opcode_handler_t;
typedef void (ZEND_FASTCALL *zend_vm_opcode_handler_func_t)(void);
#elif ZEND_VM_KIND == ZEND_VM_KIND_CALL
typedef const struct _zend_op *(ZEND_FASTCALL *zend_vm_opcode_handler_t)(struct _zend_execute_data *execute_data, const struct _zend_op *opline);
typedef const struct _zend_op *(ZEND_FASTCALL *zend_vm_opcode_handler_func_t)(struct _zend_execute_data *execute_data, const struct _zend_op *opline);
#elif ZEND_VM_KIND == ZEND_VM_KIND_SWITCH
typedef int zend_vm_opcode_handler_t;
#elif ZEND_VM_KIND == ZEND_VM_KIND_GOTO
typedef const void* zend_vm_opcode_handler_t;
#else
# error
#endif
#define ZEND_VM_OP_SPEC 0x00000001
#define ZEND_VM_OP_CONST 0x00000002
#define ZEND_VM_OP_TMPVAR 0x00000004

View file

@ -90,13 +90,13 @@ static size_t dasm_size = 0;
static zend_long jit_bisect_pos = 0;
static const void *zend_jit_runtime_jit_handler = NULL;
static const void *zend_jit_profile_jit_handler = NULL;
static const void *zend_jit_func_hot_counter_handler = NULL;
static const void *zend_jit_loop_hot_counter_handler = NULL;
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 zend_vm_opcode_handler_t zend_jit_runtime_jit_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_profile_jit_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_func_hot_counter_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_loop_hot_counter_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_func_trace_counter_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_ret_trace_counter_handler = NULL;
static zend_vm_opcode_handler_t zend_jit_loop_trace_counter_handler = NULL;
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_runtime_jit(ZEND_OPCODE_HANDLER_ARGS);
@ -1417,7 +1417,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
zend_jit_ctx ctx;
zend_jit_ctx *jit = &ctx;
zend_jit_reg_var *ra = NULL;
void *handler;
zend_vm_opcode_handler_t handler;
int call_level = 0;
void *checkpoint = NULL;
bool recv_emitted = 0; /* emitted at least one RECV opcode */
@ -3213,7 +3213,7 @@ static void zend_jit_setup_hot_counters_ex(zend_op_array *op_array, zend_cfg *cf
}
}
opline->handler = (const void*)zend_jit_func_hot_counter_handler;
opline->handler = zend_jit_func_hot_counter_handler;
}
if (JIT_G(hot_loop)) {
@ -3223,7 +3223,7 @@ static void zend_jit_setup_hot_counters_ex(zend_op_array *op_array, zend_cfg *cf
if ((cfg->blocks[i].flags & ZEND_BB_REACHABLE) &&
(cfg->blocks[i].flags & ZEND_BB_LOOP_HEADER)) {
op_array->opcodes[cfg->blocks[i].start].handler =
(const void*)zend_jit_loop_hot_counter_handler;
zend_jit_loop_hot_counter_handler;
}
}
}
@ -3316,7 +3316,7 @@ int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
jit_extension->op_array = op_array;
jit_extension->orig_handler = (void*)opline->handler;
ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
opline->handler = (const void*)zend_jit_runtime_jit_handler;
opline->handler = zend_jit_runtime_jit_handler;
zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
return SUCCESS;
@ -3346,7 +3346,7 @@ int zend_jit_op_array(zend_op_array *op_array, zend_script *script)
jit_extension->op_array = op_array;
jit_extension->orig_handler = (void*)opline->handler;
ZEND_SET_FUNC_INFO(op_array, (void*)jit_extension);
opline->handler = (const void*)zend_jit_profile_jit_handler;
opline->handler = zend_jit_profile_jit_handler;
zend_shared_alloc_register_xlat_entry(op_array->opcodes, jit_extension);
}
@ -3566,23 +3566,23 @@ void zend_jit_protect(void)
static void zend_jit_init_handlers(void)
{
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
zend_jit_runtime_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_runtime_jit];
zend_jit_profile_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_profile_jit];
zend_jit_func_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_hot_counter];
zend_jit_loop_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_hot_counter];
zend_jit_func_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_trace_counter];
zend_jit_ret_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_ret_trace_counter];
zend_jit_loop_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_trace_counter];
} else {
zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit;
zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper;
zend_jit_func_hot_counter_handler = (const void*)zend_jit_func_counter_helper;
zend_jit_loop_hot_counter_handler = (const void*)zend_jit_loop_counter_helper;
zend_jit_func_trace_counter_handler = (const void*)zend_jit_func_trace_helper;
zend_jit_ret_trace_counter_handler = (const void*)zend_jit_ret_trace_helper;
zend_jit_loop_trace_counter_handler = (const void*)zend_jit_loop_trace_helper;
}
#if ZEND_VM_KIND == ZEND_VM_KIND_HYBRID
zend_jit_runtime_jit_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_runtime_jit];
zend_jit_profile_jit_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_profile_jit];
zend_jit_func_hot_counter_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_func_hot_counter];
zend_jit_loop_hot_counter_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_loop_hot_counter];
zend_jit_func_trace_counter_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_func_trace_counter];
zend_jit_ret_trace_counter_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_ret_trace_counter];
zend_jit_loop_trace_counter_handler = (zend_vm_opcode_handler_t)zend_jit_stub_handlers[jit_stub_hybrid_loop_trace_counter];
#else
zend_jit_runtime_jit_handler = zend_runtime_jit;
zend_jit_profile_jit_handler = zend_jit_profile_helper;
zend_jit_func_hot_counter_handler = zend_jit_func_counter_helper;
zend_jit_loop_hot_counter_handler = zend_jit_loop_counter_helper;
zend_jit_func_trace_counter_handler = zend_jit_func_trace_helper;
zend_jit_ret_trace_counter_handler = zend_jit_ret_trace_helper;
zend_jit_loop_trace_counter_handler = zend_jit_loop_trace_helper;
#endif
}
static void zend_jit_globals_ctor(zend_jit_globals *jit_globals)
@ -3945,9 +3945,9 @@ static void zend_jit_restart_preloaded_op_array(zend_op_array *op_array)
}
}
if (func_info->flags & ZEND_FUNC_JIT_ON_FIRST_EXEC) {
opline->handler = (const void*)zend_jit_runtime_jit_handler;
opline->handler = zend_jit_runtime_jit_handler;
} else {
opline->handler = (const void*)zend_jit_profile_jit_handler;
opline->handler = zend_jit_profile_jit_handler;
}
#endif
}

View file

@ -26,6 +26,7 @@
#include "Zend/zend_constants.h"
#include "Zend/Optimizer/zend_func_info.h"
#include "Zend/Optimizer/zend_call_graph.h"
#include "zend_vm_opcodes.h"
/* Address Encoding */
typedef uintptr_t zend_jit_addr;
@ -130,7 +131,7 @@ static zend_always_inline bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_
typedef struct _zend_jit_op_array_extension {
zend_func_info func_info;
const zend_op_array *op_array;
const void *orig_handler;
zend_vm_opcode_handler_t orig_handler;
} zend_jit_op_array_extension;
/* Profiler */
@ -169,7 +170,7 @@ typedef struct _zend_jit_op_array_hot_extension {
zend_func_info func_info;
const zend_op_array *op_array;
int16_t *counter;
const void *orig_handlers[1];
zend_vm_opcode_handler_t orig_handlers[1];
} zend_jit_op_array_hot_extension;
#define zend_jit_op_array_hash(op_array) \
@ -225,9 +226,6 @@ extern const zend_op *zend_jit_halt_op;
# define ZEND_VM_ENTER_BIT 1ULL
#endif
/* VM handlers */
typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *zend_vm_opcode_handler_t)(ZEND_OPCODE_HANDLER_ARGS);
/* VM helpers */
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info);
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_top_func_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t call_info);
@ -339,8 +337,8 @@ typedef enum _zend_jit_trace_stop {
typedef union _zend_op_trace_info {
zend_op dummy; /* the size of this structure must be the same as zend_op */
struct {
const void *orig_handler;
const void *call_handler;
zend_vm_opcode_handler_t orig_handler;
zend_vm_opcode_handler_func_t call_handler;
int16_t *counter;
uint8_t trace_flags;
};

View file

@ -1918,15 +1918,13 @@ static void zend_jit_vm_leave(zend_jit_ctx *jit, ir_ref to_opline)
static int zend_jit_exception_handler_stub(zend_jit_ctx *jit)
{
const void *handler;
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
handler = zend_get_opcode_handler_func(EG(exception_op));
zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(EG(exception_op));
ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
ir_TAILCALL(IR_VOID, ir_LOAD_A(jit_IP(jit)));
} else {
handler = EG(exception_op)->handler;
zend_vm_opcode_handler_t handler = EG(exception_op)->handler;
if (GCC_GLOBAL_REGS) {
ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
@ -4176,17 +4174,12 @@ static ir_ref zend_jit_continue_entry(zend_jit_ctx *jit, ir_ref src, unsigned in
static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_throw)
{
const void *handler;
zend_jit_set_ip(jit, opline);
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
handler = zend_get_opcode_handler_func(opline);
} else {
handler = opline->handler;
}
if (GCC_GLOBAL_REGS) {
zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
} else {
zend_vm_opcode_handler_t handler = opline->handler;
ir_ref ip = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(handler), jit_FP(jit), jit_IP(jit));
jit_STORE_IP(jit, ip);
}
@ -4216,7 +4209,6 @@ static int zend_jit_handler(zend_jit_ctx *jit, const zend_op *opline, int may_th
static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
{
const void *handler;
ir_ref ref;
zend_basic_block *bb;
@ -4228,16 +4220,16 @@ static int zend_jit_tail_handler(zend_jit_ctx *jit, const zend_op *opline)
opline->opcode == ZEND_RETURN) {
/* Use inlined HYBRID VM handler */
handler = opline->handler;
zend_vm_opcode_handler_t handler = opline->handler;
ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
} else {
handler = zend_get_opcode_handler_func(opline);
zend_vm_opcode_handler_func_t handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(opline);
ir_CALL(IR_VOID, ir_CONST_FUNC(handler));
ref = ir_LOAD_A(jit_IP(jit));
ir_TAILCALL(IR_VOID, ref);
}
} else {
handler = opline->handler;
zend_vm_opcode_handler_t handler = opline->handler;
if (GCC_GLOBAL_REGS) {
ir_TAILCALL(IR_VOID, ir_CONST_FUNC(handler));
} else if ((jit->ssa->cfg.flags & ZEND_FUNC_RECURSIVE_DIRECTLY)
@ -16741,7 +16733,7 @@ static int zend_jit_start(zend_jit_ctx *jit, const zend_op_array *op_array, zend
return 1;
}
static void *zend_jit_finish(zend_jit_ctx *jit)
static zend_vm_opcode_handler_t zend_jit_finish(zend_jit_ctx *jit)
{
void *entry;
size_t size;
@ -16825,14 +16817,14 @@ static void *zend_jit_finish(zend_jit_ctx *jit)
opline++;
}
}
opline->handler = entry;
opline->handler = (zend_vm_opcode_handler_t)entry;
if (jit->ctx.entries_count) {
/* For all entries */
int i = jit->ctx.entries_count;
do {
ir_insn *insn = &jit->ctx.ir_base[jit->ctx.entries[--i]];
op_array->opcodes[insn->op2].handler = (char*)entry + insn->op3;
op_array->opcodes[insn->op2].handler = (zend_vm_opcode_handler_t)((char*)entry + insn->op3);
} while (i != 0);
}
} else {
@ -16859,7 +16851,7 @@ static void *zend_jit_finish(zend_jit_ctx *jit)
zend_string_release(str);
}
return entry;
return (zend_vm_opcode_handler_t)entry;
}
static const void *zend_jit_trace_allocate_exit_group(uint32_t n)

View file

@ -3409,7 +3409,7 @@ static void zend_jit_trace_setup_ret_counter(const zend_op *opline, size_t offse
ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;
}
ZEND_OP_TRACE_INFO(next_opline, offset)->trace_flags = ZEND_JIT_TRACE_START_RETURN;
next_opline->handler = (const void*)zend_jit_ret_trace_counter_handler;
next_opline->handler = zend_jit_ret_trace_counter_handler;
}
}
@ -4079,9 +4079,9 @@ static bool zend_jit_trace_may_throw(const zend_op *opline,
return zend_may_throw_ex(opline, ssa_op, op_array, ssa, t1, t2);
}
static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
static zend_vm_opcode_handler_t zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t parent_trace, uint32_t exit_num)
{
const void *handler = NULL;
zend_vm_opcode_handler_t handler = NULL;
zend_jit_ctx ctx;
zend_jit_ctx *jit = &ctx;
zend_jit_reg_var *ra = NULL;
@ -7392,9 +7392,9 @@ static zend_string *zend_jit_trace_escape_name(uint32_t trace_num, uint32_t exit
return buf.s;
}
static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
static zend_vm_opcode_handler_t zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_num)
{
const void *handler = NULL;
zend_vm_opcode_handler_t handler = NULL;
zend_jit_ctx ctx;
zend_string *name;
void *checkpoint;
@ -7458,7 +7458,7 @@ jit_failure:
static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace_buffer, const zend_op *opline, size_t offset)
{
zend_jit_trace_stop ret;
const void *handler;
zend_vm_opcode_handler_t handler;
uint8_t orig_trigger;
zend_jit_trace_info *t = NULL;
zend_jit_trace_exit_info exit_info[ZEND_JIT_TRACE_MAX_EXITS];
@ -8832,11 +8832,11 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf
zend_jit_unprotect();
if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_LOOP) {
((zend_op*)(t->opline))->handler = (const void*)zend_jit_loop_trace_counter_handler;
((zend_op*)(t->opline))->handler = zend_jit_loop_trace_counter_handler;
} else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_ENTER) {
((zend_op*)(t->opline))->handler = (const void*)zend_jit_func_trace_counter_handler;
((zend_op*)(t->opline))->handler = zend_jit_func_trace_counter_handler;
} else if (ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_START_RETURN) {
((zend_op*)(t->opline))->handler = (const void*)zend_jit_ret_trace_counter_handler;
((zend_op*)(t->opline))->handler = zend_jit_ret_trace_counter_handler;
}
ZEND_OP_TRACE_INFO(t->opline, jit_extension->offset)->trace_flags &=
ZEND_JIT_TRACE_START_LOOP|ZEND_JIT_TRACE_START_ENTER|ZEND_JIT_TRACE_START_RETURN;
@ -8889,9 +8889,9 @@ static int zend_jit_restart_hot_trace_counters(zend_op_array *op_array)
jit_extension->trace_info[i].trace_flags &=
ZEND_JIT_TRACE_START_LOOP | ZEND_JIT_TRACE_START_ENTER | ZEND_JIT_TRACE_UNSUPPORTED;
if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_LOOP) {
op_array->opcodes[i].handler = (const void*)zend_jit_loop_trace_counter_handler;
op_array->opcodes[i].handler = zend_jit_loop_trace_counter_handler;
} else if (jit_extension->trace_info[i].trace_flags == ZEND_JIT_TRACE_START_ENTER) {
op_array->opcodes[i].handler = (const void*)zend_jit_func_trace_counter_handler;
op_array->opcodes[i].handler = zend_jit_func_trace_counter_handler;
} else {
op_array->opcodes[i].handler = jit_extension->trace_info[i].orig_handler;
}
@ -8917,7 +8917,7 @@ static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
jit_extension->offset = (char*)jit_extension->trace_info - (char*)op_array->opcodes;
for (i = 0; i < op_array->last; i++) {
jit_extension->trace_info[i].orig_handler = op_array->opcodes[i].handler;
jit_extension->trace_info[i].call_handler = zend_get_opcode_handler_func(&op_array->opcodes[i]);
jit_extension->trace_info[i].call_handler = (zend_vm_opcode_handler_func_t)zend_get_opcode_handler_func(&op_array->opcodes[i]);
jit_extension->trace_info[i].counter = NULL;
jit_extension->trace_info[i].trace_flags =
zend_jit_trace_supported(&op_array->opcodes[i]);
@ -8939,7 +8939,7 @@ static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
/* loop header */
opline = op_array->opcodes + cfg.blocks[i].start;
if (!(ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_UNSUPPORTED)) {
opline->handler = (const void*)zend_jit_loop_trace_counter_handler;
opline->handler = zend_jit_loop_trace_counter_handler;
if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter) {
ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
&zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
@ -8964,7 +8964,7 @@ static int zend_jit_setup_hot_trace_counters(zend_op_array *op_array)
if (!ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags) {
/* function entry */
opline->handler = (const void*)zend_jit_func_trace_counter_handler;
opline->handler = zend_jit_func_trace_counter_handler;
ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->counter =
&zend_jit_hot_counters[ZEND_JIT_COUNTER_NUM];
ZEND_JIT_COUNTER_NUM = (ZEND_JIT_COUNTER_NUM + 1) % ZEND_HOT_COUNTERS_COUNT;

View file

@ -298,6 +298,7 @@ void ZEND_FASTCALL zend_jit_undefined_string_key(EXECUTE_DATA_D)
ZVAL_NULL(result);
}
#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID
ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_profile_helper(ZEND_OPCODE_HANDLER_ARGS)
{
zend_op_array *op_array = (zend_op_array*)EX(func);
@ -341,6 +342,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_counter_helper(ZEND_OPCODE_H
ZEND_OPCODE_TAIL_CALL(handler);
}
}
#endif
static zend_always_inline zend_constant* _zend_quick_get_constant(
const zval *key, uint32_t flags, int check_defined_only)
@ -402,6 +404,7 @@ zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key)
return _zend_quick_get_constant(key, 0, 1);
}
#if ZEND_VM_KIND != ZEND_VM_KIND_HYBRID
static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_trace_counter_helper(ZEND_OPCODE_HANDLER_ARGS_EX uint32_t cost)
{
zend_jit_op_array_trace_extension *jit_extension =
@ -450,6 +453,7 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HAN
ZEND_OPCODE_TAIL_CALL_EX(zend_jit_trace_counter_helper,
((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop)));
}
#endif
#define TRACE_RECORD(_op, _info, _ptr) \
trace_buffer[idx].info = _op | (_info); \
@ -657,7 +661,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
zend_jit_trace_stop halt = 0;
int level = 0;
int ret_level = 0;
zend_vm_opcode_handler_t handler;
zend_vm_opcode_handler_func_t handler;
const zend_op_array *op_array;
zend_jit_op_array_trace_extension *jit_extension;
size_t offset;
@ -983,7 +987,7 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
break;
}
handler = (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
handler = ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
#ifdef HAVE_GCC_GLOBAL_REGS
handler();
if (UNEXPECTED(opline == zend_jit_halt_op)) {