@@ -16762,38 +16762,37 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
16762
16762
return 1;
16763
16763
}
16764
16764
16765
- struct jit_frameless_observer_data {
16766
- ir_ref if_unobserved;
16767
- ir_ref reused_jit_ip;
16768
- };
16769
-
16770
- 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) {
16771
- struct jit_frameless_observer_data data;
16765
+ 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, zend_jit_addr res_addr) {
16772
16766
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
16773
16767
ir_ref observer_handler;
16774
16768
zend_function *fbc = ZEND_FLF_FUNC(opline);
16775
16769
// Not need for runtime cache or generator checks here, we just need if_unobserved
16776
- data. if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
16770
+ ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
16777
16771
16778
- // push args to a valid call frame, without copying
16772
+ // push args to a valid call frame, without copying (flf call takes care of freeing args)
16779
16773
bool track_last_valid_opline = jit->track_last_valid_opline;
16774
+ bool use_last_valid_opline = jit->use_last_valid_opline;
16780
16775
const zend_op *last_valid_opline = jit->last_valid_opline;
16781
16776
bool reuse_ip = jit->reuse_ip;
16782
16777
if (reuse_ip) {
16783
- data.reused_jit_ip = jit_IP(jit);
16778
+ ir_ref call = jit_CALL(jit_FP(jit), call);
16779
+ ir_STORE(jit_CALL(jit_IP(jit), prev_execute_data), call);
16780
+ ir_STORE(call, jit_IP(jit));
16784
16781
}
16785
16782
zend_jit_push_call_frame(jit, opline, NULL, fbc, 0, 0, checked_stack, ir_CONST_ADDR(fbc), IR_NULL);
16786
- // 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
16783
+ // 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
16784
+ // the primary issue here is that this code is just executed conditionally while the reuse mechanisms are meant to be global
16787
16785
jit->track_last_valid_opline = track_last_valid_opline;
16786
+ jit->use_last_valid_opline = use_last_valid_opline;
16788
16787
jit->last_valid_opline = last_valid_opline;
16789
16788
jit->reuse_ip = reuse_ip;
16790
16789
16791
16790
// push all args
16792
16791
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
16793
16792
switch (call_num_args) {
16794
- 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;
16795
- 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;
16796
- 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);
16793
+ 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, 0); ZEND_FALLTHROUGH;
16794
+ 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, 0); ZEND_FALLTHROUGH;
16795
+ 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, 0);
16797
16796
}
16798
16797
16799
16798
// Make call frame externally visible
@@ -16803,11 +16802,10 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
16803
16802
16804
16803
jit_observer_fcall_begin(jit, rx, observer_handler);
16805
16804
16806
- return data;
16807
- }
16805
+ // JIT: fbc->internal_function.handler(new_frame, return_value)
16806
+ ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
16807
+ ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)fbc->internal_function.handler), rx, res_ref);
16808
16808
16809
- 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) {
16810
- ir_ref rx = jit_IP(jit);
16811
16809
jit_observer_fcall_end(jit, rx, res_addr);
16812
16810
16813
16811
ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
@@ -16837,14 +16835,16 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
16837
16835
ir_MERGE_WITH(allocated_path);
16838
16836
}
16839
16837
16840
- if (jit->reuse_ip) {
16841
- jit_STORE_IP(jit, data->reused_jit_ip);
16838
+ if (reuse_ip) {
16839
+ jit_STORE_IP(jit, ir_LOAD_A(jit_CALL(jit_FP(jit), call)));
16840
+ ir_STORE(jit_CALL(jit_FP(jit), call), jit_CALL(jit_IP(jit), prev_execute_data));
16842
16841
} else {
16843
- jit_SET_EX_OPLINE(jit, opline);
16842
+ // Note: conditional (if_unobserved) opline, zend_jit_set_last_valid_opline() may only be called if the opline is actually unconditionally updated
16843
+ jit_STORE_IP(jit, ir_CONST_ADDR(jit->last_valid_opline ? jit->last_valid_opline : opline));
16844
16844
}
16845
16845
16846
16846
ir_ref skip = ir_END();
16847
- ir_IF_TRUE(data-> if_unobserved);
16847
+ ir_IF_TRUE(if_unobserved);
16848
16848
return skip;
16849
16849
}
16850
16850
@@ -16859,9 +16859,7 @@ static void jit_frameless_icall0(zend_jit_ctx *jit, int checked_stack, const zen
16859
16859
16860
16860
ir_ref skip_observer = IR_UNUSED;
16861
16861
if (ZEND_OBSERVER_ENABLED) {
16862
- struct jit_frameless_observer_data observer_data = jit_frameless_observer_begin(jit, checked_stack, opline, IR_UNUSED, 0, IR_UNUSED, 0, IR_UNUSED, 0);
16863
- ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
16864
- skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
16862
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, IR_UNUSED, 0, IR_UNUSED, 0, IR_UNUSED, 0, res_addr);
16865
16863
}
16866
16864
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
16867
16865
if (skip_observer != IR_UNUSED) {
@@ -16895,9 +16893,7 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, int checked_stack, const zen
16895
16893
16896
16894
ir_ref skip_observer = IR_UNUSED;
16897
16895
if (ZEND_OBSERVER_ENABLED) {
16898
- 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);
16899
- ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
16900
- skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
16896
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, IR_UNUSED, 0, IR_UNUSED, 0, res_addr);
16901
16897
}
16902
16898
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
16903
16899
if (skip_observer != IR_UNUSED) {
@@ -16944,9 +16940,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, int checked_stack, const zen
16944
16940
16945
16941
ir_ref skip_observer = IR_UNUSED;
16946
16942
if (ZEND_OBSERVER_ENABLED) {
16947
- 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);
16948
- ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
16949
- skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
16943
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, IR_UNUSED, 0, res_addr);
16950
16944
}
16951
16945
ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
16952
16946
if (skip_observer != IR_UNUSED) {
@@ -17011,9 +17005,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, int checked_stack, const zen
17011
17005
17012
17006
ir_ref skip_observer = IR_UNUSED;
17013
17007
if (ZEND_OBSERVER_ENABLED) {
17014
- 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);
17015
- ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17016
- skip_observer = jit_frameless_observer_end(jit, &observer_data, opline, res_addr);
17008
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, op3_ref, op1_data_info, res_addr);
17017
17009
}
17018
17010
ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17019
17011
if (skip_observer != IR_UNUSED) {
0 commit comments