Skip to content

Commit 097edc8

Browse files
authoredOct 15, 2024
Allow JIT for passing arguments to trampolines and "bad" functions (#16365)
* Better trace coverage (JIT trampoline calls) * clenup trampoline by zend_jit_free_trampoline() * Fix ZEND_JIT_TRACE_INIT_CALL/ZEND_JIT_TRACE_DO_ICALL num_args mismatch It may be caused by SEND_UNPACK/SEND_ARRAY * cleanup * cleanup * Don't record function that may be temporary * cleanup * Prevent invalid run_time_cache allocation for "bad" internal functions * Update zend_jit_trace_record_fake_init_call_ex() accordingly * Better handling of "bad" functions and fake closures
1 parent 2d9eb54 commit 097edc8

File tree

5 files changed

+140
-88
lines changed

5 files changed

+140
-88
lines changed
 

Diff for: ‎ext/opcache/jit/zend_jit_helpers.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static zend_never_inline zend_op_array* ZEND_FASTCALL zend_jit_init_func_run_tim
4242
{
4343
void **run_time_cache;
4444

45-
if (!RUN_TIME_CACHE(op_array)) {
45+
if (op_array->type == ZEND_USER_FUNCTION && !RUN_TIME_CACHE(op_array)) {
4646
run_time_cache = zend_arena_alloc(&CG(arena), op_array->cache_size);
4747
memset(run_time_cache, 0, op_array->cache_size);
4848
ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);

Diff for: ‎ext/opcache/jit/zend_jit_internal.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,11 @@ zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key);
248248
_(RECURSIVE_CALL, "recursive call") \
249249
_(RECURSIVE_RET, "recursive return") \
250250
_(RETURN, "return") \
251-
_(INTERPRETER, "exit to VM interpreter") \
252251
_(LINK, "link to another trace") \
252+
_(INTERPRETER, "exit to VM interpreter") \
253+
_(TRAMPOLINE, "trampoline call") \
254+
_(PROP_HOOK_CALL, "property hook call") \
255+
_(BAD_FUNC, "bad function call") \
253256
/* compilation and linking successful */ \
254257
_(COMPILED, "compiled") \
255258
_(ALREADY_DONE, "already prcessed") \
@@ -267,9 +270,6 @@ zend_constant* ZEND_FASTCALL zend_jit_check_constant(const zval *key);
267270
_(BLACK_LIST, "trace blacklisted") \
268271
_(INNER_LOOP, "inner loop") /* trace it */ \
269272
_(COMPILED_LOOP, "compiled loop") \
270-
_(TRAMPOLINE, "trampoline call") \
271-
_(PROP_HOOK_CALL, "property hook call") \
272-
_(BAD_FUNC, "bad function call") \
273273
_(COMPILER_ERROR, "JIT compilation error") \
274274
/* no recoverable error (blacklist immediately) */ \
275275
_(NO_SHM, "insufficient shared memory") \
@@ -380,6 +380,12 @@ typedef enum _zend_jit_trace_op {
380380
#define ZEND_JIT_TRACE_FAKE_INFO(level) \
381381
(((level) << ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT) | ZEND_JIT_TRACE_FAKE_INIT_CALL)
382382

383+
#define ZEND_JIT_TRACE_NUM_ARGS_INFO(count) \
384+
((count) << ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT)
385+
386+
#define ZEND_JIT_TRACE_NUM_ARGS(info) \
387+
(((info) & ZEND_JIT_TRACE_FAKE_LEVEL_MASK) >> ZEND_JIT_TRACE_FAKE_LEVEL_SHIFT)
388+
383389
#define ZEND_JIT_TRACE_SET_FIRST_SSA_VAR(_info, var) do { \
384390
_info |= (var << ZEND_JIT_TRACE_SSA_VAR_SHIFT); \
385391
} while (0)

Diff for: ‎ext/opcache/jit/zend_jit_ir.c

+25-9
Original file line numberDiff line numberDiff line change
@@ -8431,13 +8431,21 @@ static int zend_jit_push_call_frame(zend_jit_ctx *jit, const zend_op *opline, co
84318431
used_stack_ref);
84328432

84338433
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) {
8434-
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
8434+
bool may_be_trampoline = !func && (opline->opcode == ZEND_INIT_METHOD_CALL);
8435+
int32_t exit_point = zend_jit_trace_get_exit_point(opline,
8436+
may_be_trampoline ?
8437+
(ZEND_JIT_EXIT_TO_VM | ZEND_JIT_EXIT_METHOD_CALL) : ZEND_JIT_EXIT_TO_VM);
84358438
const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point);
84368439

84378440
if (!exit_addr) {
84388441
return 0;
84398442
}
84408443

8444+
if (may_be_trampoline) {
8445+
jit->trace->exit_info[exit_point].poly_func_ref = func_ref;
8446+
jit->trace->exit_info[exit_point].poly_this_ref = this_ref;
8447+
}
8448+
84418449
ir_GUARD(ref, ir_CONST_ADDR(exit_addr));
84428450
} else {
84438451
if_enough_stack = ir_IF(ref);
@@ -9064,6 +9072,14 @@ static int zend_jit_init_method_call(zend_jit_ctx *jit,
90649072
jit->delayed_call_level = call_level;
90659073
}
90669074

9075+
if (trace
9076+
&& trace->op == ZEND_JIT_TRACE_END
9077+
&& trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
9078+
if (!zend_jit_set_ip(jit, opline + 1)) {
9079+
return 0;
9080+
}
9081+
}
9082+
90679083
return 1;
90689084
}
90699085

@@ -9324,7 +9340,7 @@ static int zend_jit_init_closure_call(zend_jit_ctx *jit,
93249340

93259341
if (trace
93269342
&& trace->op == ZEND_JIT_TRACE_END
9327-
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
9343+
&& trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
93289344
if (!zend_jit_set_ip(jit, opline + 1)) {
93299345
return 0;
93309346
}
@@ -9933,7 +9949,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
99339949

99349950
if (trace && !func) {
99359951
if (trace->op == ZEND_JIT_TRACE_DO_ICALL) {
9936-
ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION);
9952+
ZEND_ASSERT(!trace->func || trace->func->type == ZEND_INTERNAL_FUNCTION);
99379953
#ifndef ZEND_WIN32
99389954
// TODO: ASLR may cause different addresses in different workers ???
99399955
func = trace->func;
@@ -10115,7 +10131,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1011510131

1011610132
if (call_num_args <= func->op_array.num_args) {
1011710133
if (!trace || (trace->op == ZEND_JIT_TRACE_END
10118-
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10134+
&& trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1011910135
uint32_t num_args;
1012010136

1012110137
if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) {
@@ -10149,7 +10165,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1014910165
}
1015010166
} else {
1015110167
if (!trace || (trace->op == ZEND_JIT_TRACE_END
10152-
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10168+
&& trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1015310169
ir_ref ip;
1015410170

1015510171
if (zend_accel_in_shm(func->op_array.opcodes)) {
@@ -10275,7 +10291,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1027510291
ir_ref observer_handler;
1027610292
ir_ref rx = jit_FP(jit);
1027710293
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
10278-
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
10294+
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1027910295
ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
1028010296
jit_SET_EX_OPLINE(jit, trace[1].opline);
1028110297
} else if (GCC_GLOBAL_REGS) {
@@ -10568,7 +10584,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1056810584
jit_LOAD_IP_ADDR(jit, opline + 1);
1056910585
} else if (trace
1057010586
&& trace->op == ZEND_JIT_TRACE_END
10571-
&& trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) {
10587+
&& trace->stop >= ZEND_JIT_TRACE_STOP_INTERPRETER) {
1057210588
jit_LOAD_IP_ADDR(jit, opline + 1);
1057310589
}
1057410590
}
@@ -16908,7 +16924,7 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr
1690816924
if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) {
1690916925
if (trace->op != ZEND_JIT_TRACE_END ||
1691016926
(trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16911-
trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16927+
trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1691216928
/* this check may be handled by the following OPLINE guard or jmp [IP] */
1691316929
ir_GUARD(ir_NE(jit_IP(jit), ir_CONST_ADDR(zend_jit_halt_op)),
1691416930
jit_STUB_ADDR(jit, jit_stub_trace_halt));
@@ -16926,7 +16942,7 @@ static int zend_jit_trace_handler(zend_jit_ctx *jit, const zend_op_array *op_arr
1692616942
}
1692716943
if (trace->op != ZEND_JIT_TRACE_END ||
1692816944
(trace->stop != ZEND_JIT_TRACE_STOP_RETURN &&
16929-
trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
16945+
trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1693016946

1693116947
const zend_op *next_opline = trace->opline;
1693216948
const zend_op *exit_opline = NULL;

0 commit comments

Comments
 (0)