@@ -4534,11 +4534,11 @@ static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observ
4534
4534
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
4535
4535
}
4536
4536
4537
- static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, zend_jit_addr res_addr ) {
4537
+ static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref ) {
4538
4538
ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
4539
4539
ir_IF_TRUE(has_end_observer);
4540
4540
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
4541
- rx, jit_ZVAL_ADDR(jit, res_addr) );
4541
+ rx, res_ref );
4542
4542
ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
4543
4543
}
4544
4544
@@ -10117,8 +10117,9 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10117
10117
zend_jit_reset_last_valid_opline(jit);
10118
10118
10119
10119
// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
10120
+ ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
10120
10121
if (zend_execute_internal) {
10121
- ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, jit_ZVAL_ADDR(jit, res_addr) );
10122
+ ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref );
10122
10123
} else {
10123
10124
if (func) {
10124
10125
func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
@@ -10128,11 +10129,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10128
10129
func_ptr = ir_CAST_FC_FUNC(func_ptr);
10129
10130
#endif
10130
10131
}
10131
- ir_CALL_2(IR_VOID, func_ptr, rx, jit_ZVAL_ADDR(jit, res_addr) );
10132
+ ir_CALL_2(IR_VOID, func_ptr, rx, res_ref );
10132
10133
}
10133
10134
10134
10135
if (may_have_observer) {
10135
- jit_observer_fcall_end(jit, rx, res_addr );
10136
+ jit_observer_fcall_end(jit, rx, res_ref );
10136
10137
}
10137
10138
10138
10139
// JIT: EG(current_execute_data) = execute_data;
@@ -10844,9 +10845,7 @@ static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_
10844
10845
}
10845
10846
op1_addr = dst;
10846
10847
}
10847
- ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end),
10848
- jit_FP(jit),
10849
- jit_ZVAL_ADDR(jit, op1_addr));
10848
+ jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
10850
10849
}
10851
10850
10852
10851
// JIT: if (!EX(return_value))
@@ -16762,38 +16761,37 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
16762
16761
return 1;
16763
16762
}
16764
16763
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;
16764
+ 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) {
16772
16765
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
16773
16766
ir_ref observer_handler;
16774
16767
zend_function *fbc = ZEND_FLF_FUNC(opline);
16775
16768
// 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;
16769
+ ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
16777
16770
16778
- // push args to a valid call frame, without copying
16771
+ // push args to a valid call frame, without copying (flf call takes care of freeing args)
16779
16772
bool track_last_valid_opline = jit->track_last_valid_opline;
16773
+ bool use_last_valid_opline = jit->use_last_valid_opline;
16780
16774
const zend_op *last_valid_opline = jit->last_valid_opline;
16781
16775
bool reuse_ip = jit->reuse_ip;
16782
16776
if (reuse_ip) {
16783
- data.reused_jit_ip = jit_IP(jit);
16777
+ ir_ref call = jit_CALL(jit_FP(jit), call);
16778
+ ir_STORE(jit_CALL(jit_IP(jit), prev_execute_data), ir_LOAD_A(call));
16779
+ ir_STORE(call, jit_IP(jit));
16784
16780
}
16785
16781
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
16782
+ // 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
16783
+ // the primary issue here is that this code is just executed conditionally while the reuse mechanisms are meant to be global
16787
16784
jit->track_last_valid_opline = track_last_valid_opline;
16785
+ jit->use_last_valid_opline = use_last_valid_opline;
16788
16786
jit->last_valid_opline = last_valid_opline;
16789
16787
jit->reuse_ip = reuse_ip;
16790
16788
16791
16789
// push all args
16792
16790
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
16793
16791
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);
16792
+ 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;
16793
+ 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;
16794
+ 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
16795
}
16798
16796
16799
16797
// Make call frame externally visible
@@ -16803,12 +16801,10 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
16803
16801
16804
16802
jit_observer_fcall_begin(jit, rx, observer_handler);
16805
16803
16806
- return data;
16807
- }
16804
+ // JIT: fbc->internal_function.handler(new_frame, return_value)
16805
+ ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(fbc->internal_function.handler), rx, res_ref);
16808
16806
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
- jit_observer_fcall_end(jit, rx, res_addr);
16807
+ jit_observer_fcall_end(jit, rx, res_ref);
16812
16808
16813
16809
ir_STORE(jit_EG(current_execute_data), ir_LOAD_A(jit_CALL(rx, prev_execute_data)));
16814
16810
@@ -16837,14 +16833,16 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
16837
16833
ir_MERGE_WITH(allocated_path);
16838
16834
}
16839
16835
16840
- if (jit->reuse_ip) {
16841
- jit_STORE_IP(jit, data->reused_jit_ip);
16836
+ if (reuse_ip) {
16837
+ jit_STORE_IP(jit, ir_LOAD_A(jit_CALL(jit_FP(jit), call)));
16838
+ ir_STORE(jit_CALL(jit_FP(jit), call), ir_LOAD_A(jit_CALL(jit_IP(jit), prev_execute_data)));
16842
16839
} else {
16843
- jit_SET_EX_OPLINE(jit, opline);
16840
+ // Note: conditional (if_unobserved) opline, zend_jit_set_last_valid_opline() may only be called if the opline is actually unconditionally updated
16841
+ jit_STORE_IP(jit, ir_CONST_ADDR(jit->last_valid_opline ? jit->last_valid_opline : opline));
16844
16842
}
16845
16843
16846
16844
ir_ref skip = ir_END();
16847
- ir_IF_TRUE(data-> if_unobserved);
16845
+ ir_IF_TRUE(if_unobserved);
16848
16846
return skip;
16849
16847
}
16850
16848
@@ -16859,9 +16857,7 @@ static void jit_frameless_icall0(zend_jit_ctx *jit, int checked_stack, const zen
16859
16857
16860
16858
ir_ref skip_observer = IR_UNUSED;
16861
16859
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);
16860
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, IR_UNUSED, 0, IR_UNUSED, 0, IR_UNUSED, 0, res_ref);
16865
16861
}
16866
16862
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
16867
16863
if (skip_observer != IR_UNUSED) {
@@ -16895,9 +16891,7 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, int checked_stack, const zen
16895
16891
16896
16892
ir_ref skip_observer = IR_UNUSED;
16897
16893
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);
16894
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, IR_UNUSED, 0, IR_UNUSED, 0, res_ref);
16901
16895
}
16902
16896
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
16903
16897
if (skip_observer != IR_UNUSED) {
@@ -16944,9 +16938,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, int checked_stack, const zen
16944
16938
16945
16939
ir_ref skip_observer = IR_UNUSED;
16946
16940
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);
16941
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, IR_UNUSED, 0, res_ref);
16950
16942
}
16951
16943
ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
16952
16944
if (skip_observer != IR_UNUSED) {
@@ -17011,9 +17003,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, int checked_stack, const zen
17011
17003
17012
17004
ir_ref skip_observer = IR_UNUSED;
17013
17005
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);
17006
+ skip_observer = jit_frameless_observer(jit, checked_stack, opline, op1_ref, op1_info, op2_ref, op2_info, op3_ref, op1_data_info, res_ref);
17017
17007
}
17018
17008
ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
17019
17009
if (skip_observer != IR_UNUSED) {
0 commit comments