From 0d4ff662e6d83fd3db0134fc826438307431335a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Thu, 4 Sep 2025 12:04:50 +0200 Subject: [PATCH] Expose the source of exit points in zend_jit_dump_exit_info() This adds a new flag: ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC. When the flag is set, zend_jit_dump_exit_info() exposes the source of exit points, in debug builds. Closes GH-19700 --- UPGRADING | 5 +++++ ext/opcache/jit/zend_jit.c | 3 ++- ext/opcache/jit/zend_jit.h | 19 ++++++++++--------- ext/opcache/jit/zend_jit_internal.h | 4 ++++ ext/opcache/jit/zend_jit_trace.c | 24 ++++++++++++++++++++++-- 5 files changed, 43 insertions(+), 12 deletions(-) diff --git a/UPGRADING b/UPGRADING index 2431add112afa..c55d0992602d7 100644 --- a/UPGRADING +++ b/UPGRADING @@ -59,6 +59,11 @@ PHP 8.6 UPGRADE NOTES 11. Changes to INI File Handling ======================================== +- Opcache: + . opcache.jit_debug accepts a new flag: ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC. + When used along with ZEND_JIT_DEBUG_TRACE_EXIT_INFO, the source of exit + points is printed in exit info output, in debug builds. + ======================================== 12. Windows Support ======================================== diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 30f49fb73f676..f6a2f415c760d 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -106,7 +106,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_runtime_jit(Z 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); -static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags); +static uint32_t _zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags ZEND_FILE_LINE_DC); +#define zend_jit_trace_get_exit_point(to_opline, flags) _zend_jit_trace_get_exit_point(to_opline, flags ZEND_FILE_LINE_CC) static const void *zend_jit_trace_get_exit_addr(uint32_t n); static void zend_jit_trace_add_code(const void *start, uint32_t size); static zend_string *zend_jit_func_name(const zend_op_array *op_array); diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h index 5e6b225676aa2..9b8e054d2292f 100644 --- a/ext/opcache/jit/zend_jit.h +++ b/ext/opcache/jit/zend_jit.h @@ -64,15 +64,16 @@ #define ZEND_JIT_DEBUG_SIZE (1<<9) #define ZEND_JIT_DEBUG_ASM_ADDR (1<<10) -#define ZEND_JIT_DEBUG_TRACE_START (1<<12) -#define ZEND_JIT_DEBUG_TRACE_STOP (1<<13) -#define ZEND_JIT_DEBUG_TRACE_COMPILED (1<<14) -#define ZEND_JIT_DEBUG_TRACE_EXIT (1<<15) -#define ZEND_JIT_DEBUG_TRACE_ABORT (1<<16) -#define ZEND_JIT_DEBUG_TRACE_BLACKLIST (1<<17) -#define ZEND_JIT_DEBUG_TRACE_BYTECODE (1<<18) -#define ZEND_JIT_DEBUG_TRACE_TSSA (1<<19) -#define ZEND_JIT_DEBUG_TRACE_EXIT_INFO (1<<20) +#define ZEND_JIT_DEBUG_TRACE_START (1<<12) +#define ZEND_JIT_DEBUG_TRACE_STOP (1<<13) +#define ZEND_JIT_DEBUG_TRACE_COMPILED (1<<14) +#define ZEND_JIT_DEBUG_TRACE_EXIT (1<<15) +#define ZEND_JIT_DEBUG_TRACE_ABORT (1<<16) +#define ZEND_JIT_DEBUG_TRACE_BLACKLIST (1<<17) +#define ZEND_JIT_DEBUG_TRACE_BYTECODE (1<<18) +#define ZEND_JIT_DEBUG_TRACE_TSSA (1<<19) +#define ZEND_JIT_DEBUG_TRACE_EXIT_INFO (1<<20) +#define ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC (1<<21) #define ZEND_JIT_DEBUG_IR_SRC (1<<24) #define ZEND_JIT_DEBUG_IR_FINAL (1<<25) diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 57c0dedb2fa2d..1bffc969902a2 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -456,6 +456,10 @@ typedef struct _zend_jit_trace_exit_info { uint32_t stack_offset; zend_jit_ref_snapshot poly_func; zend_jit_ref_snapshot poly_this; +#if ZEND_DEBUG + const char *filename; + int lineno; +#endif } zend_jit_trace_exit_info; typedef struct _zend_jit_trace_stack { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 66bb380c23d8d..21698f71500c7 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -132,7 +132,7 @@ static uint32_t zend_jit_exit_point_by_addr(const void *addr) return (uint32_t)-1; } -static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags) +static uint32_t _zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t flags ZEND_FILE_LINE_DC) { zend_jit_trace_info *t = &zend_jit_traces[ZEND_JIT_TRACE_NUM]; uint32_t exit_point; @@ -178,7 +178,13 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t && memcmp(t->stack_map + t->exit_info[i].stack_offset, stack, stack_size * sizeof(zend_jit_trace_stack)) == 0)) { if (t->exit_info[i].opline == to_opline && t->exit_info[i].flags == flags - && t->exit_info[i].stack_size == stack_size) { + && t->exit_info[i].stack_size == stack_size +#if ZEND_DEBUG + && (((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) == 0) + || (strcmp(t->exit_info[i].filename, __zend_filename) == 0 + && t->exit_info[i].lineno == __zend_lineno)) +#endif + ) { return i; } } @@ -202,6 +208,15 @@ static uint32_t zend_jit_trace_get_exit_point(const zend_op *to_opline, uint32_t t->exit_info[exit_point].stack_offset = stack_offset; t->exit_info[exit_point].poly_func = (zend_jit_ref_snapshot){.reg = ZREG_NONE}; t->exit_info[exit_point].poly_this = (zend_jit_ref_snapshot){.reg = ZREG_NONE}; +#if ZEND_DEBUG + if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) != 0) { + t->exit_info[exit_point].filename = __zend_filename; + t->exit_info[exit_point].lineno = __zend_lineno; + } else { + t->exit_info[exit_point].filename = NULL; + t->exit_info[exit_point].lineno = 0; + } +#endif } return exit_point; @@ -8096,6 +8111,11 @@ static void zend_jit_dump_exit_info(zend_jit_trace_info *t) fprintf(stderr, ":unknown(zval_copy(%s))", zend_reg_name(STACK_REG(stack, j))); } } +#if ZEND_DEBUG + if ((JIT_G(debug) & ZEND_JIT_DEBUG_TRACE_EXIT_INFO_SRC) != 0) { + fprintf(stderr, " %s:%d", t->exit_info[i].filename, t->exit_info[i].lineno); + } +#endif fprintf(stderr, "\n"); } }