Include internal functions in the observer API

There are two main motivations to this:
a) The logic for handling internal and userland observation can be unified.
b) Unwinding of observed functions on a bailout does notably not include observers. Even if users of observers were to ensure such handling themselves, it would be impossible to retain the relative ordering - either the user has to unwind all internal observed frames before the automatic unwinding (zend_observer_fcall_end_all) or afterwards, but not properly interleaved.

Signed-off-by: Bob Weinand <bobwei9@hotmail.com>
This commit is contained in:
Bob Weinand 2022-07-20 15:50:12 +02:00
parent 0c225a2f57
commit 625f164963
49 changed files with 1675 additions and 1257 deletions

View file

@ -51,6 +51,7 @@ PHP 8.2 INTERNALS UPGRADE NOTES
are deprecated (see main UPGRADING notes). To suppress the notice, e.g. to are deprecated (see main UPGRADING notes). To suppress the notice, e.g. to
avoid duplicates when processing the same value multiple times, pass or add avoid duplicates when processing the same value multiple times, pass or add
IS_CALLABLE_SUPPRESS_DEPRECATIONS to the check_flags parameter. IS_CALLABLE_SUPPRESS_DEPRECATIONS to the check_flags parameter.
* Registered zend_observer_fcall_init handlers are now also called for internal functions.
======================== ========================
2. Build system changes 2. Build system changes

View file

@ -1226,6 +1226,7 @@ ZEND_API void zend_activate(void) /* {{{ */
if (CG(map_ptr_last)) { if (CG(map_ptr_last)) {
memset(CG(map_ptr_real_base), 0, CG(map_ptr_last) * sizeof(void*)); memset(CG(map_ptr_real_base), 0, CG(map_ptr_last) * sizeof(void*));
} }
zend_init_internal_run_time_cache();
zend_observer_activate(); zend_observer_activate();
} }
/* }}} */ /* }}} */

View file

@ -2694,6 +2694,11 @@ ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend
internal_function->scope = scope; internal_function->scope = scope;
internal_function->prototype = NULL; internal_function->prototype = NULL;
internal_function->attributes = NULL; internal_function->attributes = NULL;
if (EG(active)) { // at run-time: this ought to only happen if registered with dl() or somehow temporarily at runtime
ZEND_MAP_PTR_INIT(internal_function->run_time_cache, zend_arena_alloc(&CG(arena), zend_internal_run_time_cache_reserved_size()));
} else {
ZEND_MAP_PTR_NEW(internal_function->run_time_cache);
}
if (ptr->flags) { if (ptr->flags) {
if (!(ptr->flags & ZEND_ACC_PPP_MASK)) { if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
if (ptr->flags != ZEND_ACC_DEPRECATED && scope) { if (ptr->flags != ZEND_ACC_DEPRECATED && scope) {

View file

@ -33,6 +33,7 @@
#include "zend_inheritance.h" #include "zend_inheritance.h"
#include "zend_vm.h" #include "zend_vm.h"
#include "zend_enum.h" #include "zend_enum.h"
#include "zend_observer.h"
#define SET_NODE(target, src) do { \ #define SET_NODE(target, src) do { \
target ## _type = (src)->op_type; \ target ## _type = (src)->op_type; \

View file

@ -448,6 +448,7 @@ struct _zend_op_array {
uint32_t required_num_args; uint32_t required_num_args;
zend_arg_info *arg_info; zend_arg_info *arg_info;
HashTable *attributes; HashTable *attributes;
ZEND_MAP_PTR_DEF(void **, run_time_cache);
/* END of common elements */ /* END of common elements */
int cache_size; /* number of run_time_cache_slots * sizeof(void*) */ int cache_size; /* number of run_time_cache_slots * sizeof(void*) */
@ -456,7 +457,6 @@ struct _zend_op_array {
uint32_t last; /* number of opcodes */ uint32_t last; /* number of opcodes */
zend_op *opcodes; zend_op *opcodes;
ZEND_MAP_PTR_DEF(void **, run_time_cache);
ZEND_MAP_PTR_DEF(HashTable *, static_variables_ptr); ZEND_MAP_PTR_DEF(HashTable *, static_variables_ptr);
HashTable *static_variables; HashTable *static_variables;
zend_string **vars; /* names of CV variables */ zend_string **vars; /* names of CV variables */
@ -503,6 +503,7 @@ typedef struct _zend_internal_function {
uint32_t required_num_args; uint32_t required_num_args;
zend_internal_arg_info *arg_info; zend_internal_arg_info *arg_info;
HashTable *attributes; HashTable *attributes;
ZEND_MAP_PTR_DEF(void **, run_time_cache);
/* END of common elements */ /* END of common elements */
zif_handler handler; zif_handler handler;
@ -527,6 +528,7 @@ union _zend_function {
uint32_t required_num_args; uint32_t required_num_args;
zend_arg_info *arg_info; /* index -1 represents the return value info, if any */ zend_arg_info *arg_info; /* index -1 represents the return value info, if any */
HashTable *attributes; HashTable *attributes;
ZEND_MAP_PTR_DEF(void **, run_time_cache);
} common; } common;
zend_op_array op_array; zend_op_array op_array;

View file

@ -22,6 +22,7 @@
#include "zend_enum_arginfo.h" #include "zend_enum_arginfo.h"
#include "zend_interfaces.h" #include "zend_interfaces.h"
#include "zend_enum.h" #include "zend_enum.h"
#include "zend_extensions.h"
#define ZEND_ENUM_DISALLOW_MAGIC_METHOD(propertyName, methodName) \ #define ZEND_ENUM_DISALLOW_MAGIC_METHOD(propertyName, methodName) \
do { \ do { \
@ -401,59 +402,48 @@ static ZEND_NAMED_FUNCTION(zend_enum_try_from_func)
zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); zend_enum_from_base(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
} }
static void zend_enum_register_func(zend_class_entry *ce, zend_known_string_id name_id, zend_internal_function *zif) {
zend_string *name = ZSTR_KNOWN(name_id);
zif->type = ZEND_INTERNAL_FUNCTION;
zif->module = EG(current_module);
zif->scope = ce;
ZEND_MAP_PTR_NEW(zif->run_time_cache);
ZEND_MAP_PTR_SET(zif->run_time_cache, zend_arena_alloc(&CG(arena), zend_internal_run_time_cache_reserved_size()));
if (!zend_hash_add_ptr(&ce->function_table, name, zif)) {
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::%s()", ZSTR_VAL(ce->name), ZSTR_VAL(name));
}
}
void zend_enum_register_funcs(zend_class_entry *ce) void zend_enum_register_funcs(zend_class_entry *ce)
{ {
const uint32_t fn_flags = const uint32_t fn_flags =
ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_ARENA_ALLOCATED; ZEND_ACC_PUBLIC|ZEND_ACC_STATIC|ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_ARENA_ALLOCATED;
zend_internal_function *cases_function = zend_internal_function *cases_function = zend_arena_calloc(&CG(arena), sizeof(zend_internal_function), 1);
zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
memset(cases_function, 0, sizeof(zend_internal_function));
cases_function->type = ZEND_INTERNAL_FUNCTION;
cases_function->module = EG(current_module);
cases_function->handler = zend_enum_cases_func; cases_function->handler = zend_enum_cases_func;
cases_function->function_name = ZSTR_KNOWN(ZEND_STR_CASES); cases_function->function_name = ZSTR_KNOWN(ZEND_STR_CASES);
cases_function->scope = ce;
cases_function->fn_flags = fn_flags; cases_function->fn_flags = fn_flags;
cases_function->arg_info = (zend_internal_arg_info *) (arginfo_class_UnitEnum_cases + 1); cases_function->arg_info = (zend_internal_arg_info *) (arginfo_class_UnitEnum_cases + 1);
if (!zend_hash_add_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_CASES), cases_function)) { zend_enum_register_func(ce, ZEND_STR_CASES, cases_function);
zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s::cases()", ZSTR_VAL(ce->name));
}
if (ce->enum_backing_type != IS_UNDEF) { if (ce->enum_backing_type != IS_UNDEF) {
zend_internal_function *from_function = zend_internal_function *from_function = zend_arena_calloc(&CG(arena), sizeof(zend_internal_function), 1);
zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
memset(from_function, 0, sizeof(zend_internal_function));
from_function->type = ZEND_INTERNAL_FUNCTION;
from_function->module = EG(current_module);
from_function->handler = zend_enum_from_func; from_function->handler = zend_enum_from_func;
from_function->function_name = ZSTR_KNOWN(ZEND_STR_FROM); from_function->function_name = ZSTR_KNOWN(ZEND_STR_FROM);
from_function->scope = ce;
from_function->fn_flags = fn_flags; from_function->fn_flags = fn_flags;
from_function->num_args = 1; from_function->num_args = 1;
from_function->required_num_args = 1; from_function->required_num_args = 1;
from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_from + 1); from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_from + 1);
if (!zend_hash_add_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_FROM), from_function)) { zend_enum_register_func(ce, ZEND_STR_FROM, from_function);
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot redeclare %s::from()", ZSTR_VAL(ce->name));
}
zend_internal_function *try_from_function = zend_internal_function *try_from_function = zend_arena_calloc(&CG(arena), sizeof(zend_internal_function), 1);
zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
memset(try_from_function, 0, sizeof(zend_internal_function));
try_from_function->type = ZEND_INTERNAL_FUNCTION;
try_from_function->module = EG(current_module);
try_from_function->handler = zend_enum_try_from_func; try_from_function->handler = zend_enum_try_from_func;
try_from_function->function_name = ZSTR_KNOWN(ZEND_STR_TRYFROM); try_from_function->function_name = ZSTR_KNOWN(ZEND_STR_TRYFROM);
try_from_function->scope = ce;
try_from_function->fn_flags = fn_flags; try_from_function->fn_flags = fn_flags;
try_from_function->num_args = 1; try_from_function->num_args = 1;
try_from_function->required_num_args = 1; try_from_function->required_num_args = 1;
try_from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_tryFrom + 1); try_from_function->arg_info = (zend_internal_arg_info *) (arginfo_class_BackedEnum_tryFrom + 1);
if (!zend_hash_add_ptr( zend_enum_register_func(ce, ZEND_STR_TRYFROM_LOWERCASE, try_from_function);
&ce->function_table, ZSTR_KNOWN(ZEND_STR_TRYFROM_LOWERCASE), try_from_function)) {
zend_error_noreturn(E_COMPILE_ERROR,
"Cannot redeclare %s::tryFrom()", ZSTR_VAL(ce->name));
}
} }
} }

View file

@ -144,6 +144,7 @@ ZEND_API const zend_internal_function zend_pass_function = {
0, /* required_num_args */ 0, /* required_num_args */
(zend_internal_arg_info *) zend_pass_function_arg_info + 1, /* arg_info */ (zend_internal_arg_info *) zend_pass_function_arg_info + 1, /* arg_info */
NULL, /* attributes */ NULL, /* attributes */
NULL, /* run_time_cache */
ZEND_FN(pass), /* handler */ ZEND_FN(pass), /* handler */
NULL, /* module */ NULL, /* module */
{NULL,NULL,NULL,NULL} /* reserved */ {NULL,NULL,NULL,NULL} /* reserved */

View file

@ -935,6 +935,7 @@ cleanup_args:
#if ZEND_DEBUG #if ZEND_DEBUG
bool should_throw = zend_internal_call_should_throw(func, call); bool should_throw = zend_internal_call_should_throw(func, call);
#endif #endif
ZEND_OBSERVER_FCALL_BEGIN(call);
if (EXPECTED(zend_execute_internal == NULL)) { if (EXPECTED(zend_execute_internal == NULL)) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
func->internal_function.handler(call, fci->retval); func->internal_function.handler(call, fci->retval);
@ -953,6 +954,7 @@ cleanup_args:
? Z_ISREF_P(fci->retval) : !Z_ISREF_P(fci->retval)); ? Z_ISREF_P(fci->retval) : !Z_ISREF_P(fci->retval));
} }
#endif #endif
ZEND_OBSERVER_FCALL_END(call, fci->retval);
EG(current_execute_data) = call->prev_execute_data; EG(current_execute_data) = call->prev_execute_data;
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) { if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS)) {

View file

@ -280,6 +280,40 @@ ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int ha
return handle; return handle;
} }
ZEND_API size_t zend_internal_run_time_cache_reserved_size() {
return zend_op_array_extension_handles * sizeof(void *);
}
ZEND_API void zend_init_internal_run_time_cache() {
size_t rt_size = zend_internal_run_time_cache_reserved_size();
if (rt_size) {
size_t functions = zend_hash_num_elements(CG(function_table));
zend_class_entry *ce;
ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
functions += zend_hash_num_elements(&ce->function_table);
} ZEND_HASH_FOREACH_END();
char *ptr = zend_arena_calloc(&CG(arena), functions, rt_size);
zend_internal_function *zif;
ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
if (!ZEND_USER_CODE(zif->type) && ZEND_MAP_PTR_GET(zif->run_time_cache) == NULL)
{
ZEND_MAP_PTR_SET(zif->run_time_cache, (void *)ptr);
ptr += rt_size;
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zif) {
if (!ZEND_USER_CODE(zif->type) && ZEND_MAP_PTR_GET(zif->run_time_cache) == NULL)
{
ZEND_MAP_PTR_SET(zif->run_time_cache, (void *)ptr);
ptr += rt_size;
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
}
ZEND_API zend_extension *zend_get_extension(const char *extension_name) ZEND_API zend_extension *zend_get_extension(const char *extension_name)
{ {
zend_llist_element *element; zend_llist_element *element;

View file

@ -145,6 +145,9 @@ void zend_startup_extensions_mechanism(void);
void zend_startup_extensions(void); void zend_startup_extensions(void);
void zend_shutdown_extensions(void); void zend_shutdown_extensions(void);
ZEND_API size_t zend_internal_run_time_cache_reserved_size(void);
ZEND_API void zend_init_internal_run_time_cache(void);
BEGIN_EXTERN_C() BEGIN_EXTERN_C()
ZEND_API zend_result zend_load_extension(const char *path); ZEND_API zend_result zend_load_extension(const char *path);
ZEND_API zend_result zend_load_extension_handle(DL_HANDLE handle, const char *path); ZEND_API zend_result zend_load_extension_handle(DL_HANDLE handle, const char *path);

View file

@ -23,13 +23,13 @@
#include "zend_llist.h" #include "zend_llist.h"
#include "zend_vm.h" #include "zend_vm.h"
#define ZEND_OBSERVER_DATA(op_array) \ #define ZEND_OBSERVER_DATA(function) \
ZEND_OP_ARRAY_EXTENSION(op_array, zend_observer_fcall_op_array_extension) ZEND_OP_ARRAY_EXTENSION((&(function)->common), zend_observer_fcall_op_array_extension)
#define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2) #define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2)
#define ZEND_OBSERVABLE_FN(fn_flags) \ #define ZEND_OBSERVABLE_FN(function) \
(!(fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) (ZEND_MAP_PTR(function->common.run_time_cache) && !(function->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
zend_llist zend_observers_fcall_list; zend_llist zend_observers_fcall_list;
zend_llist zend_observer_error_callbacks; zend_llist zend_observer_error_callbacks;
@ -100,12 +100,9 @@ static void zend_observer_fcall_install(zend_execute_data *execute_data)
{ {
zend_llist *list = &zend_observers_fcall_list; zend_llist *list = &zend_observers_fcall_list;
zend_function *function = execute_data->func; zend_function *function = execute_data->func;
zend_op_array *op_array = &function->op_array;
ZEND_ASSERT(function->type != ZEND_INTERNAL_FUNCTION); ZEND_ASSERT(RUN_TIME_CACHE(&function->common));
zend_observer_fcall_begin_handler *begin_handlers = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(function);
ZEND_ASSERT(RUN_TIME_CACHE(op_array));
zend_observer_fcall_begin_handler *begin_handlers = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(op_array);
zend_observer_fcall_end_handler *end_handlers = (zend_observer_fcall_end_handler *)begin_handlers + list->count, *end_handlers_start = end_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; *begin_handlers = ZEND_OBSERVER_NOT_OBSERVED;
@ -152,9 +149,9 @@ static bool zend_observer_remove_handler(void **first_handler, void *old_handler
return false; return false;
} }
ZEND_API void zend_observer_add_begin_handler(zend_op_array *op_array, zend_observer_fcall_begin_handler begin) { 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; size_t registered_observers = zend_observers_fcall_list.count;
zend_observer_fcall_begin_handler *first_handler = (void *)&ZEND_OBSERVER_DATA(op_array), *last_handler = first_handler + registered_observers - 1; 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) { if (*first_handler == ZEND_OBSERVER_NOT_OBSERVED) {
*first_handler = begin; *first_handler = begin;
} else { } else {
@ -169,13 +166,13 @@ ZEND_API void zend_observer_add_begin_handler(zend_op_array *op_array, zend_obse
} }
} }
ZEND_API bool zend_observer_remove_begin_handler(zend_op_array *op_array, zend_observer_fcall_begin_handler begin) { ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin) {
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(op_array), begin); return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function), begin);
} }
ZEND_API void zend_observer_add_end_handler(zend_op_array *op_array, zend_observer_fcall_end_handler end) { 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; size_t registered_observers = zend_observers_fcall_list.count;
zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(op_array) + registered_observers; zend_observer_fcall_end_handler *end_handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(function) + 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 // 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) { if (*end_handler != ZEND_OBSERVER_NOT_OBSERVED) {
// there's no space for new handlers, then it's forbidden to call this function // there's no space for new handlers, then it's forbidden to call this function
@ -185,9 +182,9 @@ ZEND_API void zend_observer_add_end_handler(zend_op_array *op_array, zend_observ
*end_handler = end; *end_handler = end;
} }
ZEND_API bool zend_observer_remove_end_handler(zend_op_array *op_array, zend_observer_fcall_end_handler end) { ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end) {
size_t registered_observers = zend_observers_fcall_list.count; size_t registered_observers = zend_observers_fcall_list.count;
return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(op_array) + registered_observers, end); return zend_observer_remove_handler((void **)&ZEND_OBSERVER_DATA(function) + registered_observers, end);
} }
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)
@ -196,14 +193,13 @@ static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_d
return; return;
} }
zend_op_array *op_array = &execute_data->func->op_array; zend_function *function = execute_data->func;
uint32_t fn_flags = op_array->fn_flags;
if (!ZEND_OBSERVABLE_FN(fn_flags)) { if (!ZEND_OBSERVABLE_FN(function)) {
return; return;
} }
zend_observer_fcall_begin_handler *handler = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(op_array); zend_observer_fcall_begin_handler *handler = (zend_observer_fcall_begin_handler *)&ZEND_OBSERVER_DATA(function);
if (!*handler) { if (!*handler) {
zend_observer_fcall_install(execute_data); zend_observer_fcall_install(execute_data);
} }
@ -243,11 +239,11 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute
static inline bool zend_observer_is_skipped_frame(zend_execute_data *execute_data) { static inline bool zend_observer_is_skipped_frame(zend_execute_data *execute_data) {
zend_function *func = execute_data->func; zend_function *func = execute_data->func;
if (!func || func->type == ZEND_INTERNAL_FUNCTION || !ZEND_OBSERVABLE_FN(func->common.fn_flags)) { if (!func || !ZEND_OBSERVABLE_FN(func)) {
return true; return true;
} }
zend_observer_fcall_end_handler end_handler = (&ZEND_OBSERVER_DATA(&func->op_array))[zend_observers_fcall_list.count]; zend_observer_fcall_end_handler end_handler = (&ZEND_OBSERVER_DATA(func))[zend_observers_fcall_list.count];
if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED) { if (end_handler == NULL || end_handler == ZEND_OBSERVER_NOT_OBSERVED) {
return true; return true;
} }
@ -259,11 +255,11 @@ ZEND_API void ZEND_FASTCALL zend_observer_fcall_end(zend_execute_data *execute_d
{ {
zend_function *func = execute_data->func; zend_function *func = execute_data->func;
if (!ZEND_OBSERVER_ENABLED || !ZEND_OBSERVABLE_FN(func->common.fn_flags)) { if (!ZEND_OBSERVER_ENABLED || !ZEND_OBSERVABLE_FN(func)) {
return; return;
} }
zend_observer_fcall_end_handler *handler = (zend_observer_fcall_end_handler *)&ZEND_OBSERVER_DATA(&func->op_array) + 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 // TODO: Fix exceptions from generators
// ZEND_ASSERT(fcall_data); // ZEND_ASSERT(fcall_data);
if (!*handler || *handler == ZEND_OBSERVER_NOT_OBSERVED) { if (!*handler || *handler == ZEND_OBSERVER_NOT_OBSERVED) {
@ -291,7 +287,7 @@ ZEND_API void zend_observer_fcall_end_all(void)
{ {
zend_execute_data *ex = current_observed_frame; zend_execute_data *ex = current_observed_frame;
while (ex != NULL) { while (ex != NULL) {
if (ex->func && ex->func->type != ZEND_INTERNAL_FUNCTION) { if (ex->func) {
zend_observer_fcall_end(ex, NULL); zend_observer_fcall_end(ex, NULL);
} }
ex = ex->prev_execute_data; ex = ex->prev_execute_data;

View file

@ -58,10 +58,10 @@ ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init);
// Call during runtime, but only if you have used zend_observer_fcall_register. // Call during runtime, but only if you have used zend_observer_fcall_register.
// You must not have more than one begin and one end handler active at the same time. Remove the old one first, if there is an existing one. // You must not have more than one begin and one end handler active at the same time. Remove the old one first, if there is an existing one.
ZEND_API void zend_observer_add_begin_handler(zend_op_array *op_array, zend_observer_fcall_begin_handler begin); ZEND_API void zend_observer_add_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin);
ZEND_API bool zend_observer_remove_begin_handler(zend_op_array *op_array, zend_observer_fcall_begin_handler begin); ZEND_API bool zend_observer_remove_begin_handler(zend_function *function, zend_observer_fcall_begin_handler begin);
ZEND_API void zend_observer_add_end_handler(zend_op_array *op_array, zend_observer_fcall_end_handler end); ZEND_API void zend_observer_add_end_handler(zend_function *function, zend_observer_fcall_end_handler end);
ZEND_API bool zend_observer_remove_end_handler(zend_op_array *op_array, zend_observer_fcall_end_handler end); ZEND_API bool zend_observer_remove_end_handler(zend_function *function, zend_observer_fcall_end_handler end);
ZEND_API void zend_observer_startup(void); // Called by engine before MINITs ZEND_API void zend_observer_startup(void); // Called by engine before MINITs
ZEND_API void zend_observer_post_startup(void); // Called by engine after MINITs ZEND_API void zend_observer_post_startup(void); // Called by engine after MINITs

View file

@ -3908,7 +3908,7 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT)
ZEND_VM_NEXT_OPCODE(); ZEND_VM_NEXT_OPCODE();
} }
ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
{ {
USE_OPLINE USE_OPLINE
zend_execute_data *call = EX(call); zend_execute_data *call = EX(call);
@ -3929,6 +3929,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret); ZVAL_NULL(ret);
ZEND_OBSERVER_FCALL_BEGIN(call);
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
#if ZEND_DEBUG #if ZEND_DEBUG
@ -3943,6 +3944,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
zend_vm_stack_free_args(call); zend_vm_stack_free_args(call);
@ -4048,6 +4050,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret); ZVAL_NULL(ret);
ZEND_OBSERVER_FCALL_BEGIN(call);
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
#if ZEND_DEBUG #if ZEND_DEBUG
@ -4062,6 +4065,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
@ -4153,6 +4157,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret); ZVAL_NULL(ret);
ZEND_OBSERVER_FCALL_BEGIN(call);
if (!zend_execute_internal) { if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
@ -4172,6 +4177,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
@ -8710,6 +8716,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER))
} }
ZVAL_NULL(ret); ZVAL_NULL(ret);
ZEND_OBSERVER_FCALL_BEGIN(call);
if (!zend_execute_internal) { if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
@ -8729,6 +8736,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER))
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = call->prev_execute_data; EG(current_execute_data) = call->prev_execute_data;

391
Zend/zend_vm_execute.h generated
View file

@ -1350,6 +1350,70 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
ZEND_VM_CONTINUE(); ZEND_VM_CONTINUE();
} }
static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_execute_data *call = EX(call);
zend_function *fbc = call->func;
zval *ret;
zval retval;
SAVE_OPLINE();
EX(call) = call->prev_execute_data;
call->prev_execute_data = execute_data;
EG(current_execute_data) = call;
#if ZEND_DEBUG
bool should_throw = zend_internal_call_should_throw(fbc, call);
#endif
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret);
zend_observer_fcall_begin(call);
fbc->internal_function.handler(call, ret);
#if ZEND_DEBUG
if (!EG(exception) && call->func) {
if (should_throw) {
zend_internal_call_arginfo_violation(call->func);
}
ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data;
zend_vm_stack_free_args(call);
uint32_t call_info = ZEND_CALL_INFO(call);
if (UNEXPECTED(call_info & (ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_ALLOCATED))) {
if (call_info & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
zend_free_extra_named_params(call->extra_named_params);
}
zend_vm_stack_free_call_frame_ex(call_info, call);
} else {
EG(vm_stack_top) = (zval*)call;
}
if (!RETURN_VALUE_USED(opline)) {
i_zval_ptr_dtor(ret);
}
if (UNEXPECTED(EG(exception) != NULL)) {
zend_rethrow_exception(execute_data);
HANDLE_EXCEPTION();
}
ZEND_VM_SET_OPCODE(opline + 1);
ZEND_VM_CONTINUE();
}
static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{ {
USE_OPLINE USE_OPLINE
@ -1666,6 +1730,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; ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret); ZVAL_NULL(ret);
zend_observer_fcall_begin(call);
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
#if ZEND_DEBUG #if ZEND_DEBUG
@ -1680,6 +1745,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
@ -1989,6 +2055,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; ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
ZVAL_NULL(ret); ZVAL_NULL(ret);
zend_observer_fcall_begin(call);
if (!zend_execute_internal) { if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
@ -2008,6 +2075,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = execute_data; EG(current_execute_data) = execute_data;
@ -3342,6 +3410,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
} }
ZVAL_NULL(ret); ZVAL_NULL(ret);
if (!zend_execute_internal) { if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
@ -3479,6 +3548,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_
} }
ZVAL_NULL(ret); ZVAL_NULL(ret);
zend_observer_fcall_begin(call);
if (!zend_execute_internal) { if (!zend_execute_internal) {
/* saves one function call if zend_execute_internal is not used */ /* saves one function call if zend_execute_internal is not used */
fbc->internal_function.handler(call, ret); fbc->internal_function.handler(call, ret);
@ -3498,6 +3568,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_
zend_verify_internal_func_info(call->func, ret); zend_verify_internal_func_info(call->func, ret);
} }
#endif #endif
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
EG(current_execute_data) = call->prev_execute_data; EG(current_execute_data) = call->prev_execute_data;
@ -54397,6 +54468,8 @@ ZEND_API void execute_ex(zend_execute_data *ex)
(void*)&&ZEND_INIT_DYNAMIC_CALL_SPEC_CV_LABEL, (void*)&&ZEND_INIT_DYNAMIC_CALL_SPEC_CV_LABEL,
(void*)&&ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_LABEL, (void*)&&ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_LABEL,
(void*)&&ZEND_DO_ICALL_SPEC_RETVAL_USED_LABEL, (void*)&&ZEND_DO_ICALL_SPEC_RETVAL_USED_LABEL,
(void*)&&ZEND_DO_ICALL_SPEC_OBSERVER_LABEL,
(void*)&&ZEND_DO_ICALL_SPEC_OBSERVER_LABEL,
(void*)&&ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL, (void*)&&ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL,
(void*)&&ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL, (void*)&&ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL,
(void*)&&ZEND_DO_UCALL_SPEC_OBSERVER_LABEL, (void*)&&ZEND_DO_UCALL_SPEC_OBSERVER_LABEL,
@ -55897,6 +55970,10 @@ zend_leave_helper_SPEC_LABEL:
VM_TRACE(ZEND_DO_ICALL_SPEC_RETVAL_USED) VM_TRACE(ZEND_DO_ICALL_SPEC_RETVAL_USED)
ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK(); HYBRID_BREAK();
HYBRID_CASE(ZEND_DO_ICALL_SPEC_OBSERVER):
VM_TRACE(ZEND_DO_ICALL_SPEC_OBSERVER)
ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
HYBRID_BREAK();
HYBRID_CASE(ZEND_DO_UCALL_SPEC_RETVAL_UNUSED): HYBRID_CASE(ZEND_DO_UCALL_SPEC_RETVAL_UNUSED):
VM_TRACE(ZEND_DO_UCALL_SPEC_RETVAL_UNUSED) VM_TRACE(ZEND_DO_UCALL_SPEC_RETVAL_UNUSED)
ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
@ -62448,6 +62525,8 @@ void zend_vm_init(void)
ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER, ZEND_INIT_DYNAMIC_CALL_SPEC_CV_HANDLER,
ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER, ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER,
ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER, ZEND_DO_ICALL_SPEC_RETVAL_USED_HANDLER,
ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER,
ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER,
ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER, ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_HANDLER,
ZEND_DO_UCALL_SPEC_RETVAL_USED_HANDLER, ZEND_DO_UCALL_SPEC_RETVAL_USED_HANDLER,
ZEND_DO_UCALL_SPEC_OBSERVER_HANDLER, ZEND_DO_UCALL_SPEC_OBSERVER_HANDLER,
@ -63755,7 +63834,7 @@ void zend_vm_init(void)
1255, 1255,
1256 | SPEC_RULE_OP1, 1256 | SPEC_RULE_OP1,
1261 | SPEC_RULE_OP1, 1261 | SPEC_RULE_OP1,
3448, 3450,
1266 | SPEC_RULE_OP1, 1266 | SPEC_RULE_OP1,
1271 | SPEC_RULE_OP1, 1271 | SPEC_RULE_OP1,
1276 | SPEC_RULE_OP2, 1276 | SPEC_RULE_OP2,
@ -63839,133 +63918,133 @@ void zend_vm_init(void)
2180, 2180,
2181, 2181,
2182 | SPEC_RULE_OP2, 2182 | SPEC_RULE_OP2,
2187 | SPEC_RULE_RETVAL, 2187 | SPEC_RULE_RETVAL | SPEC_RULE_OBSERVER,
2189 | SPEC_RULE_RETVAL | SPEC_RULE_OBSERVER, 2191 | SPEC_RULE_RETVAL | SPEC_RULE_OBSERVER,
2193 | SPEC_RULE_RETVAL | SPEC_RULE_OBSERVER, 2195 | SPEC_RULE_RETVAL | SPEC_RULE_OBSERVER,
2197 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2199 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2197 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2199 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2222 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2224 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2222 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2224 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2247 | SPEC_RULE_OP1, 2249 | SPEC_RULE_OP1,
2252, 2254,
2253 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2255 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2278, 2280,
2279 | SPEC_RULE_OP1, 2281 | SPEC_RULE_OP1,
2284,
2285,
2286, 2286,
2287, 2287,
2288, 2288,
2289, 2289,
2290, 2290,
2291 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2291,
2316, 2292,
2317, 2293 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2318, 2318,
2319 | SPEC_RULE_OP1, 2319,
2324, 2320,
2325 | SPEC_RULE_ISSET, 2321 | SPEC_RULE_OP1,
2327 | SPEC_RULE_OP2, 2326,
2332, 2327 | SPEC_RULE_ISSET,
2333 | SPEC_RULE_OP1, 2329 | SPEC_RULE_OP2,
2338 | SPEC_RULE_OBSERVER, 2334,
2340, 2335 | SPEC_RULE_OP1,
2341 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2340 | SPEC_RULE_OBSERVER,
2366 | SPEC_RULE_OP1 | SPEC_RULE_OBSERVER, 2342,
2376, 2343 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2377, 2368 | SPEC_RULE_OP1 | SPEC_RULE_OBSERVER,
2378, 2378,
2379, 2379,
2380 | SPEC_RULE_OP1, 2380,
2385, 2381,
2386, 2382 | SPEC_RULE_OP1,
2387 | SPEC_RULE_OP1, 2387,
2392 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2388,
2417, 2389 | SPEC_RULE_OP1,
2418 | SPEC_RULE_OP1, 2394 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2423, 2419,
2424, 2420 | SPEC_RULE_OP1,
2425, 2425,
2426, 2426,
2427, 2427,
2428, 2428,
2429, 2429,
2430, 2430,
2431 | SPEC_RULE_OP1, 2431,
2436, 2432,
2437, 2433 | SPEC_RULE_OP1,
2438, 2438,
2439 | SPEC_RULE_OP2, 2439,
2444, 2440,
2445 | SPEC_RULE_OP1, 2441 | SPEC_RULE_OP2,
2450 | SPEC_RULE_OP1, 2446,
2455 | SPEC_RULE_OP1, 2447 | SPEC_RULE_OP1,
2460 | SPEC_RULE_OP1, 2452 | SPEC_RULE_OP1,
2465 | SPEC_RULE_OP1, 2457 | SPEC_RULE_OP1,
2470, 2462 | SPEC_RULE_OP1,
2471 | SPEC_RULE_OP1, 2467 | SPEC_RULE_OP1,
2476 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2472,
2501 | SPEC_RULE_OP1, 2473 | SPEC_RULE_OP1,
2506 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2478 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2531 | SPEC_RULE_OP1, 2503 | SPEC_RULE_OP1,
2536 | SPEC_RULE_OP1, 2508 | SPEC_RULE_OP1 | SPEC_RULE_OP2,
2541, 2533 | SPEC_RULE_OP1,
2542, 2538 | SPEC_RULE_OP1,
2543, 2543,
2544, 2544,
3448, 2545,
3448, 2546,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3448, 3450,
3450,
3450,
}; };
#if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)
zend_opcode_handler_funcs = labels; zend_opcode_handler_funcs = labels;
@ -64138,7 +64217,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2547 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2549 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
if (op->op1_type < op->op2_type) { if (op->op1_type < op->op2_type) {
zend_swap_operands(op); zend_swap_operands(op);
} }
@ -64146,7 +64225,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2572 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2574 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
if (op->op1_type < op->op2_type) { if (op->op1_type < op->op2_type) {
zend_swap_operands(op); zend_swap_operands(op);
} }
@ -64154,7 +64233,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2597 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2599 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
if (op->op1_type < op->op2_type) { if (op->op1_type < op->op2_type) {
zend_swap_operands(op); zend_swap_operands(op);
} }
@ -64165,17 +64244,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2622 | SPEC_RULE_OP1 | SPEC_RULE_OP2; spec = 2624 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2647 | SPEC_RULE_OP1 | SPEC_RULE_OP2; spec = 2649 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2672 | SPEC_RULE_OP1 | SPEC_RULE_OP2; spec = 2674 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} }
break; break;
case ZEND_MUL: case ZEND_MUL:
@ -64186,17 +64265,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2697 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2699 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
} else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) { } else if (op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2722 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2724 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2747 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 2749 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
} }
break; break;
case ZEND_IS_IDENTICAL: case ZEND_IS_IDENTICAL:
@ -64207,14 +64286,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2772 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2774 | 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) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2847 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2849 | 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))) { } 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 = 3072 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 3074 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
} }
break; break;
case ZEND_IS_NOT_IDENTICAL: case ZEND_IS_NOT_IDENTICAL:
@ -64225,14 +64304,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2922 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2924 | 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) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2997 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2999 | 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))) { } 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 = 3077 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE; spec = 3079 | SPEC_RULE_OP2 | SPEC_RULE_COMMUTATIVE;
} }
break; break;
case ZEND_IS_EQUAL: case ZEND_IS_EQUAL:
@ -64243,12 +64322,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2772 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2774 | 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) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2847 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2849 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
} }
break; break;
case ZEND_IS_NOT_EQUAL: case ZEND_IS_NOT_EQUAL:
@ -64259,12 +64338,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2922 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2924 | 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) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 2997 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE; spec = 2999 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH | SPEC_RULE_COMMUTATIVE;
} }
break; break;
case ZEND_IS_SMALLER: case ZEND_IS_SMALLER:
@ -64272,12 +64351,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 3082 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; spec = 3084 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 3157 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; spec = 3159 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} }
break; break;
case ZEND_IS_SMALLER_OR_EQUAL: case ZEND_IS_SMALLER_OR_EQUAL:
@ -64285,74 +64364,74 @@ 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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 3232 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; spec = 3234 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) { } else if (op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE) {
if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 3307 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; spec = 3309 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH;
} }
break; break;
case ZEND_QM_ASSIGN: case ZEND_QM_ASSIGN:
if (op1_info == MAY_BE_LONG) { if (op1_info == MAY_BE_LONG) {
spec = 3394 | SPEC_RULE_OP1; spec = 3396 | SPEC_RULE_OP1;
} else if (op1_info == MAY_BE_DOUBLE) { } else if (op1_info == MAY_BE_DOUBLE) {
spec = 3399 | SPEC_RULE_OP1; spec = 3401 | 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))))) { } 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 = 3404 | SPEC_RULE_OP1; spec = 3406 | SPEC_RULE_OP1;
} }
break; break;
case ZEND_PRE_INC: case ZEND_PRE_INC:
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
spec = 3382 | SPEC_RULE_RETVAL;
} else if (op1_info == MAY_BE_LONG) {
spec = 3384 | SPEC_RULE_RETVAL; spec = 3384 | SPEC_RULE_RETVAL;
} else if (op1_info == MAY_BE_LONG) {
spec = 3386 | SPEC_RULE_RETVAL;
} }
break; break;
case ZEND_PRE_DEC: case ZEND_PRE_DEC:
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
spec = 3386 | SPEC_RULE_RETVAL;
} else if (op1_info == MAY_BE_LONG) {
spec = 3388 | SPEC_RULE_RETVAL; spec = 3388 | SPEC_RULE_RETVAL;
} else if (op1_info == MAY_BE_LONG) {
spec = 3390 | SPEC_RULE_RETVAL;
} }
break; break;
case ZEND_POST_INC: case ZEND_POST_INC:
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
spec = 3390;
} else if (op1_info == MAY_BE_LONG) {
spec = 3391;
}
break;
case ZEND_POST_DEC:
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) { if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
spec = 3392; spec = 3392;
} else if (op1_info == MAY_BE_LONG) { } else if (op1_info == MAY_BE_LONG) {
spec = 3393; spec = 3393;
} }
break; break;
case ZEND_POST_DEC:
if (res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG) {
spec = 3394;
} else if (op1_info == MAY_BE_LONG) {
spec = 3395;
}
break;
case ZEND_JMP: case ZEND_JMP:
if (OP_JMP_ADDR(op, op->op1) > op) { if (OP_JMP_ADDR(op, op->op1) > op) {
spec = 2546; spec = 2548;
} }
break; break;
case ZEND_RECV: case ZEND_RECV:
if (op->op2.num == MAY_BE_ANY) { if (op->op2.num == MAY_BE_ANY) {
spec = 2545; spec = 2547;
} }
break; break;
case ZEND_SEND_VAL: case ZEND_SEND_VAL:
if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) { if (op->op1_type == IS_CONST && op->op2_type == IS_UNUSED && !Z_REFCOUNTED_P(RT_CONSTANT(op, op->op1))) {
spec = 3444; spec = 3446;
} }
break; break;
case ZEND_SEND_VAR_EX: 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) { if (op->op2_type == IS_UNUSED && op->op2.num <= MAX_ARG_FLAG_NUM && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) {
spec = 3439 | SPEC_RULE_OP1; spec = 3441 | SPEC_RULE_OP1;
} }
break; break;
case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_R:
if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) { if (op->op2_type == IS_CV && (op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY) {
spec = 3446 | SPEC_RULE_RETVAL; spec = 3448 | SPEC_RULE_RETVAL;
} }
break; break;
case ZEND_FETCH_DIM_R: case ZEND_FETCH_DIM_R:
@ -64360,17 +64439,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) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) {
break; break;
} }
spec = 3409 | SPEC_RULE_OP1 | SPEC_RULE_OP2; spec = 3411 | SPEC_RULE_OP1 | SPEC_RULE_OP2;
} }
break; break;
case ZEND_SEND_VAL_EX: 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))) { 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 = 3445; spec = 3447;
} }
break; break;
case ZEND_SEND_VAR: case ZEND_SEND_VAR:
if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { if (op->op2_type == IS_UNUSED && (op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) {
spec = 3434 | SPEC_RULE_OP1; spec = 3436 | SPEC_RULE_OP1;
} }
break; break;
case ZEND_BW_OR: case ZEND_BW_OR:

File diff suppressed because it is too large Load diff

View file

@ -9527,13 +9527,19 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
} }
} }
| // EG(current_execute_data) = execute_data;
| MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1
if (ZEND_OBSERVER_ENABLED) {
| mov FCARG1x, RX
| EXT_CALL zend_observer_fcall_begin, REG0
| ldr REG0, EX:RX->func // reload
}
| // ZVAL_NULL(EX_VAR(opline->result.var)); | // ZVAL_NULL(EX_VAR(opline->result.var));
| LOAD_ZVAL_ADDR FCARG2x, res_addr | LOAD_ZVAL_ADDR FCARG2x, res_addr
| SET_Z_TYPE_INFO FCARG2x, IS_NULL, TMP1w | SET_Z_TYPE_INFO FCARG2x, IS_NULL, TMP1w
| // EG(current_execute_data) = execute_data;
| MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1
zend_jit_reset_last_valid_opline(); zend_jit_reset_last_valid_opline();
| // fbc->internal_function.handler(call, ret); | // fbc->internal_function.handler(call, ret);
@ -9545,6 +9551,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
| blr TMP1 | blr TMP1
} }
if (ZEND_OBSERVER_ENABLED) {
| LOAD_ZVAL_ADDR FCARG2x, res_addr
| mov FCARG1x, RX
| EXT_CALL zend_observer_fcall_end, REG0
}
| // EG(current_execute_data) = execute_data; | // EG(current_execute_data) = execute_data;
| MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0 | MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0

View file

@ -10231,13 +10231,19 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
} }
} }
| // EG(current_execute_data) = execute_data;
| MEM_STORE_ZTS aword, executor_globals, current_execute_data, RX, r1
if (ZEND_OBSERVER_ENABLED) {
| mov FCARG1a, RX
| EXT_CALL zend_observer_fcall_begin, r0
| mov r0, EX:RX->func // reload
}
| // ZVAL_NULL(EX_VAR(opline->result.var)); | // ZVAL_NULL(EX_VAR(opline->result.var));
| LOAD_ZVAL_ADDR FCARG2a, res_addr | LOAD_ZVAL_ADDR FCARG2a, res_addr
| SET_Z_TYPE_INFO FCARG2a, IS_NULL | SET_Z_TYPE_INFO FCARG2a, IS_NULL
| // EG(current_execute_data) = execute_data;
| MEM_STORE_ZTS aword, executor_globals, current_execute_data, RX, r1
zend_jit_reset_last_valid_opline(); zend_jit_reset_last_valid_opline();
| // fbc->internal_function.handler(call, ret); | // fbc->internal_function.handler(call, ret);
@ -10248,6 +10254,12 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend
| call aword [r0 + offsetof(zend_internal_function, handler)] | call aword [r0 + offsetof(zend_internal_function, handler)]
} }
if (ZEND_OBSERVER_ENABLED) {
| LOAD_ZVAL_ADDR FCARG2a, res_addr
| mov FCARG1a, RX
| EXT_CALL zend_observer_fcall_end, r0
}
| // EG(current_execute_data) = execute_data; | // EG(current_execute_data) = execute_data;
| MEM_STORE_ZTS aword, executor_globals, current_execute_data, FP, r0 | MEM_STORE_ZTS aword, executor_globals, current_execute_data, FP, r0

View file

@ -1245,6 +1245,7 @@ bool pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent); func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent);
func.scope = dbh_obj->std.ce; func.scope = dbh_obj->std.ce;
func.prototype = NULL; func.prototype = NULL;
ZEND_MAP_PTR(func.run_time_cache) = NULL;
if (funcs->flags) { if (funcs->flags) {
func.fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE; func.fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE;
} else { } else {

View file

@ -264,8 +264,8 @@ static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList)
if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) { if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) {
ZEND_HASH_FOREACH_STR_KEY(*p, funcname) { ZEND_HASH_FOREACH_STR_KEY(*p, funcname) {
if ((func = zend_hash_find_ptr(EG(function_table), funcname))) { if ((func = zend_hash_find_ptr(EG(function_table), funcname))) {
zend_observer_remove_begin_handler(&func->op_array, observer_begin); zend_observer_remove_begin_handler(func, observer_begin);
zend_observer_remove_end_handler(&func->op_array, observer_end); zend_observer_remove_end_handler(func, observer_end);
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} }
@ -280,8 +280,8 @@ static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList)
if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) { if (stage != PHP_INI_STAGE_STARTUP && stage != PHP_INI_STAGE_ACTIVATE && stage != PHP_INI_STAGE_DEACTIVATE && stage != PHP_INI_STAGE_SHUTDOWN) {
ZEND_HASH_FOREACH_STR_KEY(*p, funcname) { ZEND_HASH_FOREACH_STR_KEY(*p, funcname) {
if ((func = zend_hash_find_ptr(EG(function_table), funcname))) { if ((func = zend_hash_find_ptr(EG(function_table), funcname))) {
zend_observer_add_begin_handler(&func->op_array, observer_begin); zend_observer_add_begin_handler(func, observer_begin);
zend_observer_add_end_handler(&func->op_array, observer_end); zend_observer_add_end_handler(func, observer_end);
} }
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} }

View file

@ -48,6 +48,13 @@ var_dump(foo());
{main} %s%eobserver_backtrace_%d.php {main} %s%eobserver_backtrace_%d.php
--> -->
<foo> <foo>
<!-- init Generator::current() -->
<!--
Generator::current()
foo()
{main} %s%eobserver_backtrace_%d.php
-->
<Generator::current>
<!-- init gen() --> <!-- init gen() -->
<!-- <!--
gen() gen()
@ -65,6 +72,16 @@ var_dump(foo());
{main} %s%eobserver_backtrace_%d.php {main} %s%eobserver_backtrace_%d.php
--> -->
<TestClass::foo> <TestClass::foo>
<!-- init array_map() -->
<!--
array_map()
TestClass::foo()
gen()
Generator::current()
foo()
{main} %s%eobserver_backtrace_%d.php
-->
<array_map>
<!-- init TestClass::{closure}() --> <!-- init TestClass::{closure}() -->
<!-- <!--
TestClass::{closure}() TestClass::{closure}()
@ -94,13 +111,22 @@ var_dump(foo());
<TestClass::bar> <TestClass::bar>
</TestClass::bar> </TestClass::bar>
</TestClass::{closure}> </TestClass::{closure}>
</array_map>
</TestClass::foo> </TestClass::foo>
</gen> </gen>
</Generator::current>
</foo> </foo>
<!-- init var_dump() -->
<!--
var_dump()
{main} %s%eobserver_backtrace_%d.php
-->
<var_dump>
array(2) { array(2) {
[0]=> [0]=>
int(42) int(42)
[1]=> [1]=>
int(1337) int(1337)
} }
</var_dump>
</file '%s%eobserver_backtrace_%d.php'> </file '%s%eobserver_backtrace_%d.php'>

View file

@ -26,30 +26,44 @@ foo();
echo 'DONE' . PHP_EOL; echo 'DONE' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_basic_01.php' --> <!-- init '%s%eobserver_basic_%d.php' -->
<file '%s%eobserver_basic_01.php'> <file '%s%eobserver_basic_%d.php'>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
Foo Foo
<!-- init bar() --> <!-- init bar() -->
<bar> <bar>
Bar Bar
<!-- init array_sum() -->
<array_sum>
</array_sum>
<!-- init var_dump() -->
<var_dump>
int(6) int(6)
</var_dump>
</bar> </bar>
</foo> </foo>
<foo> <foo>
Foo Foo
<bar> <bar>
Bar Bar
<array_sum>
</array_sum>
<var_dump>
int(6) int(6)
</var_dump>
</bar> </bar>
</foo> </foo>
<foo> <foo>
Foo Foo
<bar> <bar>
Bar Bar
<array_sum>
</array_sum>
<var_dump>
int(6) int(6)
</var_dump>
</bar> </bar>
</foo> </foo>
DONE DONE
</file '%s%eobserver_basic_01.php'> </file '%s%eobserver_basic_%d.php'>

View file

@ -30,30 +30,44 @@ $test->foo();
echo 'DONE' . PHP_EOL; echo 'DONE' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_basic_02.php' --> <!-- init '%s%eobserver_basic_%d.php' -->
<file '%s%eobserver_basic_02.php'> <file '%s%eobserver_basic_%d.php'>
<!-- init TestClass::foo() --> <!-- init TestClass::foo() -->
<TestClass::foo> <TestClass::foo>
Foo Foo
<!-- init TestClass::bar() --> <!-- init TestClass::bar() -->
<TestClass::bar> <TestClass::bar>
Bar Bar
<!-- init array_sum() -->
<array_sum>
</array_sum>
<!-- init var_dump() -->
<var_dump>
int(6) int(6)
</var_dump>
</TestClass::bar> </TestClass::bar>
</TestClass::foo> </TestClass::foo>
<TestClass::foo> <TestClass::foo>
Foo Foo
<TestClass::bar> <TestClass::bar>
Bar Bar
<array_sum>
</array_sum>
<var_dump>
int(6) int(6)
</var_dump>
</TestClass::bar> </TestClass::bar>
</TestClass::foo> </TestClass::foo>
<TestClass::foo> <TestClass::foo>
Foo Foo
<TestClass::bar> <TestClass::bar>
Bar Bar
<array_sum>
</array_sum>
<var_dump>
int(6) int(6)
</var_dump>
</TestClass::bar> </TestClass::bar>
</TestClass::foo> </TestClass::foo>
DONE DONE
</file '%s%eobserver_basic_02.php'> </file '%s%eobserver_basic_%d.php'>

View file

@ -34,6 +34,7 @@ Foo
</foo> </foo>
<!-- init bar() --> <!-- init bar() -->
Bar Bar
<!-- init ini_set() -->
Foo Foo
<bar> <bar>
Bar Bar

View file

@ -25,7 +25,16 @@ call_user_func([$r->getAttributes(A::class)[0], 'newInstance']);
--EXPECTF-- --EXPECTF--
<!-- init '%s' --> <!-- init '%s' -->
<file '%s'> <file '%s'>
<!-- init ReflectionFunction::__construct() -->
<ReflectionFunction::__construct>
</ReflectionFunction::__construct>
<!-- init ReflectionFunctionAbstract::getAttributes() -->
<ReflectionFunctionAbstract::getAttributes>
</ReflectionFunctionAbstract::getAttributes>
<!-- init ReflectionAttribute::newInstance() -->
<ReflectionAttribute::newInstance>
<!-- init A::__construct() --> <!-- init A::__construct() -->
<A::__construct> <A::__construct>
</A::__construct> </A::__construct>
</ReflectionAttribute::newInstance>
</file '%s'> </file '%s'>

View file

@ -25,9 +25,24 @@ call_user_func([$r->getAttributes(A::class)[0], 'newInstance']);
--EXPECTF-- --EXPECTF--
<!-- init '%s' --> <!-- init '%s' -->
<file '%s'> <file '%s'>
<!-- init ReflectionFunction::__construct() -->
<ReflectionFunction::__construct>
</ReflectionFunction::__construct>
<!-- init ReflectionFunctionAbstract::getAttributes() -->
<ReflectionFunctionAbstract::getAttributes>
</ReflectionFunctionAbstract::getAttributes>
<!-- init ReflectionAttribute::newInstance() -->
<ReflectionAttribute::newInstance>
<!-- init A::__construct() --> <!-- init A::__construct() -->
<A::__construct> <A::__construct>
<!-- init array_map() -->
<array_map>
<!-- init str_repeat() -->
<str_repeat>
Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d Fatal error: Allowed memory size of %d bytes exhausted %s in %s on line %d
</str_repeat>
</array_map>
</A::__construct> </A::__construct>
</ReflectionAttribute::newInstance>
</file '%s'> </file '%s'>

View file

@ -42,6 +42,8 @@ a();
<d> <d>
</d> </d>
<!-- init bailout() --> <!-- init bailout() -->
<!-- init array_map() -->
<!-- init str_repeat() -->
Fatal error: Allowed memory size of 20971520 bytes exhausted %s in %s on line %d Fatal error: Allowed memory size of 20971520 bytes exhausted %s in %s on line %d
</a> </a>

View file

@ -26,14 +26,19 @@ namespace Test {
} }
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_call_user_func_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_call_user_func_%d.php'> <file '%s'>
<!-- init call_user_func() -->
<call_user_func>
<!-- init Test\MyClass::myMethod() --> <!-- init Test\MyClass::myMethod() -->
<Test\MyClass::myMethod> <Test\MyClass::myMethod>
MyClass::myMethod called MyClass::myMethod called
</Test\MyClass::myMethod> </Test\MyClass::myMethod>
</call_user_func>
<call_user_func>
<!-- init Test\my_function() --> <!-- init Test\my_function() -->
<Test\my_function> <Test\my_function>
my_function called my_function called
</Test\my_function> </Test\my_function>
</file '%s%eobserver_call_user_func_%d.php'> </call_user_func>
</file '%s'>

View file

@ -26,14 +26,19 @@ namespace Test {
} }
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_call_user_func_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_call_user_func_%d.php'> <file '%s'>
<!-- init call_user_func_array() -->
<call_user_func_array>
<!-- init Test\MyClass::myMethod() --> <!-- init Test\MyClass::myMethod() -->
<Test\MyClass::myMethod> <Test\MyClass::myMethod>
MyClass::myMethod called MyClass::myMethod called
</Test\MyClass::myMethod> </Test\MyClass::myMethod>
</call_user_func_array>
<call_user_func_array>
<!-- init Test\my_function() --> <!-- init Test\my_function() -->
<Test\my_function> <Test\my_function>
my_function called my_function called
</Test\my_function> </Test\my_function>
</file '%s%eobserver_call_user_func_%d.php'> </call_user_func_array>
</file '%s'>

View file

@ -23,27 +23,41 @@ $foo($bar);
echo 'DONE' . PHP_EOL; echo 'DONE' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_closure_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_closure_%d.php'> <file '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<{closure}> <{closure}>
Answer Answer
<!-- init {closure}() --> <!-- init {closure}() -->
<{closure}> <{closure}>
<!-- init array_sum() -->
<array_sum>
</array_sum>
<!-- init var_dump() -->
<var_dump>
int(42) int(42)
</var_dump>
</{closure}> </{closure}>
</{closure}> </{closure}>
<{closure}> <{closure}>
Answer Answer
<{closure}> <{closure}>
<array_sum>
</array_sum>
<var_dump>
int(42) int(42)
</var_dump>
</{closure}> </{closure}>
</{closure}> </{closure}>
<{closure}> <{closure}>
Answer Answer
<{closure}> <{closure}>
<array_sum>
</array_sum>
<var_dump>
int(42) int(42)
</var_dump>
</{closure}> </{closure}>
</{closure}> </{closure}>
DONE DONE
</file '%s%eobserver_closure_%d.php'> </file '%s'>

View file

@ -22,11 +22,14 @@ $closure();
echo 'DONE' . PHP_EOL; echo 'DONE' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_closure_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_closure_%d.php'> <file '%s'>
<!-- init Closure::fromCallable() -->
<Closure::fromCallable>
</Closure::fromCallable>
<!-- init Foo::bar() --> <!-- init Foo::bar() -->
<Foo::bar> <Foo::bar>
Called as fake closure. Called as fake closure.
</Foo::bar> </Foo::bar>
DONE DONE
</file '%s%eobserver_closure_%d.php'> </file '%s'>

View file

@ -19,11 +19,14 @@ foo();
echo 'You should not see this.'; echo 'You should not see this.';
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_error_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_error_%d.php'> <file '%s'>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
<!-- init str_repeat() -->
<str_repeat>
Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d Fatal error: Allowed memory size of 2097152 bytes exhausted%s(tried to allocate %d bytes) in %s on line %d
</str_repeat:NULL>
</foo:NULL> </foo:NULL>
</file '%s%eobserver_error_%d.php'> </file '%s%eobserver_error_%d.php'>

View file

@ -18,11 +18,14 @@ foo();
echo 'You should not see this.'; echo 'You should not see this.';
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_error_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_error_%d.php'> <file '%s'>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
<!-- init trigger_error() -->
<trigger_error>
Fatal error: Foo error in %s on line %d Fatal error: Foo error in %s on line %d
</trigger_error:NULL>
</foo:NULL> </foo:NULL>
</file '%s%eobserver_error_%d.php'> </file '%s'>

View file

@ -36,10 +36,18 @@ echo 'Done.' . PHP_EOL;
<main> <main>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
<!-- init SoapClient::__construct() -->
<SoapClient::__construct>
<!-- Exception: SoapFault -->
</SoapClient::__construct:NULL>
<!-- Exception: SoapFault --> <!-- Exception: SoapFault -->
</foo:NULL> </foo:NULL>
<!-- Exception: SoapFault --> <!-- Exception: SoapFault -->
</main:NULL> </main:NULL>
<!-- init Exception::getMessage() -->
<Exception::getMessage>
</Exception::getMessage:'SOAP-ERROR: Parsing WSDL: Couldn\'t load from \'foo\' : failed to load external entity "foo"
'>
SOAP-ERROR: Parsing WSDL: Couldn't load from 'foo' : failed to load external entity "foo" SOAP-ERROR: Parsing WSDL: Couldn't load from 'foo' : failed to load external entity "foo"
Done. Done.

View file

@ -22,14 +22,20 @@ foo();
echo 'You should not see this.'; echo 'You should not see this.';
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_error_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_error_%d.php'> <file '%s'>
<!-- init set_error_handler() -->
<set_error_handler>
</set_error_handler:NULL>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
<!-- init {closure}() --> <!-- init {closure}() -->
<{closure}> <{closure}>
<!-- init trigger_error() -->
<trigger_error>
Fatal error: Foo error in %s on line %d Fatal error: Foo error in %s on line %d
</trigger_error:NULL>
</{closure}:NULL> </{closure}:NULL>
</foo:NULL> </foo:NULL>
</file '%s%eobserver_error_%d.php'> </file '%s'>

View file

@ -23,8 +23,8 @@ foo();
echo 'You should not see this' . PHP_EOL; echo 'You should not see this' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_exception_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_exception_%d.php'> <file '%s'>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
Call #0 Call #0
@ -34,10 +34,19 @@ Call #1
</foo> </foo>
<foo> <foo>
Call #2 Call #2
<!-- init Exception::__construct() -->
<Exception::__construct>
</Exception::__construct>
<!-- Exception: RuntimeException --> <!-- Exception: RuntimeException -->
</foo> </foo>
<!-- Exception: RuntimeException --> <!-- Exception: RuntimeException -->
</file '%s%eobserver_exception_%d.php'> </file '%s'>
<!-- init Exception::__toString() -->
<Exception::__toString>
<!-- init Exception::getTraceAsString() -->
<Exception::getTraceAsString>
</Exception::getTraceAsString>
</Exception::__toString>
Fatal error: Uncaught RuntimeException: Third time is a charm in %s%eobserver_exception_%d.php:%d Fatal error: Uncaught RuntimeException: Third time is a charm in %s%eobserver_exception_%d.php:%d
Stack trace: Stack trace:

View file

@ -19,13 +19,17 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_01.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- alloc: %s --> <!-- alloc: %s -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- init Fiber::resume() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->

View file

@ -16,10 +16,13 @@ $fiber->start();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_02.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->

View file

@ -39,14 +39,19 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_03.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- init Fiber::resume() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- init var_dump() -->
int(1) int(1)
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>

View file

@ -26,12 +26,16 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_04.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- init Fiber::resume() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->

View file

@ -25,12 +25,16 @@ $fiber->resume();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_05.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- init Fiber::resume() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->

View file

@ -22,12 +22,17 @@ try {
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%sobserver_fiber_06.php' --> <!-- init '%s' -->
<!-- init Fiber::__construct() -->
<!-- init Fiber::start() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<init '%s'> <init '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<!-- init Fiber::suspend() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<suspend '%s'> <suspend '%s'>
<!-- init Exception::__construct() -->
<!-- init Fiber::throw() -->
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->
<resume '%s'> <resume '%s'>
<!-- switching from fiber %s to %s --> <!-- switching from fiber %s to %s -->

View file

@ -28,8 +28,8 @@ function doSomething() {
echo doSomething() . PHP_EOL; echo doSomething() . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_generator_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_generator_%d.php'> <file '%s'>
<!-- init doSomething() --> <!-- init doSomething() -->
<doSomething> <doSomething>
<!-- init getResults() --> <!-- init getResults() -->
@ -44,7 +44,10 @@ echo doSomething() . PHP_EOL;
12 12
<getResults> <getResults>
</getResults:1337> </getResults:1337>
<!-- init Generator::getReturn() -->
<Generator::getReturn>
</Generator::getReturn:1337>
1337 1337
</doSomething:'Done'> </doSomething:'Done'>
Done Done
</file '%s%eobserver_generator_%d.php'> </file '%s'>

View file

@ -33,32 +33,87 @@ function doSomething() {
echo doSomething() . PHP_EOL; echo doSomething() . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_generator_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_generator_%d.php'> <file '%s'>
<!-- init doSomething() --> <!-- init doSomething() -->
<doSomething> <doSomething>
<!-- init Generator::current() -->
<Generator::current>
<!-- init fooResults() --> <!-- init fooResults() -->
<fooResults> <fooResults>
Starting generator Starting generator
</fooResults:0> </fooResults:0>
</Generator::current:0>
<Generator::current>
</Generator::current:0>
0 0
<Generator::current>
</Generator::current:0>
<!-- init Generator::next() -->
<Generator::next>
<fooResults> <fooResults>
</fooResults:1> </fooResults:1>
</Generator::next:NULL>
<Generator::current>
</Generator::current:1>
<Generator::current>
</Generator::current:1>
1 1
<Generator::current>
</Generator::current:1>
<Generator::next>
<fooResults> <fooResults>
</fooResults:2> </fooResults:2>
</Generator::next:NULL>
<Generator::current>
</Generator::current:2>
<Generator::current>
</Generator::current:2>
2 2
<Generator::current>
</Generator::current:2>
<Generator::next>
<fooResults> <fooResults>
</fooResults:3> </fooResults:3>
</Generator::next:NULL>
<Generator::current>
</Generator::current:3>
<Generator::current>
</Generator::current:3>
3 3
<Generator::current>
</Generator::current:3>
<Generator::next>
<fooResults> <fooResults>
</fooResults:4> </fooResults:4>
</Generator::next:NULL>
<Generator::current>
</Generator::current:4>
<Generator::current>
</Generator::current:4>
4 4
<Generator::current>
</Generator::current:4>
<Generator::next>
<fooResults> <fooResults>
</fooResults:5> </fooResults:5>
</Generator::next:NULL>
<Generator::current>
</Generator::current:5>
<Generator::current>
</Generator::current:5>
5 5
<Generator::current>
</Generator::current:5>
<!-- init Generator::send() -->
<Generator::send>
<fooResults> <fooResults>
</fooResults:NULL> </fooResults:NULL>
</Generator::send:NULL>
<Generator::next>
</Generator::next:NULL>
<Generator::current>
</Generator::current:NULL>
</doSomething:'Done'> </doSomething:'Done'>
Done Done
</file '%s%eobserver_generator_%d.php'> </file '%s'>

View file

@ -26,8 +26,8 @@ function doSomething() {
echo doSomething() . PHP_EOL; echo doSomething() . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_generator_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_generator_%d.php'> <file '%s'>
<!-- init doSomething() --> <!-- init doSomething() -->
<doSomething> <doSomething>
<!-- init fooResults() --> <!-- init fooResults() -->
@ -38,12 +38,27 @@ echo doSomething() . PHP_EOL;
</fooResults:1> </fooResults:1>
1 1
<fooResults> <fooResults>
<!-- init Exception::__construct() -->
<Exception::__construct>
</Exception::__construct:NULL>
<!-- Exception: RuntimeException --> <!-- Exception: RuntimeException -->
</fooResults:NULL> </fooResults:NULL>
<!-- Exception: RuntimeException --> <!-- Exception: RuntimeException -->
</doSomething:NULL> </doSomething:NULL>
<!-- Exception: RuntimeException --> <!-- Exception: RuntimeException -->
</file '%s%eobserver_generator_%d.php'> </file '%s'>
<!-- init Exception::__toString() -->
<Exception::__toString>
<!-- init Exception::getTraceAsString() -->
<Exception::getTraceAsString>
</Exception::getTraceAsString:'#0 %s(%d): fooResults()
#1 %s(%d): doSomething()
#2 {main}'>
</Exception::__toString:'RuntimeException: Oops! in %s%eobserver_generator_%d.php:%d
Stack trace:
#0 %s%eobserver_generator_%d.php(%d): fooResults()
#1 %s%eobserver_generator_%d.php(%d): doSomething()
#2 {main}'>
Fatal error: Uncaught RuntimeException: Oops! in %s%eobserver_generator_%d.php:%d Fatal error: Uncaught RuntimeException: Oops! in %s%eobserver_generator_%d.php:%d
Stack trace: Stack trace:

View file

@ -20,9 +20,9 @@ echo array_sum([1,2,3]) . PHP_EOL;
foo(); foo();
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_opline_%d.php' --> <!-- init '%s' -->
<!-- opcode: 'ZEND_INIT_FCALL' --> <!-- opcode: 'ZEND_INIT_FCALL' -->
<file '%s%eobserver_opline_%d.php'> <file '%s'>
<!-- opcode: 'ZEND_INIT_FCALL' --> <!-- opcode: 'ZEND_INIT_FCALL' -->
<!-- init foo() --> <!-- init foo() -->
<!-- opcode: 'ZEND_ECHO' --> <!-- opcode: 'ZEND_ECHO' -->
@ -31,9 +31,9 @@ foo();
Foo Foo
<!-- opcode: 'ZEND_RETURN' --> <!-- opcode: 'ZEND_RETURN' -->
</foo> </foo>
<!-- init '%s%eobserver.inc' --> <!-- init '%s' -->
<!-- opcode: 'ZEND_INIT_FCALL' --> <!-- opcode: 'ZEND_INIT_FCALL' -->
<file '%s%eobserver.inc'> <file '%s'>
<!-- opcode: 'ZEND_INIT_FCALL' --> <!-- opcode: 'ZEND_INIT_FCALL' -->
<!-- init foo_observer_test() --> <!-- init foo_observer_test() -->
<!-- opcode: 'ZEND_ECHO' --> <!-- opcode: 'ZEND_ECHO' -->
@ -43,7 +43,13 @@ foo_observer_test
<!-- opcode: 'ZEND_RETURN' --> <!-- opcode: 'ZEND_RETURN' -->
</foo_observer_test> </foo_observer_test>
<!-- opcode: 'ZEND_RETURN' --> <!-- opcode: 'ZEND_RETURN' -->
</file '%s%eobserver.inc'> </file '%s'>
<!-- init array_sum() -->
<!-- opcode: 'ZEND_RETURN' -->
<array_sum>
<!-- opcode: 'ZEND_RETURN' -->
<!-- opcode: 'ZEND_RETURN' -->
</array_sum>
6 6
<foo> <foo>
<!-- opcode: 'ZEND_ECHO' --> <!-- opcode: 'ZEND_ECHO' -->
@ -51,4 +57,4 @@ Foo
<!-- opcode: 'ZEND_RETURN' --> <!-- opcode: 'ZEND_RETURN' -->
</foo> </foo>
<!-- opcode: 'ZEND_RETURN' --> <!-- opcode: 'ZEND_RETURN' -->
</file '%s%eobserver_opline_%d.php'> </file '%s'>

View file

@ -21,12 +21,20 @@ $gen->current();
echo 'Done' . PHP_EOL; echo 'Done' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_retval_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_retval_%d.php'> <file '%s'>
<!-- init Generator::current() -->
<Generator::current>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
</foo:'I should be observable'> </foo:'I should be observable'>
</Generator::current:'I should be observable'>
<!-- init Generator::next() -->
<Generator::next>
<foo> <foo>
</foo:'Me too!'> </foo:'Me too!'>
</Generator::next:NULL>
<Generator::current>
</Generator::current:'Me too!'>
Done Done
</file '%s%eobserver_retval_%d.php'> </file '%s'>

View file

@ -24,13 +24,16 @@ function foo() {
echo 'Done: ' . bar(40) . PHP_EOL; echo 'Done: ' . bar(40) . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_shutdown_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_shutdown_%d.php'> <file '%s'>
<!-- init register_shutdown_function() -->
<register_shutdown_function>
</register_shutdown_function:NULL>
<!-- init bar() --> <!-- init bar() -->
<bar> <bar>
</bar:40> </bar:40>
Done: 40 Done: 40
</file '%s%eobserver_shutdown_%d.php'> </file '%s'>
<!-- init {closure}() --> <!-- init {closure}() -->
<{closure}> <{closure}>
<!-- init foo() --> <!-- init foo() -->

View file

@ -12,14 +12,24 @@ function foo(array $a) { return 1; }
foo(42); foo(42);
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_types_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_types_%d.php'> <file '%s'>
<!-- init foo() --> <!-- init foo() -->
<foo> <foo>
<!-- Exception: TypeError --> <!-- Exception: TypeError -->
</foo:NULL> </foo:NULL>
<!-- Exception: TypeError --> <!-- Exception: TypeError -->
</file '%s%eobserver_types_%d.php'> </file '%s'>
<!-- init Error::__toString() -->
<Error::__toString>
<!-- init Error::getTraceAsString() -->
<Error::getTraceAsString>
</Error::getTraceAsString:'#0 %s(%d): foo(42)
#1 {main}'>
</Error::__toString:'TypeError: foo(): Argument #1 ($a) must be of type array, int given, called in %s:%d
Stack trace:
#0 %s%eobserver_types_%d.php(%d): foo(42)
#1 {main}'>
Fatal error: Uncaught TypeError: foo(): Argument #1 ($a) must be of type array, int given, called in %s:%d Fatal error: Uncaught TypeError: foo(): Argument #1 ($a) must be of type array, int given, called in %s:%d
Stack trace: Stack trace:

View file

@ -18,8 +18,10 @@ var_dump(array_reduce($a, 'sum'));
echo 'Done' . PHP_EOL; echo 'Done' . PHP_EOL;
?> ?>
--EXPECTF-- --EXPECTF--
<!-- init '%s%eobserver_zend_call_function_%d.php' --> <!-- init '%s' -->
<file '%s%eobserver_zend_call_function_%d.php'> <file '%s'>
<!-- init array_reduce() -->
<array_reduce>
<!-- init sum() --> <!-- init sum() -->
<sum> <sum>
</sum> </sum>
@ -31,6 +33,10 @@ echo 'Done' . PHP_EOL;
</sum> </sum>
<sum> <sum>
</sum> </sum>
</array_reduce>
<!-- init var_dump() -->
<var_dump>
int(15) int(15)
</var_dump>
Done Done
</file '%s%eobserver_zend_call_function_%d.php'> </file '%s'>