@@ -4470,51 +4470,64 @@ static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr s
4470
4470
return 1;
4471
4471
}
4472
4472
4473
- 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) {
4474
- ir_ref run_time_cache, if_trampoline_or_generator = IR_UNUSED, if_rt_cache = IR_UNUSED;
4473
+ struct jit_observer_fcall_is_unobserved_data {
4474
+ ir_ref if_unobserved;
4475
+ ir_ref if_rt_cache;
4476
+ ir_ref if_trampoline_or_generator;
4477
+ };
4478
+
4479
+ 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) {
4480
+ ir_ref run_time_cache;
4481
+ struct jit_observer_fcall_is_unobserved_data data = {
4482
+ .if_rt_cache = IS_UNUSED,
4483
+ .if_trampoline_or_generator = IS_UNUSED,
4484
+ };
4475
4485
if (func) {
4476
4486
ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
4477
4487
} else {
4478
4488
ZEND_ASSERT(rx != IR_UNUSED);
4479
- if_trampoline_or_generator = ir_IF(ir_AND_U32(
4489
+ data. if_trampoline_or_generator = ir_IF(ir_AND_U32(
4480
4490
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
4481
4491
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
4482
- ir_IF_FALSE(if_trampoline_or_generator);
4492
+ ir_IF_FALSE(data. if_trampoline_or_generator);
4483
4493
}
4484
- if (func && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4485
- // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4486
- if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
4487
- ZEND_ASSERT(rx != IR_UNUSED);
4488
- run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4489
- ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4490
- ir_IF_TRUE(if_odd);
4491
-
4492
- ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4493
-
4494
- ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4495
- run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
4496
- } else {
4494
+ if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0) {
4495
+ if (ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4497
4496
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)));
4497
+ } else {
4498
+ ZEND_ASSERT(rx != IR_UNUSED);
4499
+ 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)));
4500
+ data.if_rt_cache = ir_IF(ir_NE(run_time_cache, IR_NULL));
4501
+ ir_IF_TRUE(data.if_rt_cache);
4498
4502
}
4499
4503
} else {
4500
4504
ZEND_ASSERT(rx != IR_UNUSED);
4505
+ // Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
4501
4506
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
4502
- if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
4503
- ir_IF_TRUE(if_rt_cache);
4507
+ ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
4508
+ ir_IF_TRUE(if_odd);
4509
+
4510
+ ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
4511
+
4512
+ ir_MERGE_WITH_EMPTY_FALSE(if_odd);
4513
+ run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache2, run_time_cache);
4504
4514
}
4505
4515
*observer_handler = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
4506
4516
ir_ref is_unobserved = ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED));
4507
- if (if_rt_cache != IR_UNUSED) {
4508
- ir_MERGE_WITH_EMPTY_FALSE(if_rt_cache);
4509
- is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4510
- *observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4517
+
4518
+ data.if_unobserved = ir_IF(is_unobserved);
4519
+ ir_IF_FALSE(data.if_unobserved);
4520
+ return data;
4521
+ }
4522
+
4523
+ static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
4524
+ if (data->if_rt_cache != IR_UNUSED) {
4525
+ ir_MERGE_WITH_EMPTY_FALSE(data->if_rt_cache);
4511
4526
}
4512
- if (if_trampoline_or_generator != IR_UNUSED) {
4513
- ir_MERGE_WITH_EMPTY_TRUE(if_trampoline_or_generator);
4514
- is_unobserved = ir_PHI_2(IR_BOOL, is_unobserved, IR_TRUE);
4515
- *observer_handler = ir_PHI_2(IR_ADDR, *observer_handler, IR_NULL);
4527
+ if (data->if_trampoline_or_generator != IR_UNUSED) {
4528
+ ir_MERGE_WITH_EMPTY_TRUE(data->if_trampoline_or_generator);
4516
4529
}
4517
- return is_unobserved ;
4530
+ ir_MERGE_WITH_EMPTY_TRUE(data->if_unobserved) ;
4518
4531
}
4519
4532
4520
4533
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
@@ -9940,15 +9953,13 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
9940
9953
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
9941
9954
ir_ref observer_handler;
9942
9955
ir_ref rx = jit_FP(jit); // Not sure why we cannot reuse rx here, but have to refetch
9943
- ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref);
9944
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
9945
- ir_IF_FALSE(if_is_unobserved);
9956
+ struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
9946
9957
if (GCC_GLOBAL_REGS) {
9947
9958
// EX(opline) = opline
9948
9959
ir_STORE(jit_EX(opline), jit_IP(jit));
9949
9960
}
9950
9961
jit_observer_fcall_begin(jit, rx, observer_handler);
9951
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved );
9962
+ jit_observer_fcall_is_unobserved_end(jit, &unobserved_data );
9952
9963
}
9953
9964
9954
9965
if (trace) {
@@ -10076,14 +10087,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10076
10087
ir_STORE(jit_EG(current_execute_data), rx);
10077
10088
10078
10089
bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
10079
- ir_ref is_unobserved;
10080
10090
if (may_have_observer) {
10081
10091
ir_ref observer_handler;
10082
- is_unobserved = jit_observer_fcall_is_unobserved(jit, func, &observer_handler, rx, func_ref ? func_ref : ir_LOAD_A(jit_CALL(rx, func)));
10083
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
10084
- ir_IF_FALSE(if_is_unobserved);
10092
+ 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)));
10085
10093
jit_observer_fcall_begin(jit, rx, observer_handler);
10086
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved );
10094
+ jit_observer_fcall_is_unobserved_end(jit, &unobserved_data );
10087
10095
}
10088
10096
10089
10097
// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
@@ -10124,10 +10132,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
10124
10132
}
10125
10133
10126
10134
if (may_have_observer) {
10127
- ir_ref if_is_unobserved = ir_IF(is_unobserved);
10128
- ir_IF_FALSE(if_is_unobserved);
10129
10135
jit_observer_fcall_end(jit, rx, res_addr);
10130
- ir_MERGE_WITH_EMPTY_TRUE(if_is_unobserved);
10131
10136
}
10132
10137
10133
10138
// JIT: EG(current_execute_data) = execute_data;
@@ -16758,7 +16763,7 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
16758
16763
}
16759
16764
16760
16765
struct jit_frameless_observer_data {
16761
- ir_ref if_is_unobserved ;
16766
+ ir_ref if_unobserved ;
16762
16767
ir_ref reused_jit_ip;
16763
16768
};
16764
16769
@@ -16767,30 +16772,31 @@ static struct jit_frameless_observer_data jit_frameless_observer_begin(zend_jit_
16767
16772
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
16768
16773
ir_ref observer_handler;
16769
16774
zend_function *fbc = ZEND_FLF_FUNC(opline);
16770
- ir_ref is_unobserved = jit_observer_fcall_is_unobserved(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED);
16771
- data.if_is_unobserved = ir_IF(is_unobserved) ;
16775
+ // 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 ;
16772
16777
16773
16778
// push args to a valid call frame, without copying
16774
- ir_IF_FALSE(data.if_is_unobserved);
16775
-
16776
- // yes, we'll temporarily reuse the IP, but we don't want to handle this via the reuse_ip mechanism for simiplicity
16777
16779
bool track_last_valid_opline = jit->track_last_valid_opline;
16778
16780
const zend_op *last_valid_opline = jit->last_valid_opline;
16779
16781
bool reuse_ip = jit->reuse_ip;
16780
16782
if (reuse_ip) {
16781
16783
data.reused_jit_ip = jit_IP(jit);
16782
16784
}
16783
16785
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
16784
16787
jit->track_last_valid_opline = track_last_valid_opline;
16785
16788
jit->last_valid_opline = last_valid_opline;
16786
16789
jit->reuse_ip = reuse_ip;
16787
16790
16791
+ // push all args
16788
16792
uint32_t call_num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
16789
16793
switch (call_num_args) {
16790
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;
16791
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;
16792
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
16797
}
16798
+
16799
+ // Make call frame externally visible
16794
16800
ir_ref rx = jit_IP(jit);
16795
16801
ir_STORE(jit_CALL(rx, prev_execute_data), jit_FP(jit));
16796
16802
ir_STORE(jit_EG(current_execute_data), rx);
@@ -16838,7 +16844,7 @@ static ir_ref jit_frameless_observer_end(zend_jit_ctx *jit, struct jit_frameless
16838
16844
}
16839
16845
16840
16846
ir_ref skip = ir_END();
16841
- ir_IF_TRUE(data->if_is_unobserved );
16847
+ ir_IF_TRUE(data->if_unobserved );
16842
16848
return skip;
16843
16849
}
16844
16850
0 commit comments