@@ -4477,51 +4477,64 @@ static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr s
4477
4477
return 1;
4478
4478
}
4479
4479
4480
- static ir_ref jit_observer_fcall_is_unobserved(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4481
- ir_ref run_time_cache, if_trampoline_or_generator = IR_UNUSED, if_rt_cache = IR_UNUSED;
4480
+ struct jit_observer_fcall_is_unobserved_data {
4481
+ ir_ref if_unobserved;
4482
+ ir_ref if_rt_cache;
4483
+ ir_ref if_trampoline_or_generator;
4484
+ };
4485
+
4486
+ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobserved_start(zend_jit_ctx *jit, const zend_function *func, ir_ref *observer_handler, ir_ref rx, ir_ref func_ref) {
4487
+ ir_ref run_time_cache;
4488
+ struct jit_observer_fcall_is_unobserved_data data = {
4489
+ .if_rt_cache = IS_UNUSED,
4490
+ .if_trampoline_or_generator = IS_UNUSED,
4491
+ };
4482
4492
if (func) {
4483
4493
ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4484
4494
} else {
4485
4495
ZEND_ASSERT(rx != IR_UNUSED);
4486
- if_trampoline_or_generator = ir_IF(ir_AND_U32(
4496
+ data. if_trampoline_or_generator = ir_IF(ir_AND_U32(
4487
4497
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4488
4498
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4489
- ir_IF_FALSE(if_trampoline_or_generator);
4499
+ ir_IF_FALSE(data. if_trampoline_or_generator);
4490
4500
}
4491
- if (func && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4492
- // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4493
- if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
4494
- ZEND_ASSERT(rx != IR_UNUSED);
4495
- run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4496
- ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4497
- ir_IF_TRUE(if_odd);
4498
-
4499
- ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4500
-
4501
- ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4502
- run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
4503
- } else {
4501
+ if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0) {
4502
+ if (ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4504
4503
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CG(map_ptr_base)), (uintptr_t)ZEND_MAP_PTR(func->common.run_time_cache)));
4504
+ } else {
4505
+ ZEND_ASSERT(rx != IR_UNUSED);
4506
+ run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(func_ref ? func_ref : ir_CONST_ADDR(func), offsetof(zend_op_array, run_time_cache__ptr)));
4507
+ data.if_rt_cache = ir_IF(ir_NE(run_time_cache, IR_NULL));
4508
+ ir_IF_TRUE(data.if_rt_cache);
4505
4509
}
4506
4510
} else {
4507
4511
ZEND_ASSERT(rx != IR_UNUSED);
4512
+ // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4508
4513
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4509
- if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4510
- ir_IF_TRUE(if_rt_cache);
4514
+ ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4515
+ ir_IF_TRUE(if_odd);
4516
+
4517
+ ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4518
+
4519
+ ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4520
+ run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
4511
4521
}
4512
4522
*observer_handler = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4513
4523
ir_ref is_unobserved = ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED));
4514
- if (if_rt_cache != IR_UNUSED) {
4515
- ir_MERGE_WITH_EMPTY_FALSE(if_rt_cache);
4516
- is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4517
- *observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4524
+
4525
+ data.if_unobserved = ir_IF(is_unobserved);
4526
+ ir_IF_FALSE(data.if_unobserved);
4527
+ return data;
4528
+ }
4529
+
4530
+ static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4531
+ if (data->if_rt_cache != IR_UNUSED) {
4532
+ ir_MERGE_WITH_EMPTY_FALSE(data->if_rt_cache);
4518
4533
}
4519
- if (if_trampoline_or_generator != IR_UNUSED) {
4520
- ir_MERGE_WITH_EMPTY_TRUE(if_trampoline_or_generator);
4521
- is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4522
- *observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4534
+ if (data->if_trampoline_or_generator != IR_UNUSED) {
4535
+ ir_MERGE_WITH_EMPTY_TRUE(data->if_trampoline_or_generator);
4523
4536
}
4524
- return is_unobserved ;
4537
+ ir_MERGE_WITH_EMPTY_TRUE(data->if_unobserved) ;
4525
4538
}
4526
4539
4527
4540
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
@@ -9947,15 +9960,13 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
9947
9960
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
9948
9961
ir_ref observer_handler;
9949
9962
ir_ref rx = jit_FP(jit); // Not sure why we cannot reuse rx here, but have to refetch
9950
- ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref);
9951
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
9952
- ir_IF_FALSE(if_is_unobserved);
9963
+ struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
9953
9964
if (GCC_GLOBAL_REGS) {
9954
9965
// EX(opline) = opline
9955
9966
ir_STORE(jit_EX(opline), jit_IP(jit));
9956
9967
}
9957
9968
jit_observer_fcall_begin(jit, rx, observer_handler);
9958
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved );
9969
+ jit_observer_fcall_is_unobserved_end(jit, &unobserved_data );
9959
9970
}
9960
9971
9961
9972
if (trace) {
@@ -10083,14 +10094,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10083
10094
ir_STORE(jit_EG(current_execute_data), rx);
10084
10095
10085
10096
bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10086
- ir_ref is_unobserved;
10087
10097
if (may_have_observer) {
10088
10098
ir_ref observer_handler;
10089
- is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10090
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
10091
- ir_IF_FALSE(if_is_unobserved);
10099
+ struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10092
10100
jit_observer_fcall_begin(jit, rx, observer_handler);
10093
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved );
10101
+ jit_observer_fcall_is_unobserved_end(jit, &unobserved_data );
10094
10102
}
10095
10103
10096
10104
// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
@@ -10131,10 +10139,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10131
10139
}
10132
10140
10133
10141
if (may_have_observer) {
10134
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
10135
- ir_IF_FALSE(if_is_unobserved);
10136
10142
jit_observer_fcall_end(jit, rx, res_addr);
10137
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved);
10138
10143
}
10139
10144
10140
10145
// JIT: EG(current_execute_data) = execute_data;
@@ -16765,7 +16770,7 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
16765
16770
}
16766
16771
16767
16772
struct jit_frameless_observer_data {
16768
- ir_ref if_is_unobserved ;
16773
+ ir_ref if_unobserved ;
16769
16774
ir_ref reused_jit_ip;
16770
16775
};
16771
16776
@@ -16774,30 +16779,31 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
16774
16779
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
16775
16780
ir_ref observer_handler;
16776
16781
zend_function *fbc = ZEND_FLF_FUNC(opline);
16777
- ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED);
16778
- data.if_is_unobserved = ir_IF(is_unobserved) ;
16782
+ // Not need for runtime cache or generator checks here, we just need if_unobserved
16783
+ data.if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved ;
16779
16784
16780
16785
// push args to a valid call frame, without copying
16781
- ir_IF_FALSE(data.if_is_unobserved);
16782
-
16783
- // yes, we'll temporarily reuse the IP, but we don't want to handle this via the reuse_ip mechanism for simiplicity
16784
16786
bool track_last_valid_opline = jit->track_last_valid_opline;
16785
16787
const zend_op *last_valid_opline = jit->last_valid_opline;
16786
16788
bool reuse_ip = jit->reuse_ip;
16787
16789
if (reuse_ip) {
16788
16790
data.reused_jit_ip = jit_IP(jit);
16789
16791
}
16790
16792
zend_jit_push_call_frame(jit, opline, NULL, fbc, 0, 0, checked_stack, ir_CONST_ADDR(fbc), IR_NULL);
16793
+ // 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
16791
16794
jit->track_last_valid_opline = track_last_valid_opline;
16792
16795
jit->last_valid_opline = last_valid_opline;
16793
16796
jit->reuse_ip = reuse_ip;
16794
16797
16798
+ // push all args
16795
16799
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
16796
16800
switch (call_num_args) {
16797
16801
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;
16798
16802
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;
16799
16803
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);
16800
16804
}
16805
+
16806
+ // Make call frame externally visible
16801
16807
ir_ref rx = jit_IP(jit);
16802
16808
ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
16803
16809
ir_STORE(jit_EG(current_execute_data), rx);
@@ -16845,7 +16851,7 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
16845
16851
}
16846
16852
16847
16853
ir_ref skip = ir_END();
16848
- ir_IF_TRUE(data->if_is_unobserved );
16854
+ ir_IF_TRUE(data->if_unobserved );
16849
16855
return skip;
16850
16856
}
16851
16857
0 commit comments