mirror of
https://github.com/php/php-src.git
synced 2024-11-23 01:44:06 +08:00
Optimize observers (#13649)
Inline the lookup whether a function is observed at all. This strategy is also used for FRAMELESS calls. If the frameless call is observed, we instead allocate a call frame and push the arguments, to call the the function afterwards. Doing so is still a performance benefit as opposed to executing individual INIT_FCALL+SEND_VAL ops. Thus, even if the frameless call turns out to be observed, the call overhead is slightly lower than before. If the internal function is not observed at all, the unavoidable overhead is fetching the FLF zend_function pointer and the run-time cache needs to be inspected. As part of this work, it turned out to be most viable to put the result operand on the ZEND_OP_DATA instead of ZEND_FRAMELESS_ICALL_3, allowing seamless interoperability with the DO_ICALL opcode. This is a bit unusual in comparison to all other ZEND_OP_DATA usages, but seems to not pose problems overall. There is also a small issue resolved: trampolines would always use the ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER function due to zend_observer_fcall_op_array_extension being set to -1 too late.
This commit is contained in:
parent
6e825dfe43
commit
6a2c5318f9
@ -1776,7 +1776,7 @@ ZEND_FUNCTION(debug_print_backtrace)
|
||||
|
||||
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
|
||||
{
|
||||
zend_execute_data *call;
|
||||
zend_execute_data *call, *last_call = NULL;
|
||||
zend_object *object;
|
||||
bool fake_frame = 0;
|
||||
int lineno, frameno = 0;
|
||||
@ -1821,6 +1821,7 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
|
||||
if (skip_last) {
|
||||
/* skip debug_backtrace() */
|
||||
last_call = call;
|
||||
call = call->prev_execute_data;
|
||||
}
|
||||
|
||||
@ -1857,9 +1858,15 @@ ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int
|
||||
zval *arg = zend_get_zval_ptr(op_data, op_data->op1_type, &op_data->op1, call);
|
||||
if (Z_TYPE_P(arg) == IS_UNDEF) goto not_frameless_call;
|
||||
}
|
||||
zend_function *func = ZEND_FLF_FUNC(opline);
|
||||
/* Assume frameless functions are not recursive with themselves.
|
||||
* This condition may be true when observers are enabled:
|
||||
* Observers will put a call frame on top of the frameless opcode. */
|
||||
if (last_call && last_call->func == func) {
|
||||
goto not_frameless_call;
|
||||
}
|
||||
stack_frame = zend_new_array(8);
|
||||
zend_hash_real_init_mixed(stack_frame);
|
||||
zend_function *func = ZEND_FLF_FUNC(opline);
|
||||
zend_string *name = func->common.function_name;
|
||||
ZVAL_STRINGL(&tmp, ZSTR_VAL(name), ZSTR_LEN(name));
|
||||
_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
|
||||
@ -2068,6 +2075,7 @@ skip_frame:
|
||||
} else {
|
||||
fake_frame = 0;
|
||||
include_filename = filename;
|
||||
last_call = call;
|
||||
call = prev;
|
||||
}
|
||||
}
|
||||
|
@ -4575,7 +4575,7 @@ static uint32_t find_frameless_function_offset(uint32_t arity, void *handler)
|
||||
|
||||
static const zend_frameless_function_info *find_frameless_function_info(zend_ast_list *args, zend_function *fbc, uint32_t type)
|
||||
{
|
||||
if (ZEND_OBSERVER_ENABLED || zend_execute_internal) {
|
||||
if (zend_execute_internal) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1536,6 +1536,54 @@ static zend_never_inline void zend_assign_to_object_dim(zend_object *obj, zval *
|
||||
}
|
||||
}
|
||||
|
||||
static void frameless_observed_call_copy(zend_execute_data *call, uint32_t arg, zval *zv)
|
||||
{
|
||||
if (Z_ISUNDEF_P(zv)) {
|
||||
ZVAL_NULL(ZEND_CALL_VAR_NUM(call, arg));
|
||||
} else {
|
||||
ZVAL_COPY_DEREF(ZEND_CALL_VAR_NUM(call, arg), zv);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data)
|
||||
{
|
||||
const zend_op *opline = EX(opline);
|
||||
uint8_t num_args = ZEND_FLF_NUM_ARGS(opline->opcode);
|
||||
zend_function *fbc = ZEND_FLF_FUNC(opline);
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
|
||||
zend_execute_data *call = zend_vm_stack_push_call_frame_ex(zend_vm_calc_used_stack(num_args, fbc), ZEND_CALL_NESTED_FUNCTION, fbc, num_args, NULL);
|
||||
call->prev_execute_data = execute_data;
|
||||
|
||||
switch (num_args) {
|
||||
case 3: frameless_observed_call_copy(call, 2, zend_get_zval_ptr(opline+1, (opline+1)->op1_type, &(opline+1)->op1, execute_data)); ZEND_FALLTHROUGH;
|
||||
case 2: frameless_observed_call_copy(call, 1, zend_get_zval_ptr(opline, opline->op2_type, &opline->op2, execute_data)); ZEND_FALLTHROUGH;
|
||||
case 1: frameless_observed_call_copy(call, 0, zend_get_zval_ptr(opline, opline->op1_type, &opline->op1, execute_data));
|
||||
}
|
||||
|
||||
EG(current_execute_data) = call;
|
||||
|
||||
zend_observer_fcall_begin_prechecked(call, ZEND_OBSERVER_DATA(fbc));
|
||||
fbc->internal_function.handler(call, result);
|
||||
zend_observer_fcall_end(call, result);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
if (UNEXPECTED(EG(exception) != NULL)) {
|
||||
zend_rethrow_exception(execute_data);
|
||||
}
|
||||
|
||||
zend_vm_stack_free_args(call);
|
||||
|
||||
uint32_t call_info = ZEND_CALL_INFO(call);
|
||||
if (UNEXPECTED(call_info & ZEND_CALL_ALLOCATED)) {
|
||||
zend_vm_stack_free_call_frame_ex(call_info, call);
|
||||
} else {
|
||||
EG(vm_stack_top) = (zval*)call;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static zend_always_inline int zend_binary_op(zval *ret, zval *op1, zval *op2 OPLINE_DC)
|
||||
{
|
||||
static const binary_op_type zend_binary_ops[] = {
|
||||
|
@ -430,6 +430,8 @@ ZEND_API void zend_cleanup_unfinished_execution(zend_execute_data *execute_data,
|
||||
ZEND_API ZEND_ATTRIBUTE_DEPRECATED HashTable *zend_unfinished_execution_gc(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer);
|
||||
ZEND_API HashTable *zend_unfinished_execution_gc_ex(zend_execute_data *execute_data, zend_execute_data *call, zend_get_gc_buffer *gc_buffer, bool suspended_by_yield);
|
||||
|
||||
ZEND_API void zend_frameless_observed_call(zend_execute_data *execute_data);
|
||||
|
||||
zval * ZEND_FASTCALL zend_handle_named_arg(
|
||||
zend_execute_data **call_ptr, zend_string *arg_name,
|
||||
uint32_t *arg_num_ptr, void **cache_slot);
|
||||
|
@ -115,7 +115,7 @@ typedef void (*zend_frameless_function_3)(zval *return_value, zval *op1, zval *o
|
||||
extern size_t zend_flf_count;
|
||||
extern size_t zend_flf_capacity;
|
||||
ZEND_API extern void **zend_flf_handlers;
|
||||
extern zend_function **zend_flf_functions;
|
||||
ZEND_API extern zend_function **zend_flf_functions;
|
||||
|
||||
typedef struct {
|
||||
void *handler;
|
||||
|
@ -194,6 +194,8 @@ struct _zend_executor_globals {
|
||||
|
||||
uint32_t jit_trace_num; /* Used by tracing JIT to reference the currently running trace */
|
||||
|
||||
zend_execute_data *current_observed_frame;
|
||||
|
||||
int ticks_count;
|
||||
|
||||
zend_long precision;
|
||||
|
@ -14,6 +14,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Levi Morrison <levim@php.net> |
|
||||
| Sammy Kaye Powers <sammyk@php.net> |
|
||||
| Bob Weinand <bobwei9@hotmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
@ -23,15 +24,8 @@
|
||||
#include "zend_llist.h"
|
||||
#include "zend_vm.h"
|
||||
|
||||
#define ZEND_OBSERVER_DATA(function) \
|
||||
ZEND_OP_ARRAY_EXTENSION((&(function)->common), ZEND_USER_CODE((function)->type) \
|
||||
? zend_observer_fcall_op_array_extension : zend_observer_fcall_internal_function_extension)
|
||||
|
||||
#define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2)
|
||||
|
||||
#define ZEND_OBSERVABLE_FN(function) \
|
||||
(ZEND_MAP_PTR(function->common.run_time_cache) && !(function->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
|
||||
|
||||
static zend_llist zend_observers_fcall_list;
|
||||
static zend_llist zend_observer_function_declared_callbacks;
|
||||
static zend_llist zend_observer_class_linked_callbacks;
|
||||
@ -46,8 +40,6 @@ bool zend_observer_errors_observed;
|
||||
bool zend_observer_function_declared_observed;
|
||||
bool zend_observer_class_linked_observed;
|
||||
|
||||
ZEND_TLS zend_execute_data *current_observed_frame;
|
||||
|
||||
// Call during minit/startup ONLY
|
||||
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init)
|
||||
{
|
||||
@ -107,7 +99,7 @@ ZEND_API void zend_observer_post_startup(void)
|
||||
|
||||
ZEND_API void zend_observer_activate(void)
|
||||
{
|
||||
current_observed_frame = NULL;
|
||||
EG(current_observed_frame) = NULL;
|
||||
}
|
||||
|
||||
ZEND_API void zend_observer_shutdown(void)
|
||||
@ -127,11 +119,12 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
|
||||
zend_function *function = execute_data->func;
|
||||
|
||||
ZEND_ASSERT(RUN_TIME_CACHE(&function->common));
|
||||
zend_observer_fcall_begin_handler *begin_handlers = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(function);
|
||||
zend_observer_fcall_begin_handler *begin_handlers = ZEND_OBSERVER_DATA(function), *begin_handlers_start = begin_handlers;
|
||||
zend_observer_fcall_end_handler *end_handlers = (zend_observer_fcall_end_handler *)begin_handlers + list->count, *end_handlers_start = end_handlers;
|
||||
|
||||
*begin_handlers = ZEND_OBSERVER_NOT_OBSERVED;
|
||||
*end_handlers = ZEND_OBSERVER_NOT_OBSERVED;
|
||||
bool has_handlers = false;
|
||||
|
||||
for (zend_llist_element *element = list->head; element; element = element->next) {
|
||||
zend_observer_fcall_init init;
|
||||
@ -139,9 +132,11 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
|
||||
zend_observer_fcall_handlers handlers = init(execute_data);
|
||||
if (handlers.begin) {
|
||||
*(begin_handlers++) = handlers.begin;
|
||||
has_handlers = true;
|
||||
}
|
||||
if (handlers.end) {
|
||||
*(end_handlers++) = handlers.end;
|
||||
has_handlers = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +146,10 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
|
||||
*end_handlers = *end_handlers_start;
|
||||
*end_handlers_start = tmp;
|
||||
}
|
||||
|
||||
if (!has_handlers) {
|
||||
*begin_handlers_start = ZEND_OBSERVER_NONE_OBSERVED;
|
||||
}
|
||||
}
|
||||
|
||||
/* We need to provide the ability to retrieve the handler which will move onto the position the current handler was.
|
||||
@ -182,8 +181,8 @@ static bool zend_observer_remove_handler(void **first_handler, void *old_handler
|
||||
|
||||
ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin) {
|
||||
size_t registered_observers = zend_observers_fcall_list.count;
|
||||
zend_observer_fcall_begin_handler *first_handler = (void *)&ZEND_OBSERVER_DATA(function), *last_handler = first_handler + registered_observers - 1;
|
||||
if (*first_handler == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
zend_observer_fcall_begin_handler *first_handler = ZEND_OBSERVER_DATA(function), *last_handler = first_handler + registered_observers - 1;
|
||||
if (*first_handler == ZEND_OBSERVER_NOT_OBSERVED || *first_handler == ZEND_OBSERVER_NONE_OBSERVED) {
|
||||
*first_handler = begin;
|
||||
} else {
|
||||
for (zend_observer_fcall_begin_handler *cur_handler = first_handler + 1; cur_handler <= last_handler; ++cur_handler) {
|
||||
@ -198,24 +197,47 @@ ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_obse
|
||||
}
|
||||
|
||||
ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin, zend_observer_fcall_begin_handler *next) {
|
||||
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function), begin, (void **)next);
|
||||
void **begin_handlers = (void **)ZEND_OBSERVER_DATA(function);
|
||||
if (zend_observer_remove_handler(begin_handlers, begin, (void**)next)) {
|
||||
// Ensure invariant: ZEND_OBSERVER_NONE_OBSERVED in begin_handlers if both are not observed
|
||||
if (*begin_handlers == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
size_t registered_observers = zend_observers_fcall_list.count;
|
||||
if (begin_handlers[registered_observers] /* first end handler */ == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
*begin_handlers = ZEND_OBSERVER_NONE_OBSERVED;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ZEND_API void zend_observer_add_end_handler(zend_function *function, zend_observer_fcall_end_handler end) {
|
||||
size_t registered_observers = zend_observers_fcall_list.count;
|
||||
zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(function) + registered_observers;
|
||||
void **begin_handler = (void **)ZEND_OBSERVER_DATA(function);
|
||||
zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)begin_handler + registered_observers;
|
||||
// to allow to preserve the invariant that end handlers are in reverse order of begin handlers, push the new end handler in front
|
||||
if (*end_handler != ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
// there's no space for new handlers, then it's forbidden to call this function
|
||||
ZEND_ASSERT(end_handler[registered_observers - 1] == NULL);
|
||||
memmove(end_handler + 1, end_handler, sizeof(end_handler) * (registered_observers - 1));
|
||||
} else if (*begin_handler == ZEND_OBSERVER_NONE_OBSERVED) {
|
||||
*begin_handler = ZEND_OBSERVER_NOT_OBSERVED;
|
||||
}
|
||||
*end_handler = end;
|
||||
}
|
||||
|
||||
ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end, zend_observer_fcall_end_handler *next) {
|
||||
size_t registered_observers = zend_observers_fcall_list.count;
|
||||
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function) + registered_observers, end, (void **)next);
|
||||
void **begin_handlers = (void **)ZEND_OBSERVER_DATA(function);
|
||||
void **end_handlers = begin_handlers + registered_observers;
|
||||
if (zend_observer_remove_handler(end_handlers, end, (void**)next)) {
|
||||
// Ensure invariant: ZEND_OBSERVER_NONE_OBSERVED in begin_handlers if both are not observed
|
||||
if (*begin_handlers == ZEND_OBSERVER_NOT_OBSERVED && *end_handlers == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
*begin_handlers = ZEND_OBSERVER_NONE_OBSERVED;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline zend_execute_data **prev_observed_frame(zend_execute_data *execute_data) {
|
||||
@ -224,33 +246,33 @@ static inline zend_execute_data **prev_observed_frame(zend_execute_data *execute
|
||||
return (zend_execute_data **)&Z_PTR_P(EX_VAR_NUM((ZEND_USER_CODE(func->type) ? func->op_array.last_var : ZEND_CALL_NUM_ARGS(execute_data)) + func->common.T - 1));
|
||||
}
|
||||
|
||||
static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_data)
|
||||
{
|
||||
static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_data) {
|
||||
if (!ZEND_OBSERVER_ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
zend_function *function = execute_data->func;
|
||||
zend_observer_fcall_begin_specialized(execute_data, true);
|
||||
}
|
||||
|
||||
if (!ZEND_OBSERVABLE_FN(function)) {
|
||||
return;
|
||||
}
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin_prechecked(zend_execute_data *execute_data, zend_observer_fcall_begin_handler *handler)
|
||||
{
|
||||
zend_observer_fcall_begin_handler *possible_handlers_end = handler + zend_observers_fcall_list.count;
|
||||
|
||||
zend_observer_fcall_begin_handler *handler = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(function);
|
||||
if (!*handler) {
|
||||
zend_observer_fcall_install(execute_data);
|
||||
if (zend_observer_handler_is_unobserved(handler)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
zend_observer_fcall_begin_handler *possible_handlers_end = handler + zend_observers_fcall_list.count;
|
||||
|
||||
zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)possible_handlers_end;
|
||||
if (*end_handler != ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
*prev_observed_frame(execute_data) = current_observed_frame;
|
||||
current_observed_frame = execute_data;
|
||||
}
|
||||
*prev_observed_frame(execute_data) = EG(current_observed_frame);
|
||||
EG(current_observed_frame) = execute_data;
|
||||
|
||||
if (*handler == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
return;
|
||||
if (*handler == ZEND_OBSERVER_NOT_OBSERVED) { // this function must not be called if ZEND_OBSERVER_NONE_OBSERVED, hence sufficient to check
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
@ -265,17 +287,17 @@ ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(zend_execute_data *ex
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute_data)
|
||||
{
|
||||
ZEND_ASSUME(execute_data->func);
|
||||
if (!(execute_data->func->common.fn_flags & ZEND_ACC_GENERATOR)) {
|
||||
ZEND_ASSUME(EX(func));
|
||||
if (!(EX(func)->common.fn_flags & ZEND_ACC_GENERATOR)) {
|
||||
_zend_observe_fcall_begin(execute_data);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void call_end_observers(zend_execute_data *execute_data, zval *return_value) {
|
||||
zend_function *func = execute_data->func;
|
||||
zend_function *func = EX(func);
|
||||
ZEND_ASSERT(func);
|
||||
|
||||
zend_observer_fcall_end_handler *handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(func) + zend_observers_fcall_list.count;
|
||||
zend_observer_fcall_end_handler *handler = (zend_observer_fcall_end_handler *)ZEND_OBSERVER_DATA(func) + zend_observers_fcall_list.count;
|
||||
// TODO: Fix exceptions from generators
|
||||
// ZEND_ASSERT(fcall_data);
|
||||
if (!*handler || *handler == ZEND_OBSERVER_NOT_OBSERVED) {
|
||||
@ -288,19 +310,16 @@ static inline void call_end_observers(zend_execute_data *execute_data, zval *ret
|
||||
} while (++handler != possible_handlers_end && *handler != NULL);
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_data, zval *return_value)
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end_prechecked(zend_execute_data *execute_data, zval *return_value)
|
||||
{
|
||||
if (execute_data != current_observed_frame) {
|
||||
return;
|
||||
}
|
||||
call_end_observers(execute_data, return_value);
|
||||
current_observed_frame = *prev_observed_frame(execute_data);
|
||||
EG(current_observed_frame) = *prev_observed_frame(execute_data);
|
||||
}
|
||||
|
||||
ZEND_API void zend_observer_fcall_end_all(void)
|
||||
{
|
||||
zend_execute_data *execute_data = current_observed_frame, *original_execute_data = EG(current_execute_data);
|
||||
current_observed_frame = NULL;
|
||||
zend_execute_data *execute_data = EG(current_observed_frame), *original_execute_data = EG(current_execute_data);
|
||||
EG(current_observed_frame) = NULL;
|
||||
while (execute_data) {
|
||||
EG(current_execute_data) = execute_data;
|
||||
call_end_observers(execute_data, NULL);
|
||||
@ -401,8 +420,8 @@ ZEND_API void ZEND_FASTCALL zend_observer_fiber_switch_notify(zend_fiber_context
|
||||
callback(from, to);
|
||||
}
|
||||
|
||||
from->top_observed_frame = current_observed_frame;
|
||||
current_observed_frame = to->top_observed_frame;
|
||||
from->top_observed_frame = EG(current_observed_frame);
|
||||
EG(current_observed_frame) = to->top_observed_frame;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fiber_destroy_notify(zend_fiber_context *destroying)
|
||||
|
@ -14,6 +14,7 @@
|
||||
+----------------------------------------------------------------------+
|
||||
| Authors: Levi Morrison <levim@php.net> |
|
||||
| Sammy Kaye Powers <sammyk@php.net> |
|
||||
| Bob Weinand <bobwei9@hotmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
@ -32,6 +33,16 @@ extern ZEND_API bool zend_observer_errors_observed;
|
||||
extern ZEND_API bool zend_observer_function_declared_observed;
|
||||
extern ZEND_API bool zend_observer_class_linked_observed;
|
||||
|
||||
#define ZEND_OBSERVER_HANDLE(function) (ZEND_USER_CODE((function)->type) \
|
||||
? zend_observer_fcall_op_array_extension : zend_observer_fcall_internal_function_extension)
|
||||
|
||||
#define ZEND_OBSERVER_DATA(function) \
|
||||
((zend_observer_fcall_begin_handler *)&ZEND_OP_ARRAY_EXTENSION((&(function)->common), ZEND_OBSERVER_HANDLE(function)))
|
||||
|
||||
/* Neither begin nor end handler present. Needs to be set in the slot of the begin handler.
|
||||
* Optimization reducing runtime checks. */
|
||||
#define ZEND_OBSERVER_NONE_OBSERVED ((void *) 3)
|
||||
|
||||
/* Omit zend_observer_fcall_internal_function_extension check, they are set at the same time. */
|
||||
#define ZEND_OBSERVER_ENABLED (zend_observer_fcall_op_array_extension != -1)
|
||||
|
||||
@ -73,15 +84,48 @@ ZEND_API void zend_observer_post_startup(void); // Called by engine after MINITs
|
||||
ZEND_API void zend_observer_activate(void);
|
||||
ZEND_API void zend_observer_shutdown(void);
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(
|
||||
zend_execute_data *execute_data);
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute_data);
|
||||
/* prechecked: the call is actually observed. */
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin_prechecked(zend_execute_data *execute_data, zend_observer_fcall_begin_handler *observer_data);
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(
|
||||
zend_execute_data *execute_data);
|
||||
static zend_always_inline bool zend_observer_handler_is_unobserved(zend_observer_fcall_begin_handler *handler) {
|
||||
return *handler == ZEND_OBSERVER_NONE_OBSERVED;
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(
|
||||
zend_execute_data *execute_data,
|
||||
zval *return_value);
|
||||
/* Initial check for observers has not happened yet or no observers are installed. */
|
||||
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) {
|
||||
zend_function *function = EX(func);
|
||||
void *ZEND_MAP_PTR(runtime_cache) = ZEND_MAP_PTR(function->common.run_time_cache);
|
||||
|
||||
if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | (allow_generator ? 0 : ZEND_ACC_GENERATOR))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ZEND_MAP_PTR(runtime_cache)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*handler = (zend_observer_fcall_begin_handler *)ZEND_MAP_PTR_GET(runtime_cache) + ZEND_OBSERVER_HANDLE(function);
|
||||
return zend_observer_handler_is_unobserved(*handler);
|
||||
}
|
||||
|
||||
/* zend_observer_fcall_begin(), but with generator check inlined and optimized away. */
|
||||
static zend_always_inline void zend_observer_fcall_begin_specialized(zend_execute_data *execute_data, bool allow_generator) {
|
||||
zend_observer_fcall_begin_handler *handler;
|
||||
if (!zend_observer_fcall_has_no_observers(execute_data, allow_generator, &handler)) {
|
||||
zend_observer_fcall_begin_prechecked(execute_data, handler);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(zend_execute_data *execute_data);
|
||||
|
||||
/* prechecked: the call is actually observed. */
|
||||
ZEND_API void ZEND_FASTCALL zend_observer_fcall_end_prechecked(zend_execute_data *execute_data, zval *return_value);
|
||||
static zend_always_inline void zend_observer_fcall_end(zend_execute_data *execute_data, zval *return_value) {
|
||||
if (execute_data == EG(current_observed_frame)) {
|
||||
zend_observer_fcall_end_prechecked(execute_data, return_value);
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_API void zend_observer_fcall_end_all(void);
|
||||
|
||||
|
@ -9599,38 +9599,59 @@ ZEND_VM_C_LABEL(try_again):
|
||||
}
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICALL_0, UNUSED, UNUSED)
|
||||
ZEND_VM_HANDLER(204, ZEND_FRAMELESS_ICALL_0, UNUSED, UNUSED, SPEC(OBSERVER))
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
function(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
|
||||
#if !ZEND_VM_SPEC || ZEND_OBSERVER_ENABLED
|
||||
if (ZEND_OBSERVER_ENABLED && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(EX_VAR(opline->result.var));
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED)
|
||||
ZEND_VM_HANDLER(205, ZEND_FRAMELESS_ICALL_1, ANY, UNUSED, SPEC(OBSERVER))
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
FREE_OP1();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1);
|
||||
|
||||
#if !ZEND_VM_SPEC || ZEND_OBSERVER_ENABLED
|
||||
if (ZEND_OBSERVER_ENABLED && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP1();
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY)
|
||||
ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY, SPEC(OBSERVER))
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
zval *arg2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
@ -9638,7 +9659,17 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY)
|
||||
FREE_OP2();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1, arg2);
|
||||
|
||||
#if !ZEND_VM_SPEC || ZEND_OBSERVER_ENABLED
|
||||
if (ZEND_OBSERVER_ENABLED && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2);
|
||||
}
|
||||
|
||||
FREE_OP1();
|
||||
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
|
||||
if (OP1_TYPE & (IS_VAR|IS_TMP_VAR)) {
|
||||
@ -9648,12 +9679,13 @@ ZEND_VM_HANDLER(206, ZEND_FRAMELESS_ICALL_2, ANY, ANY)
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY)
|
||||
ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY, SPEC(OBSERVER))
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
zval *arg2 = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
zval *arg3 = GET_OP_DATA_ZVAL_PTR_DEREF(BP_VAR_R);
|
||||
@ -9663,7 +9695,17 @@ ZEND_VM_HANDLER(207, ZEND_FRAMELESS_ICALL_3, ANY, ANY)
|
||||
FREE_OP_DATA();
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1, arg2, arg3);
|
||||
|
||||
#if !ZEND_VM_SPEC || ZEND_OBSERVER_ENABLED
|
||||
if (ZEND_OBSERVER_ENABLED && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
FREE_OP1();
|
||||
/* Set to UNDEF in case FREE_OP2() throws. */
|
||||
if (OP1_TYPE & (IS_VAR|IS_TMP_VAR)) {
|
||||
|
436
Zend/zend_vm_execute.h
generated
436
Zend/zend_vm_execute.h
generated
@ -1408,7 +1408,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBS
|
||||
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
|
||||
ZVAL_NULL(ret);
|
||||
|
||||
zend_observer_fcall_begin(call);
|
||||
zend_observer_fcall_begin_specialized(call, false);
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
@ -1519,7 +1519,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_OBS
|
||||
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
|
||||
LOAD_OPLINE_EX();
|
||||
SAVE_OPLINE();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
|
||||
ZEND_VM_ENTER_EX();
|
||||
}
|
||||
@ -1735,7 +1735,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
|
||||
i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC);
|
||||
LOAD_OPLINE_EX();
|
||||
SAVE_OPLINE();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
|
||||
ZEND_VM_ENTER_EX();
|
||||
} else {
|
||||
@ -1767,7 +1767,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
|
||||
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
|
||||
ZVAL_NULL(ret);
|
||||
|
||||
zend_observer_fcall_begin(call);
|
||||
zend_observer_fcall_begin_specialized(call, false);
|
||||
fbc->internal_function.handler(call, ret);
|
||||
|
||||
#if ZEND_DEBUG
|
||||
@ -2053,11 +2053,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
|
||||
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||
LOAD_OPLINE_EX();
|
||||
SAVE_OPLINE();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
ZEND_VM_ENTER_EX();
|
||||
} else {
|
||||
SAVE_OPLINE_EX();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
execute_data = EX(prev_execute_data);
|
||||
LOAD_OPLINE();
|
||||
ZEND_ADD_CALL_FLAG(call, ZEND_CALL_TOP);
|
||||
@ -2092,7 +2092,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
|
||||
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
|
||||
ZVAL_NULL(ret);
|
||||
|
||||
zend_observer_fcall_begin(call);
|
||||
zend_observer_fcall_begin_specialized(call, false);
|
||||
if (!zend_execute_internal) {
|
||||
/* saves one function call if zend_execute_internal is not used */
|
||||
fbc->internal_function.handler(call, ret);
|
||||
@ -3610,11 +3610,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_
|
||||
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||
LOAD_OPLINE_EX();
|
||||
SAVE_OPLINE();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
ZEND_VM_ENTER_EX();
|
||||
} else {
|
||||
SAVE_OPLINE_EX();
|
||||
zend_observer_fcall_begin(execute_data);
|
||||
zend_observer_fcall_begin_specialized(execute_data, false);
|
||||
execute_data = EX(prev_execute_data);
|
||||
if (execute_data) {
|
||||
LOAD_OPLINE();
|
||||
@ -3638,7 +3638,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_
|
||||
}
|
||||
|
||||
ZVAL_NULL(ret);
|
||||
zend_observer_fcall_begin(call);
|
||||
zend_observer_fcall_begin_specialized(call, false);
|
||||
if (!zend_execute_internal) {
|
||||
/* saves one function call if zend_execute_internal is not used */
|
||||
fbc->internal_function.handler(call, ret);
|
||||
@ -3697,8 +3697,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
@ -3706,7 +3707,51 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1, arg2);
|
||||
|
||||
#if 0 || 0
|
||||
if (0 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2);
|
||||
}
|
||||
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
/* Set OP1 to UNDEF in case FREE_OP(opline->op2_type, opline->op2.var) throws. */
|
||||
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
#if 0 || 1
|
||||
if (1 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_2 function = (zend_frameless_function_2)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2);
|
||||
}
|
||||
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
/* Set OP1 to UNDEF in case FREE_OP(opline->op2_type, opline->op2.var) throws. */
|
||||
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
|
||||
@ -3720,8 +3765,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R);
|
||||
zval *arg3 = get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1);
|
||||
@ -3731,7 +3777,57 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1, arg2, arg3);
|
||||
|
||||
#if 0 || 0
|
||||
if (0 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
/* Set to UNDEF in case FREE_OP(opline->op2_type, opline->op2.var) throws. */
|
||||
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
|
||||
ZVAL_UNDEF(EX_VAR(opline->op1.var));
|
||||
}
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
|
||||
ZVAL_UNDEF(EX_VAR(opline->op2.var));
|
||||
}
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
ZEND_VM_NEXT_OPCODE_EX(1, 2);
|
||||
}
|
||||
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
zval *arg2 = get_zval_ptr_deref(opline->op2_type, opline->op2, BP_VAR_R);
|
||||
zval *arg3 = get_op_data_zval_ptr_deref_r((opline+1)->op1_type, (opline+1)->op1);
|
||||
if (EG(exception)) {
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
FREE_OP(opline->op2_type, opline->op2.var);
|
||||
FREE_OP((opline+1)->op1_type, (opline+1)->op1.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
#if 0 || 1
|
||||
if (1 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_3 function = (zend_frameless_function_3)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1, arg2, arg3);
|
||||
}
|
||||
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
/* Set to UNDEF in case FREE_OP(opline->op2_type, opline->op2.var) throws. */
|
||||
if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
|
||||
@ -4138,14 +4234,50 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
function(EX_VAR(opline->result.var), arg1);
|
||||
|
||||
#if 0 || 0
|
||||
if (0 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
zval *arg1 = get_zval_ptr_deref(opline->op1_type, opline->op1, BP_VAR_R);
|
||||
if (EG(exception)) {
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
#if 0 || 1
|
||||
if (1 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_1 function = (zend_frameless_function_1)ZEND_FLF_HANDLER(opline);
|
||||
function(result, arg1);
|
||||
}
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
@ -5217,7 +5349,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_OBSERVER_
|
||||
|
||||
call->prev_execute_data = execute_data;
|
||||
i_init_code_execute_data(call, new_op_array, return_value);
|
||||
zend_observer_fcall_begin(call);
|
||||
zend_observer_fcall_begin_specialized(call, false);
|
||||
if (EXPECTED(zend_execute_ex == execute_ex)) {
|
||||
FREE_OP(opline->op1_type, opline->op1.var);
|
||||
ZEND_VM_ENTER();
|
||||
@ -37351,9 +37483,39 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_0_SPEC_UNUSED_
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
function(EX_VAR(opline->result.var));
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
|
||||
#if 0 || 0
|
||||
if (0 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(EX_VAR(opline->result.var));
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
USE_OPLINE
|
||||
SAVE_OPLINE();
|
||||
|
||||
zval *result = EX_VAR(opline->result.var);
|
||||
ZVAL_NULL(result);
|
||||
|
||||
#if 0 || 1
|
||||
if (1 && UNEXPECTED(zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(ZEND_FLF_FUNC(opline))) == false)) {
|
||||
zend_frameless_observed_call(execute_data);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
zend_frameless_function_0 function = (zend_frameless_function_0)ZEND_FLF_HANDLER(opline);
|
||||
function(EX_VAR(opline->result.var));
|
||||
}
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
}
|
||||
|
||||
@ -56188,9 +56350,13 @@ ZEND_API void execute_ex(zend_execute_data *ex)
|
||||
(void*)&&ZEND_CALLABLE_CONVERT_SPEC_UNUSED_UNUSED_LABEL,
|
||||
(void*)&&ZEND_BIND_INIT_STATIC_OR_JMP_SPEC_CV_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_0_SPEC_UNUSED_UNUSED_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_2_SPEC_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_3_SPEC_LABEL,
|
||||
(void*)&&ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER_LABEL,
|
||||
(void*)&&ZEND_JMP_FRAMELESS_SPEC_CONST_LABEL,
|
||||
(void*)&&ZEND_INIT_FCALL_OFFSET_SPEC_CONST_LABEL,
|
||||
(void*)&&ZEND_RECV_NOTYPE_SPEC_LABEL,
|
||||
@ -57549,11 +57715,21 @@ zend_leave_helper_SPEC_LABEL:
|
||||
ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_2_SPEC)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER):
|
||||
VM_TRACE(ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER)
|
||||
ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_FRAMELESS_ICALL_3_SPEC):
|
||||
VM_TRACE(ZEND_FRAMELESS_ICALL_3_SPEC)
|
||||
ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_3_SPEC)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER):
|
||||
VM_TRACE(ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER)
|
||||
ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_JMP_FORWARD_SPEC):
|
||||
VM_TRACE(ZEND_JMP_FORWARD_SPEC)
|
||||
ZEND_JMP_FORWARD_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
@ -57609,6 +57785,11 @@ zend_leave_helper_SPEC_LABEL:
|
||||
ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER):
|
||||
VM_TRACE(ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER)
|
||||
ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_INIT_DYNAMIC_CALL_SPEC_CV):
|
||||
VM_TRACE(ZEND_INIT_DYNAMIC_CALL_SPEC_CV)
|
||||
ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
@ -61236,6 +61417,11 @@ zend_leave_helper_SPEC_LABEL:
|
||||
ZEND_FRAMELESS_ICALL_0_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_0_SPEC_UNUSED_UNUSED)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER):
|
||||
VM_TRACE(ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER)
|
||||
ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
VM_TRACE_OP_END(ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER)
|
||||
HYBRID_BREAK();
|
||||
HYBRID_CASE(ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_CV):
|
||||
VM_TRACE(ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_CV)
|
||||
ZEND_ASSIGN_OBJ_OP_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
@ -65351,9 +65537,13 @@ void zend_vm_init(void)
|
||||
ZEND_CALLABLE_CONVERT_SPEC_UNUSED_UNUSED_HANDLER,
|
||||
ZEND_BIND_INIT_STATIC_OR_JMP_SPEC_CV_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_0_SPEC_UNUSED_UNUSED_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_0_SPEC_OBSERVER_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_1_SPEC_UNUSED_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_1_SPEC_OBSERVER_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_2_SPEC_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_2_SPEC_OBSERVER_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_3_SPEC_HANDLER,
|
||||
ZEND_FRAMELESS_ICALL_3_SPEC_OBSERVER_HANDLER,
|
||||
ZEND_JMP_FRAMELESS_SPEC_CONST_HANDLER,
|
||||
ZEND_INIT_FCALL_OFFSET_SPEC_CONST_HANDLER,
|
||||
ZEND_RECV_NOTYPE_SPEC_HANDLER,
|
||||
@ -66312,7 +66502,7 @@ void zend_vm_init(void)
|
||||
1255,
|
||||
1256 | SPEC_RULE_OP1,
|
||||
1261 | SPEC_RULE_OP1,
|
||||
3482,
|
||||
3486,
|
||||
1266 | SPEC_RULE_OP1,
|
||||
1271 | SPEC_RULE_OP1,
|
||||
1276 | SPEC_RULE_OP2,
|
||||
@ -66471,58 +66661,58 @@ void zend_vm_init(void)
|
||||
2565,
|
||||
2566,
|
||||
2567,
|
||||
2568,
|
||||
2569,
|
||||
2570,
|
||||
2571,
|
||||
2572,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
3482,
|
||||
2568 | SPEC_RULE_OBSERVER,
|
||||
2570 | SPEC_RULE_OBSERVER,
|
||||
2572 | SPEC_RULE_OBSERVER,
|
||||
2574 | SPEC_RULE_OBSERVER,
|
||||
2576,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
3486,
|
||||
};
|
||||
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
|
||||
zend_opcode_handler_funcs = labels;
|
||||
@ -66695,7 +66885,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2581 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2585 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
if (op->op1_type < op->op2_type) {
|
||||
zend_swap_operands(op);
|
||||
}
|
||||
@ -66703,7 +66893,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2606 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2610 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
if (op->op1_type < op->op2_type) {
|
||||
zend_swap_operands(op);
|
||||
}
|
||||
@ -66711,7 +66901,7 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2631 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2635 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
if (op->op1_type < op->op2_type) {
|
||||
zend_swap_operands(op);
|
||||
}
|
||||
@ -66722,17 +66912,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2656 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
spec = 2660 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
} else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2681 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
spec = 2685 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2706 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
spec = 2710 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
}
|
||||
break;
|
||||
case ZEND_MUL:
|
||||
@ -66743,17 +66933,17 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2731 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2735 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2756 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2760 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2781 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2785 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_IDENTICAL:
|
||||
@ -66764,14 +66954,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2806 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2810 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2881 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2885 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) {
|
||||
spec = 3106 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 3110 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_NOT_IDENTICAL:
|
||||
@ -66782,14 +66972,14 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2956 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2960 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3031 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 3035 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op->op1_type == IS_CV && (op->op2_type & (IS_CONST|IS_CV)) && !(op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) && !(op2_info & (MAY_BE_UNDEF|MAY_BE_REF))) {
|
||||
spec = 3111 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 3115 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_EQUAL:
|
||||
@ -66800,12 +66990,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2806 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2810 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2881 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2885 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_NOT_EQUAL:
|
||||
@ -66816,12 +67006,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 2956 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 2960 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3031 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
spec = 3035 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_SMALLER:
|
||||
@ -66829,12 +67019,12 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3116 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
spec = 3120 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3191 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
spec = 3195 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
}
|
||||
break;
|
||||
case ZEND_IS_SMALLER_OR_EQUAL:
|
||||
@ -66842,79 +67032,79 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3266 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
spec = 3270 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3341 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
spec = 3345 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
|
||||
}
|
||||
break;
|
||||
case ZEND_QM_ASSIGN:
|
||||
if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3428 | SPEC_RULE_OP1;
|
||||
spec = 3432 | SPEC_RULE_OP1;
|
||||
} else if (op1_info == MAY_BE_DOUBLE) {
|
||||
spec = 3433 | SPEC_RULE_OP1;
|
||||
spec = 3437 | SPEC_RULE_OP1;
|
||||
} else if ((op->op1_type == IS_CONST) ? !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1)) : (!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) {
|
||||
spec = 3438 | SPEC_RULE_OP1;
|
||||
spec = 3442 | SPEC_RULE_OP1;
|
||||
}
|
||||
break;
|
||||
case ZEND_PRE_INC:
|
||||
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
|
||||
spec = 3416 | SPEC_RULE_RETVAL;
|
||||
} else if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3418 | SPEC_RULE_RETVAL;
|
||||
}
|
||||
break;
|
||||
case ZEND_PRE_DEC:
|
||||
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
|
||||
spec = 3420 | SPEC_RULE_RETVAL;
|
||||
} else if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3422 | SPEC_RULE_RETVAL;
|
||||
}
|
||||
break;
|
||||
case ZEND_PRE_DEC:
|
||||
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
|
||||
spec = 3424 | SPEC_RULE_RETVAL;
|
||||
} else if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3426 | SPEC_RULE_RETVAL;
|
||||
}
|
||||
break;
|
||||
case ZEND_POST_INC:
|
||||
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
|
||||
spec = 3424;
|
||||
spec = 3428;
|
||||
} else if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3425;
|
||||
spec = 3429;
|
||||
}
|
||||
break;
|
||||
case ZEND_POST_DEC:
|
||||
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
|
||||
spec = 3426;
|
||||
spec = 3430;
|
||||
} else if (op1_info == MAY_BE_LONG) {
|
||||
spec = 3427;
|
||||
spec = 3431;
|
||||
}
|
||||
break;
|
||||
case ZEND_JMP:
|
||||
if (OP_JMP_ADDR(op, op->op1) > op) {
|
||||
spec = 2580;
|
||||
spec = 2584;
|
||||
}
|
||||
break;
|
||||
case ZEND_INIT_FCALL:
|
||||
if (Z_EXTRA_P(RT_CONSTANT(op, op->op2)) != 0) {
|
||||
spec = 2573;
|
||||
spec = 2577;
|
||||
}
|
||||
break;
|
||||
case ZEND_RECV:
|
||||
if (op->op2.num == MAY_BE_ANY) {
|
||||
spec = 2574;
|
||||
spec = 2578;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAL:
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) {
|
||||
spec = 3478;
|
||||
spec = 3482;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAR_EX:
|
||||
if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) {
|
||||
spec = 3473 | SPEC_RULE_OP1;
|
||||
spec = 3477 | SPEC_RULE_OP1;
|
||||
}
|
||||
break;
|
||||
case ZEND_FE_FETCH_R:
|
||||
if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) {
|
||||
spec = 3480 | SPEC_RULE_RETVAL;
|
||||
spec = 3484 | SPEC_RULE_RETVAL;
|
||||
}
|
||||
break;
|
||||
case ZEND_FETCH_DIM_R:
|
||||
@ -66922,22 +67112,22 @@ ZEND_API void ZEND_FASTCALL zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t
|
||||
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
|
||||
break;
|
||||
}
|
||||
spec = 3443 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
spec = 3447 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAL_EX:
|
||||
if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && op->op1_type == IS_CONST && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) {
|
||||
spec = 3479;
|
||||
spec = 3483;
|
||||
}
|
||||
break;
|
||||
case ZEND_SEND_VAR:
|
||||
if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) {
|
||||
spec = 3468 | SPEC_RULE_OP1;
|
||||
spec = 3472 | SPEC_RULE_OP1;
|
||||
}
|
||||
break;
|
||||
case ZEND_COUNT:
|
||||
if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_ARRAY) {
|
||||
spec = 2575 | SPEC_RULE_OP1;
|
||||
spec = 2579 | SPEC_RULE_OP1;
|
||||
}
|
||||
break;
|
||||
case ZEND_BW_OR:
|
||||
|
@ -730,8 +730,8 @@ function gen_code($f, $spec, $kind, $code, $op1, $op2, $name, $extra_spec=null)
|
||||
"/FREE_OP2\(\)/" => $op2_free_op[$op2],
|
||||
"/FREE_OP1_IF_VAR\(\)/" => $op1_free_op_if_var[$op1],
|
||||
"/FREE_OP2_IF_VAR\(\)/" => $op2_free_op_if_var[$op2],
|
||||
"/\!ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"0":"1",
|
||||
"/ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY")?"1":"0",
|
||||
"/\!ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY"||$extra_spec)?"0":"1",
|
||||
"/ZEND_VM_SPEC/m" => ($op1!="ANY"||$op2!="ANY"||$extra_spec)?"1":"0",
|
||||
"/ZEND_VM_C_LABEL\(\s*([A-Za-z_]*)\s*\)/m" => "\\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""),
|
||||
"/ZEND_VM_C_GOTO\(\s*([A-Za-z_]*)\s*\)/m" => "goto \\1".(($spec && $kind != ZEND_VM_KIND_CALL)?("_SPEC".$prefix[$op1].$prefix[$op2].extra_spec_name($extra_spec)):""),
|
||||
"/^#(\s*)if\s+1\s*\\|\\|.*[^\\\\]$/m" => "#\\1if 1",
|
||||
@ -776,7 +776,7 @@ function gen_code($f, $spec, $kind, $code, $op1, $op2, $name, $extra_spec=null)
|
||||
"/ZEND_OBSERVER_FREE_RETVAL\(\)/" => isset($extra_spec['OBSERVER']) && $extra_spec['OBSERVER'] == 1 ? "if (return_value == &observer_retval) { zval_ptr_dtor_nogc(&observer_retval); }" : "",
|
||||
"/ZEND_OBSERVER_SAVE_OPLINE\(\)/" => isset($extra_spec['OBSERVER']) && $extra_spec['OBSERVER'] == 1 ? "SAVE_OPLINE()" : "",
|
||||
"/ZEND_OBSERVER_FCALL_BEGIN\(\s*(.*)\s*\)/" => isset($extra_spec['OBSERVER']) ?
|
||||
($extra_spec['OBSERVER'] == 0 ? "" : "zend_observer_fcall_begin(\\1)")
|
||||
($extra_spec['OBSERVER'] == 0 ? "" : "zend_observer_fcall_begin_specialized(\\1, false)")
|
||||
: "",
|
||||
"/ZEND_OBSERVER_FCALL_END\(\s*([^,]*)\s*,\s*(.*)\s*\)/" => isset($extra_spec['OBSERVER']) ?
|
||||
($extra_spec['OBSERVER'] == 0 ? "" : "zend_observer_fcall_end(\\1, \\2)")
|
||||
|
990
Zend/zend_vm_handlers.h
generated
990
Zend/zend_vm_handlers.h
generated
File diff suppressed because it is too large
Load Diff
@ -4513,6 +4513,102 @@ static int zend_jit_update_regs(zend_jit_ctx *jit, uint32_t var, zend_jit_addr s
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct jit_observer_fcall_is_unobserved_data {
|
||||
ir_ref if_unobserved;
|
||||
ir_ref ir_end_inputs;
|
||||
};
|
||||
|
||||
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) {
|
||||
ir_ref run_time_cache;
|
||||
struct jit_observer_fcall_is_unobserved_data data = { .ir_end_inputs = IR_UNUSED };
|
||||
if (func) {
|
||||
ZEND_ASSERT((func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
|
||||
} else {
|
||||
// JIT: if (function->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) {
|
||||
ZEND_ASSERT(rx != IR_UNUSED);
|
||||
ir_ref if_trampoline_or_generator = ir_IF(ir_AND_U32(
|
||||
ir_LOAD_U32(ir_ADD_OFFSET(func_ref, offsetof(zend_function, common.fn_flags))),
|
||||
ir_CONST_U32(ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)));
|
||||
ir_IF_TRUE(if_trampoline_or_generator);
|
||||
ir_END_list(data.ir_end_inputs);
|
||||
ir_IF_FALSE(if_trampoline_or_generator);
|
||||
}
|
||||
if (func && (func->common.fn_flags & ZEND_ACC_CLOSURE) == 0 && ZEND_MAP_PTR_IS_OFFSET(func->common.run_time_cache)) {
|
||||
// JIT: ZEND_MAP_PTR_GET_IMM(func->common.runtime_cache)
|
||||
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)));
|
||||
} else {
|
||||
ZEND_ASSERT(rx != IR_UNUSED);
|
||||
// Closures may be duplicated and have a different runtime cache. Use the regular run_time_cache access pattern for these
|
||||
if (func && ZEND_USER_CODE(func->type)) { // not a closure and definitely not an internal function
|
||||
run_time_cache = ir_LOAD_A(jit_CALL(rx, run_time_cache));
|
||||
} else {
|
||||
// JIT: ZEND_MAP_PTR_GET(func->common.runtime_cache)
|
||||
run_time_cache = ir_LOAD_A(ir_ADD_OFFSET(ir_LOAD_A(jit_CALL(rx, func)), offsetof(zend_op_array, run_time_cache__ptr)));
|
||||
ir_ref if_odd = ir_IF(ir_AND_A(run_time_cache, ir_CONST_ADDR(1)));
|
||||
ir_IF_TRUE(if_odd);
|
||||
|
||||
ir_ref run_time_cache2 = ir_LOAD_A(ir_ADD_A(run_time_cache, ir_LOAD_A(jit_CG(map_ptr_base))));
|
||||
|
||||
ir_ref if_odd_end = ir_END();
|
||||
ir_IF_FALSE(if_odd);
|
||||
|
||||
// JIT: if (func->common.runtime_cache != NULL) {
|
||||
ir_ref if_rt_cache = ir_IF(ir_EQ(run_time_cache, IR_NULL));
|
||||
ir_IF_TRUE(if_rt_cache);
|
||||
ir_END_list(data.ir_end_inputs);
|
||||
ir_IF_FALSE(if_rt_cache);
|
||||
|
||||
ir_MERGE_WITH(if_odd_end);
|
||||
run_time_cache = ir_PHI_2(IR_ADDR, run_time_cache, run_time_cache2);
|
||||
}
|
||||
}
|
||||
// JIT: observer_handler = runtime_cache + ZEND_OBSERVER_HANDLE(function)
|
||||
if (func) {
|
||||
*observer_handler = ir_ADD_OFFSET(run_time_cache, ZEND_OBSERVER_HANDLE(func) * sizeof(void *));
|
||||
} else {
|
||||
// JIT: (func->type == ZEND_INTERNAL_FUNCTION ? zend_observer_fcall_internal_function_extension : zend_observer_fcall_op_array_extension) * sizeof(void *)
|
||||
ir_ref tmp = ir_LOAD_U8(ir_ADD_OFFSET(func_ref, offsetof(zend_function, type)));
|
||||
ir_ref if_internal_func = ir_IF(ir_AND_U8(tmp, ir_CONST_U8(ZEND_INTERNAL_FUNCTION)));
|
||||
ir_IF_TRUE(if_internal_func);
|
||||
|
||||
ir_ref observer_handler_internal = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_internal_function_extension * sizeof(void *));
|
||||
|
||||
ir_ref if_internal_func_end = ir_END();
|
||||
ir_IF_FALSE(if_internal_func);
|
||||
|
||||
ir_ref observer_handler_user = ir_ADD_OFFSET(run_time_cache, zend_observer_fcall_op_array_extension * sizeof(void *));
|
||||
|
||||
ir_MERGE_WITH(if_internal_func_end);
|
||||
*observer_handler = ir_PHI_2(IR_ADDR, observer_handler_internal, observer_handler_user);
|
||||
}
|
||||
|
||||
// JIT: if (*observer_handler == ZEND_OBSERVER_NONE_OBSERVED) {
|
||||
data.if_unobserved = ir_IF(ir_EQ(ir_LOAD_A(*observer_handler), ir_CONST_ADDR(ZEND_OBSERVER_NONE_OBSERVED)));
|
||||
ir_IF_FALSE(data.if_unobserved);
|
||||
return data;
|
||||
}
|
||||
|
||||
/* For frameless the true branch of if_unobserved is used and this function not called. */
|
||||
static void jit_observer_fcall_is_unobserved_end(zend_jit_ctx *jit, struct jit_observer_fcall_is_unobserved_data *data) {
|
||||
ir_END_list(data->ir_end_inputs);
|
||||
ir_IF_TRUE(data->if_unobserved);
|
||||
ir_END_list(data->ir_end_inputs);
|
||||
ir_MERGE_list(data->ir_end_inputs);
|
||||
}
|
||||
|
||||
static void jit_observer_fcall_begin(zend_jit_ctx *jit, ir_ref rx, ir_ref observer_handler) {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin_prechecked), rx, observer_handler);
|
||||
}
|
||||
|
||||
static void jit_observer_fcall_end(zend_jit_ctx *jit, ir_ref rx, ir_ref res_ref) {
|
||||
// JIT: if (execute_data == EG(current_observed_frame)) {
|
||||
ir_ref has_end_observer = ir_IF(ir_EQ(rx, ir_LOAD_A(jit_EG(current_observed_frame))));
|
||||
ir_IF_TRUE(has_end_observer);
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end_prechecked),
|
||||
rx, res_ref);
|
||||
ir_MERGE_WITH_EMPTY_FALSE(has_end_observer);
|
||||
}
|
||||
|
||||
static int zend_jit_inc_dec(zend_jit_ctx *jit, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw)
|
||||
{
|
||||
ir_ref if_long = IR_UNUSED;
|
||||
@ -9951,7 +10047,10 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
ir_MERGE_WITH_EMPTY_FALSE(if_need);
|
||||
}
|
||||
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
|
||||
ir_ref observer_handler;
|
||||
ir_ref rx = jit_FP(jit);
|
||||
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
|
||||
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) {
|
||||
ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
|
||||
jit_SET_EX_OPLINE(jit, trace[1].opline);
|
||||
@ -9959,7 +10058,8 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
// EX(opline) = opline
|
||||
ir_STORE(jit_EX(opline), jit_IP(jit));
|
||||
}
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin), jit_FP(jit));
|
||||
jit_observer_fcall_begin(jit, rx, observer_handler);
|
||||
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
|
||||
}
|
||||
|
||||
if (trace) {
|
||||
@ -10086,8 +10186,12 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
// JIT: EG(current_execute_data) = execute_data;
|
||||
ir_STORE(jit_EG(current_execute_data), rx);
|
||||
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_begin), rx);
|
||||
bool may_have_observer = ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0);
|
||||
if (may_have_observer) {
|
||||
ir_ref observer_handler;
|
||||
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)));
|
||||
jit_observer_fcall_begin(jit, rx, observer_handler);
|
||||
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
|
||||
}
|
||||
|
||||
// JIT: ZVAL_NULL(EX_VAR(opline->result.var));
|
||||
@ -10113,8 +10217,9 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
zend_jit_reset_last_valid_opline(jit);
|
||||
|
||||
// JIT: (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret);
|
||||
ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
|
||||
if (zend_execute_internal) {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, jit_ZVAL_ADDR(jit, res_addr));
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_execute_internal), rx, res_ref);
|
||||
} else {
|
||||
if (func) {
|
||||
func_ptr = ir_CONST_FC_FUNC(func->internal_function.handler);
|
||||
@ -10124,12 +10229,11 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
func_ptr = ir_CAST_FC_FUNC(func_ptr);
|
||||
#endif
|
||||
}
|
||||
ir_CALL_2(IR_VOID, func_ptr, rx, jit_ZVAL_ADDR(jit, res_addr));
|
||||
ir_CALL_2(IR_VOID, func_ptr, rx, res_ref);
|
||||
}
|
||||
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end),
|
||||
rx, jit_ZVAL_ADDR(jit, res_addr));
|
||||
if (may_have_observer) {
|
||||
jit_observer_fcall_end(jit, rx, res_ref);
|
||||
}
|
||||
|
||||
// JIT: EG(current_execute_data) = execute_data;
|
||||
@ -10841,9 +10945,7 @@ static int zend_jit_return(zend_jit_ctx *jit, const zend_op *opline, const zend_
|
||||
}
|
||||
op1_addr = dst;
|
||||
}
|
||||
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_observer_fcall_end),
|
||||
jit_FP(jit),
|
||||
jit_ZVAL_ADDR(jit, op1_addr));
|
||||
jit_observer_fcall_end(jit, jit_FP(jit), jit_ZVAL_ADDR(jit, op1_addr));
|
||||
}
|
||||
|
||||
// JIT: if (!EX(return_value))
|
||||
@ -16994,6 +17096,21 @@ static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ir_ref jit_frameless_observer(zend_jit_ctx *jit, const zend_op *opline) {
|
||||
// JIT: zend_observer_handler_is_unobserved(ZEND_OBSERVER_DATA(fbc))
|
||||
ir_ref observer_handler;
|
||||
zend_function *fbc = ZEND_FLF_FUNC(opline);
|
||||
// Not need for runtime cache or generator checks here, we just need if_unobserved
|
||||
ir_ref if_unobserved = jit_observer_fcall_is_unobserved_start(jit, fbc, &observer_handler, IR_UNUSED, IR_UNUSED).if_unobserved;
|
||||
|
||||
// Call zend_frameless_observed_call for the main logic.
|
||||
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)zend_frameless_observed_call), jit_FP(jit));
|
||||
|
||||
ir_ref skip = ir_END();
|
||||
ir_IF_TRUE(if_unobserved);
|
||||
return skip;
|
||||
}
|
||||
|
||||
static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
|
||||
{
|
||||
jit_SET_EX_OPLINE(jit, opline);
|
||||
@ -17002,7 +17119,18 @@ static void jit_frameless_icall0(zend_jit_ctx *jit, const zend_op *opline)
|
||||
zend_jit_addr res_addr = RES_ADDR();
|
||||
ir_ref res_ref = jit_ZVAL_ADDR(jit, res_addr);
|
||||
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
|
||||
|
||||
ir_ref skip_observer = IR_UNUSED;
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
skip_observer = jit_frameless_observer(jit, opline);
|
||||
}
|
||||
|
||||
ir_CALL_1(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref);
|
||||
|
||||
if (skip_observer != IR_UNUSED) {
|
||||
ir_MERGE_WITH(skip_observer);
|
||||
}
|
||||
|
||||
zend_jit_check_exception(jit);
|
||||
}
|
||||
|
||||
@ -17027,7 +17155,18 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint3
|
||||
if (op1_info & MAY_BE_REF) {
|
||||
op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
|
||||
}
|
||||
|
||||
ir_ref skip_observer = IR_UNUSED;
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
skip_observer = jit_frameless_observer(jit, opline);
|
||||
}
|
||||
|
||||
ir_CALL_2(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref);
|
||||
|
||||
if (skip_observer != IR_UNUSED) {
|
||||
ir_MERGE_WITH(skip_observer);
|
||||
}
|
||||
|
||||
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
|
||||
zend_jit_check_exception(jit);
|
||||
}
|
||||
@ -17064,7 +17203,18 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3
|
||||
if (op2_info & MAY_BE_REF) {
|
||||
op2_ref = jit_ZVAL_DEREF_ref(jit, op2_ref);
|
||||
}
|
||||
|
||||
ir_ref skip_observer = IR_UNUSED;
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
skip_observer = jit_frameless_observer(jit, opline);
|
||||
}
|
||||
|
||||
ir_CALL_3(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref);
|
||||
|
||||
if (skip_observer != IR_UNUSED) {
|
||||
ir_MERGE_WITH(skip_observer);
|
||||
}
|
||||
|
||||
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
|
||||
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
|
||||
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0) {
|
||||
@ -17118,7 +17268,18 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3
|
||||
if (op1_data_info & MAY_BE_REF) {
|
||||
op3_ref = jit_ZVAL_DEREF_ref(jit, op3_ref);
|
||||
}
|
||||
|
||||
ir_ref skip_observer = IR_UNUSED;
|
||||
if (ZEND_OBSERVER_ENABLED) {
|
||||
skip_observer = jit_frameless_observer(jit, opline);
|
||||
}
|
||||
|
||||
ir_CALL_4(IR_VOID, ir_CONST_ADDR((size_t)function), res_ref, op1_ref, op2_ref, op3_ref);
|
||||
|
||||
if (skip_observer != IR_UNUSED) {
|
||||
ir_MERGE_WITH(skip_observer);
|
||||
}
|
||||
|
||||
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, NULL);
|
||||
/* Set OP1 to UNDEF in case FREE_OP2() throws. */
|
||||
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
|
||||
|
@ -1,5 +1,5 @@
|
||||
--TEST--
|
||||
Bug #81435 (Observer current_observed_frame may point to an old (overwritten) frame)
|
||||
Bug #81435 (Observer EG(current_observed_frame) may point to an old (overwritten) frame)
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
|
@ -1,5 +1,5 @@
|
||||
--TEST--
|
||||
Observer: Frameless calls are disabled when there are observers
|
||||
Observer: Frameless calls are properly observable
|
||||
--EXTENSIONS--
|
||||
zend_test
|
||||
--INI--
|
||||
@ -10,9 +10,13 @@ zend_test.observer.show_output=1
|
||||
function _strpos(string $str) {
|
||||
return \strpos($str, 'o', 1);
|
||||
}
|
||||
_strpos('foo');
|
||||
var_dump(_strpos('foo'));
|
||||
var_dump(_strpos('foo')); // second time, with no observers detected
|
||||
?>
|
||||
--EXPECTF--
|
||||
<!-- init '%s' -->
|
||||
<!-- init _strpos() -->
|
||||
<!-- init strpos() -->
|
||||
<!-- init var_dump() -->
|
||||
int(1)
|
||||
int(1)
|
||||
|
10
main/main.c
10
main/main.c
@ -2108,6 +2108,11 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
|
||||
#endif
|
||||
gc_globals_ctor();
|
||||
|
||||
zend_observer_startup();
|
||||
#if ZEND_DEBUG
|
||||
zend_observer_error_register(report_zend_debug_error_notify_cb);
|
||||
#endif
|
||||
|
||||
zuf.error_function = php_error_cb;
|
||||
zuf.printf_function = php_printf;
|
||||
zuf.write_function = php_output_write;
|
||||
@ -2127,11 +2132,6 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi
|
||||
zend_reset_lc_ctype_locale();
|
||||
zend_update_current_locale();
|
||||
|
||||
zend_observer_startup();
|
||||
#if ZEND_DEBUG
|
||||
zend_observer_error_register(report_zend_debug_error_notify_cb);
|
||||
#endif
|
||||
|
||||
#if HAVE_TZSET
|
||||
tzset();
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user