Skip to content

Commit 8fc959e

Browse files
committed
Simplify frameless jit handler and fix wordpress issue
1 parent dab832d commit 8fc959e

File tree

1 file changed

+49
-44
lines changed

1 file changed

+49
-44
lines changed

ext/opcache/jit/zend_jit_ir.c

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4538,11 +4538,11 @@ static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observ
45384538
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
45394539
}
45404540

4541-
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, zend_jit_addr res_addr) {
4541+
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
45424542
ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
45434543
ir_IF_TRUE(has_end_observer);
45444544
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4545-
rx, jit_ZVAL_ADDR(jit, res_addr));
4545+
rx, res_ref);
45464546
ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
45474547
}
45484548

@@ -10155,8 +10155,9 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1015510155
zend_jit_reset_last_valid_opline(jit);
1015610156

1015710157
// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10158+
ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
1015810159
if (zend_execute_internal) {
10159-
ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, jit_ZVAL_ADDR(jit, res_addr));
10160+
ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
1016010161
} else {
1016110162
if (func) {
1016210163
func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
@@ -10166,11 +10167,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1016610167
func_ptr = ir_CAST_FC_FUNC(func_ptr);
1016710168
#endif
1016810169
}
10169-
ir_CALL_2(IR_VOID, func_ptr, rx, jit_ZVAL_ADDR(jit, res_addr));
10170+
ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
1017010171
}
1017110172

1017210173
if (may_have_observer) {
10173-
jit_observer_fcall_end(jit, rx, res_addr);
10174+
jit_observer_fcall_end(jit, rx, res_ref);
1017410175
}
1017510176

1017610177
// JIT: EG(current_execute_data) = execute_data;
@@ -10882,9 +10883,7 @@ static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_
1088210883
}
1088310884
op1_addr = dst;
1088410885
}
10885-
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end),
10886-
jit_FP(jit),
10887-
jit_ZVAL_ADDR(jit, op1_addr));
10886+
jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
1088810887
}
1088910888

1089010889
// JIT: if (!EX(return_value))
@@ -17035,38 +17034,38 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
1703517034
return 1;
1703617035
}
1703717036

17038-
struct jit_frameless_observer_data {
17039-
ir_ref if_unobserved;
17040-
ir_ref reused_jit_ip;
17041-
};
17042-
17043-
static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_ctx *jit, int checked_stack, const zend_op *opline, ir_ref op1_ref, uint32_t op1_info, ir_ref op2_ref, uint32_t op2_info, ir_ref op1_data_ref, uint32_t op1_data_info) {
17044-
struct jit_frameless_observer_data data;
17037+
static ir_ref jit_frameless_observer(zend_jit_ctx *jit, int checked_stack, const zend_op *opline, ir_ref op1_ref, uint32_t op1_info, ir_ref op2_ref, uint32_t op2_info, ir_ref op1_data_ref, uint32_t op1_data_info, ir_ref res_ref) {
1704517038
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
1704617039
ir_ref observer_handler;
1704717040
zend_function *fbc = ZEND_FLF_FUNC(opline);
1704817041
// Not need for runtime cache or generator checks here, we just need if_unobserved
17049-
data.if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
17042+
ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
1705017043

17051-
// push args to a valid call frame, without copying
17044+
// push args to a valid call frame
1705217045
bool track_last_valid_opline = jit->track_last_valid_opline;
17046+
bool use_last_valid_opline = jit->use_last_valid_opline;
1705317047
const zend_op *last_valid_opline = jit->last_valid_opline;
1705417048
bool reuse_ip = jit->reuse_ip;
17055-
if (reuse_ip) {
17056-
data.reused_jit_ip = jit_IP(jit);
17049+
// zend_jit_save_call_chain, but preserve delayed_call_level. We cannot override delayed_call_level without also saving in unobserved path.
17050+
if (jit->delayed_call_level) {
17051+
ir_ref call = jit_CALL(jit_FP(jit), call);
17052+
ir_STORE(jit_CALL(jit_IP(jit), prev_execute_data), jit->delayed_call_level == 1 ? IR_NULL : ir_LOAD_A(call));
17053+
ir_STORE(call, jit_IP(jit));
1705717054
}
1705817055
zend_jit_push_call_frame(jit, opline, NULL, fbc, 0, 0, checked_stack, ir_CONST_ADDR(fbc), IR_NULL);
17059-
// yes, we'll temporarily reuse the IP, but we don't want to handle this via the reuse_ip mechanism for simiplicity - we just reset IP to original in end
17056+
// yes, we'll temporarily reuse the IP, but we must not handle this via the reuse_ip mechanism - we just reset IP to original in end
17057+
// the primary issue here is that this code is just executed conditionally while the reuse mechanisms are meant to be global
1706017058
jit->track_last_valid_opline = track_last_valid_opline;
17059+
jit->use_last_valid_opline = use_last_valid_opline;
1706117060
jit->last_valid_opline = last_valid_opline;
1706217061
jit->reuse_ip = reuse_ip;
1706317062

1706417063
// push all args
1706517064
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
1706617065
switch (call_num_args) {
17067-
case 3: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(3)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_data_ref), op1_data_info, 0); ZEND_FALLTHROUGH;
17068-
case 2: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(2)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op2_ref), op2_info, 0); ZEND_FALLTHROUGH;
17069-
case 1: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(1)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_ref), op1_info, 0);
17066+
case 3: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(2)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_data_ref), op1_data_info, 1); ZEND_FALLTHROUGH;
17067+
case 2: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(1)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op2_ref), op2_info, 1); ZEND_FALLTHROUGH;
17068+
case 1: jit_ZVAL_COPY(jit, ZEND_ADDR_MEM_ZVAL(ZREG_RX, EX_NUM_TO_VAR(0)), MAY_BE_ANY & ~MAY_BE_REF, ZEND_ADDR_REF_ZVAL(op1_ref), op1_info, 1);
1707017069
}
1707117070

1707217071
// Make call frame externally visible
@@ -17076,15 +17075,22 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
1707617075

1707717076
jit_observer_fcall_begin(jit, rx, observer_handler);
1707817077

17079-
return data;
17080-
}
17078+
// JIT: fbc->internal_function.handler(new_frame, return_value)
17079+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(fbc->internal_function.handler), rx, res_ref);
1708117080

17082-
static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless_observer_data *data, const zend_op *opline, zend_jit_addr res_addr) {
17083-
ir_ref rx = jit_IP(jit);
17084-
jit_observer_fcall_end(jit, rx, res_addr);
17081+
jit_observer_fcall_end(jit, rx, res_ref);
1708517082

1708617083
ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
1708717084

17085+
for (int i = 0; i < call_num_args; ++i) {
17086+
if (zend_jit_needs_arg_dtor(fbc, i, NULL)) {
17087+
uint32_t offset = EX_NUM_TO_VAR(i);
17088+
zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset);
17089+
17090+
jit_ZVAL_PTR_DTOR(jit, var_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 0, opline);
17091+
}
17092+
}
17093+
1708817094
ir_ref allocated_path = IR_UNUSED;
1708917095

1709017096
// free the call frame
@@ -17110,14 +17116,18 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
1711017116
ir_MERGE_WITH(allocated_path);
1711117117
}
1711217118

17113-
if (jit->reuse_ip) {
17114-
jit_STORE_IP(jit, data->reused_jit_ip);
17119+
if (reuse_ip) {
17120+
jit_STORE_IP(jit, ir_LOAD_A(jit_CALL(jit_FP(jit), call)));
17121+
if (jit->delayed_call_level) { // restore if saved
17122+
ir_STORE(jit_CALL(jit_FP(jit), call), ir_LOAD_A(jit_CALL(jit_IP(jit), prev_execute_data)));
17123+
}
1711517124
} else {
17116-
jit_SET_EX_OPLINE(jit, opline);
17125+
// Note: conditional (if_unobserved) opline, zend_jit_set_last_valid_opline() may only be called if the opline is actually unconditionally updated
17126+
jit_STORE_IP(jit, ir_CONST_ADDR(jit->last_valid_opline ? jit->last_valid_opline : opline));
1711717127
}
1711817128

1711917129
ir_ref skip = ir_END();
17120-
ir_IF_TRUE(data->if_unobserved);
17130+
ir_IF_TRUE(if_unobserved);
1712117131
return skip;
1712217132
}
1712317133

@@ -17132,9 +17142,7 @@ static void jit_frameless_icall0(zend_jit_ctx *jit, int checked_stack, const zen
1713217142

1713317143
ir_ref skip_observer = IR_UNUSED;
1713417144
if (ZEND_OBSERVER_ENABLED) {
17135-
struct jit_frameless_observer_data observer_data = jit_frameless_observer_begin(jit, checked_stack, opline, IR_UNUSED, 0, IR_UNUSED, 0, IR_UNUSED, 0);
17136-
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
17137-
skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
17145+
skip_observer = jit_frameless_observer(jit, checked_stack, opline, IR_UNUSED, 0, IR_UNUSED, 0, IR_UNUSED, 0, res_ref);
1713817146
}
1713917147
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
1714017148
if (skip_observer != IR_UNUSED) {
@@ -17168,16 +17176,15 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, int checked_stack, const zen
1716817176

1716917177
ir_ref skip_observer = IR_UNUSED;
1717017178
if (ZEND_OBSERVER_ENABLED) {
17171-
struct jit_frameless_observer_data observer_data = jit_frameless_observer_begin(jit, checked_stack, opline, op1_ref, op1_info, IR_UNUSED, 0, IR_UNUSED, 0);
17172-
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
17173-
skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
17179+
skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, IR_UNUSED, 0, IR_UNUSED, 0, res_ref);
1717417180
}
1717517181
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
1717617182
if (skip_observer != IR_UNUSED) {
1717717183
ir_MERGE_WITH(skip_observer);
1717817184
}
1717917185

1718017186
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
17187+
1718117188
zend_jit_check_exception(jit);
1718217189
}
1718317190

@@ -17217,9 +17224,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, int checked_stack, const zen
1721717224

1721817225
ir_ref skip_observer = IR_UNUSED;
1721917226
if (ZEND_OBSERVER_ENABLED) {
17220-
struct jit_frameless_observer_data observer_data = jit_frameless_observer_begin(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, IR_UNUSED, 0);
17221-
ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
17222-
skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
17227+
skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, IR_UNUSED, 0, res_ref);
1722317228
}
1722417229
ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
1722517230
if (skip_observer != IR_UNUSED) {
@@ -17233,6 +17238,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, int checked_stack, const zen
1723317238
jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF);
1723417239
}
1723517240
jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, NULL);
17241+
1723617242
zend_jit_check_exception(jit);
1723717243
}
1723817244

@@ -17284,9 +17290,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, int checked_stack, const zen
1728417290

1728517291
ir_ref skip_observer = IR_UNUSED;
1728617292
if (ZEND_OBSERVER_ENABLED) {
17287-
struct jit_frameless_observer_data observer_data = jit_frameless_observer_begin(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, op3_ref, op1_data_info);
17288-
ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17289-
skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
17293+
skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, op3_ref, op1_data_info, res_ref);
1729017294
}
1729117295
ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
1729217296
if (skip_observer != IR_UNUSED) {
@@ -17309,6 +17313,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, int checked_stack, const zen
1730917313
jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF);
1731017314
}
1731117315
jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, op1_data_info, NULL);
17316+
1731217317
zend_jit_check_exception(jit);
1731317318
}
1731417319

0 commit comments

Comments
 (0)