Skip to content

Commit c8c4aaa

Browse files
author
test@test.test
committed
Add comments
1 parent 14bb1c1 commit c8c4aaa

File tree

5 files changed

+22
-8
lines changed

5 files changed

+22
-8
lines changed

Zend/zend_builtin_functions.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1860,7 +1860,8 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
18601860
}
18611861
zend_function *func = ZEND_FLF_FUNC(opline);
18621862
/* Assume frameless functions are not recursive with themselves.
1863-
* This condition may be true when observers are enabled. */
1863+
* This condition may be true when observers are enabled:
1864+
* Observers will put a call frame on top of the frameless opcode. */
18641865
if (last_call && last_call->func == func) {
18651866
goto not_frameless_call;
18661867
}

Zend/zend_observer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_obse
199199
ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin, zend_observer_fcall_begin_handler *next) {
200200
void **begin_handlers = (void **)ZEND_OBSERVER_DATA(function);
201201
if (zend_observer_remove_handler(begin_handlers, begin, (void**)next)) {
202+
// Ensure invariant: ZEND_OBSERVER_NONE_OBSERVED in begin_handlers if both are not observed
202203
if (*begin_handlers == ZEND_OBSERVER_NOT_OBSERVED) {
203204
size_t registered_observers = zend_observers_fcall_list.count;
204205
if (begin_handlers[registered_observers] /* first end handler */ == ZEND_OBSERVER_NOT_OBSERVED) {
@@ -230,6 +231,7 @@ ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_obs
230231
void **begin_handlers = (void **)ZEND_OBSERVER_DATA(function);
231232
void **end_handlers = begin_handlers + registered_observers;
232233
if (zend_observer_remove_handler(end_handlers, end, (void**)next)) {
234+
// Ensure invariant: ZEND_OBSERVER_NONE_OBSERVED in begin_handlers if both are not observed
233235
if (*begin_handlers == ZEND_OBSERVER_NOT_OBSERVED && *end_handlers == ZEND_OBSERVER_NOT_OBSERVED) {
234236
*begin_handlers = ZEND_OBSERVER_NONE_OBSERVED;
235237
}

Zend/zend_observer.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ typedef struct _zend_observer_fcall_handlers {
4848
#define ZEND_OBSERVER_DATA(function) \
4949
((zend_observer_fcall_begin_handler *)&ZEND_OP_ARRAY_EXTENSION((&(function)->common), ZEND_OBSERVER_HANDLE(function)))
5050

51-
#define ZEND_OBSERVER_NONE_OBSERVED ((void *) 3) // Neither begin nor end handler present
51+
/* Neither begin nor end handler present. Needs to be set in the slot of the begin handler.
52+
* Optimization reducing runtime checks. */
53+
#define ZEND_OBSERVER_NONE_OBSERVED ((void *) 3)
5254

5355
/* Omit zend_observer_fcall_internal_function_extension check, they are set at the same time. */
5456
#define ZEND_OBSERVER_ENABLED (zend_observer_fcall_op_array_extension != -1)
@@ -84,12 +86,14 @@ ZEND_API void zend_observer_activate(void);
8486
ZEND_API void zend_observer_shutdown(void);
8587

8688
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute_data);
89+
/* prechecked: the call is actually observed. */
8790
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin_prechecked(zend_execute_data *execute_data, zend_observer_fcall_begin_handler *observer_data);
8891

8992
static zend_always_inline bool zend_observer_handler_is_unobserved(zend_observer_fcall_begin_handler *handler) {
9093
return *handler == ZEND_OBSERVER_NONE_OBSERVED;
9194
}
9295

96+
/* Initial check for observers has not happened yet or no observers are installed. */
9397
static zend_always_inline bool zend_observer_fcall_has_no_observers(zend_execute_data *execute_data, bool allow_generator, zend_observer_fcall_begin_handler **handler) {
9498
zend_function *function = EX(func);
9599
void *ZEND_MAP_PTR(runtime_cache) = ZEND_MAP_PTR(function->common.run_time_cache);
@@ -106,6 +110,7 @@ static zend_always_inline bool zend_observer_fcall_has_no_observers(zend_execute
106110
return zend_observer_handler_is_unobserved(*handler);
107111
}
108112

113+
/* zend_observer_fcall_begin(), but with generator check inlined and optimized away. */
109114
static zend_always_inline void zend_observer_fcall_begin_specialized(zend_execute_data *execute_data, bool allow_generator) {
110115
zend_observer_fcall_begin_handler *handler;
111116
if (!zend_observer_fcall_has_no_observers(execute_data, allow_generator, &handler)) {
@@ -115,6 +120,7 @@ static zend_always_inline void zend_observer_fcall_begin_specialized(zend_execut
115120

116121
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(zend_execute_data *execute_data);
117122

123+
/* prechecked: the call is actually observed. */
118124
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end_prechecked(zend_execute_data *execute_data, zval *return_value);
119125
static zend_always_inline void zend_observer_fcall_end(zend_execute_data *execute_data, zval *return_value) {
120126
if (execute_data == EG(current_observed_frame)) {

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3278,4 +3278,3 @@ static zend_string* ZEND_FASTCALL zend_jit_rope_end(zend_string **rope, uint32_t
32783278
*target = '\0';
32793279
return ret;
32803280
}
3281-

ext/opcache/jit/zend_jit_ir.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4485,6 +4485,7 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse
44854485
if (func) {
44864486
ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
44874487
} else {
4488+
// JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
44884489
ZEND_ASSERT(rx != IR_UNUSED);
44894490
ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
44904491
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
@@ -4494,13 +4495,15 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse
44944495
ir_IF_FALSE(if_trampoline_or_generator);
44954496
}
44964497
if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
4498+
// JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
44974499
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)));
44984500
} else {
44994501
ZEND_ASSERT(rx != IR_UNUSED);
45004502
// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
45014503
if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
45024504
run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
45034505
} else {
4506+
// JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
45044507
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
45054508
ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
45064509
ir_IF_TRUE(if_odd);
@@ -4510,6 +4513,7 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse
45104513
ir_ref if_odd_end = ir_END();
45114514
ir_IF_FALSE(if_odd);
45124515

4516+
// JIT: if (func->common.runtime_cache != NULL) {
45134517
ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
45144518
ir_IF_TRUE(if_rt_cache);
45154519
ir_END_list(data.ir_end_inputs);
@@ -4519,12 +4523,13 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse
45194523
run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
45204524
}
45214525
}
4526+
// JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
45224527
if (func) {
45234528
*observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
45244529
} else {
4525-
// JIT: if (ZEND_USER_CODE(func->type)) {
4530+
// JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
45264531
ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
4527-
ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(1)));
4532+
ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
45284533
ir_IF_TRUE(if_internal_func);
45294534

45304535
ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
@@ -4538,11 +4543,13 @@ static struct jit_observer_fcall_is_unobserved_data jit_observer_fcall_is_unobse
45384543
*observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
45394544
}
45404545

4546+
// JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
45414547
data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
45424548
ir_IF_FALSE(data.if_unobserved);
45434549
return data;
45444550
}
45454551

4552+
/* For frameless the true branch of if_unobserved is used and this function not called. */
45464553
static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
45474554
ir_END_list(data->ir_end_inputs);
45484555
ir_IF_TRUE(data->if_unobserved);
@@ -4555,6 +4562,7 @@ static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observ
45554562
}
45564563

45574564
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
4565+
// JIT: if (execute_data == EG(current_observed_frame)) {
45584566
ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
45594567
ir_IF_TRUE(has_end_observer);
45604568
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
@@ -17058,7 +17066,7 @@ static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
1705817066
// Not need for runtime cache or generator checks here, we just need if_unobserved
1705917067
ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
1706017068

17061-
// push call frame
17069+
// Call zend_frameless_observed_call for the main logic.
1706217070
if (GCC_GLOBAL_REGS) {
1706317071
// FP register will point to the right place, but zend_frameless_observed_call needs IP to be also pointing to the precise opline.
1706417072
ir_ref old_ip = ir_HARD_COPY_A(ir_RLOAD_A(ZREG_IP));
@@ -17150,7 +17158,6 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3
1715017158
zend_jit_addr res_addr = RES_ADDR();
1715117159
zend_jit_addr op1_addr = OP1_ADDR();
1715217160
zend_jit_addr op2_addr = OP2_ADDR();
17153-
1715417161
ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
1715517162
ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
1715617163
ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
@@ -17210,7 +17217,6 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3
1721017217
zend_jit_addr op1_addr = OP1_ADDR();
1721117218
zend_jit_addr op2_addr = OP2_ADDR();
1721217219
zend_jit_addr op3_addr = OP1_DATA_ADDR();
17213-
1721417220
ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
1721517221
ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
1721617222
ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);

0 commit comments

Comments
 (0)