diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 01f9277214d77..f90ecdc32abf1 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2061,6 +2061,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio } internal_function->type = ZEND_INTERNAL_FUNCTION; internal_function->module = EG(current_module); + ZEND_MAP_PTR_NEW(internal_function->instrument_cache); memset(internal_function->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*)); if (scope) { diff --git a/Zend/zend_closures.c b/Zend/zend_closures.c index 02df3504ccf16..9d8b07c203351 100644 --- a/Zend/zend_closures.c +++ b/Zend/zend_closures.c @@ -309,6 +309,10 @@ static int zend_create_closure_from_callable(zval *return_value, zval *callable, call.function_name = mptr->common.function_name; call.scope = mptr->common.scope; + // TODO: Is this correct??? + static const zend_instrument_fcall_cache *dummy_handlers = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(call.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handlers); + zend_free_trampoline(mptr); mptr = (zend_function *) &call; } @@ -395,6 +399,10 @@ ZEND_API zend_function *zend_get_closure_invoke_method(zend_object *object) /* { invoke->internal_function.module = 0; invoke->internal_function.scope = zend_ce_closure; invoke->internal_function.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE); + + // TODO: Is this correct??? + static const zend_instrument_fcall_cache *dummy_handler = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(invoke->internal_function.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handler); return invoke; } /* }}} */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 58c74e1da08e9..1e9be24d5f2a5 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -6258,9 +6258,14 @@ void zend_compile_func_decl(znode *result, zend_ast *ast, zend_bool toplevel) /* op_array->fn_flags |= ZEND_ACC_PRELOADED; ZEND_MAP_PTR_NEW(op_array->run_time_cache); ZEND_MAP_PTR_NEW(op_array->static_variables_ptr); + ZEND_MAP_PTR_NEW(op_array->instrument_cache); } else { ZEND_MAP_PTR_INIT(op_array->run_time_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); + + ZEND_MAP_PTR_INIT(op_array->instrument_cache, + zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->instrument_cache, NULL); } op_array->fn_flags |= (orig_op_array->fn_flags & ZEND_ACC_STRICT_TYPES); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a90219b1b4453..90b9268b780f0 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -403,6 +403,7 @@ struct _zend_op_array { uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; + ZEND_MAP_PTR_DEF(struct zend_instrument_fcall_cache *, instrument_cache); /* END of common elements */ int cache_size; /* number of run_time_cache_slots * sizeof(void*) */ @@ -452,6 +453,7 @@ typedef struct _zend_internal_function { uint32_t num_args; uint32_t required_num_args; zend_internal_arg_info *arg_info; + ZEND_MAP_PTR_DEF(struct zend_instrument_fcall_cache *, instrument_cache); /* END of common elements */ zif_handler handler; @@ -475,6 +477,7 @@ union _zend_function { uint32_t num_args; uint32_t required_num_args; zend_arg_info *arg_info; /* index -1 represents the return value info, if any */ + ZEND_MAP_PTR_DEF(struct zend_instrument_fcall_cache *, instrument_cache); } common; zend_op_array op_array; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 2eb7b1726010c..89c7468ee3b13 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -43,6 +43,7 @@ /* Virtual current working directory support */ #include "zend_virtual_cwd.h" +#include "zend_instrument.h" #ifdef HAVE_GCC_GLOBAL_REGS # if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386) @@ -137,6 +138,7 @@ ZEND_API const zend_internal_function zend_pass_function = { 0, /* num_args */ 0, /* required_num_args */ NULL, /* arg_info */ + NULL, ZEND_FN(pass), /* handler */ NULL, /* module */ {NULL,NULL,NULL,NULL} /* reserved */ @@ -3307,10 +3309,7 @@ static int zend_check_symbol(zval *pz) #define CHECK_SYMBOL_TABLES() #endif -ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value) -{ - execute_data->func->internal_function.handler(execute_data, return_value); -} +ZEND_API extern inline void execute_internal(zend_execute_data *execute_data, zval *return_value); ZEND_API void zend_clean_and_cache_symbol_table(zend_array *symbol_table) /* {{{ */ { @@ -3508,6 +3507,9 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function(zend_string *name) /* if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache_i(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } return fbc; } return NULL; @@ -3523,6 +3525,9 @@ ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str(const char *name, if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache_i(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } return fbc; } return NULL; @@ -3555,6 +3560,12 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr); memset(ptr, 0, op_array->cache_size); } + if (!ZEND_MAP_PTR(op_array->instrument_cache)) { + ZEND_MAP_PTR_INIT(op_array->instrument_cache, + zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->instrument_cache, NULL); + zend_instrument_fcall_install((zend_function *)op_array); + } EX(run_time_cache) = RUN_TIME_CACHE(op_array); EG(current_execute_data) = execute_data; @@ -3579,6 +3590,9 @@ ZEND_API void zend_init_func_execute_data(zend_execute_data *ex, zend_op_array * if (!RUN_TIME_CACHE(op_array)) { init_func_run_time_cache(op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(op_array->instrument_cache))) { + zend_instrument_fcall_install((zend_function *)op_array); + } i_init_func_execute_data(op_array, return_value, 1 EXECUTE_DATA_CC); #if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID)) @@ -3930,6 +3944,9 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } else { if (ZSTR_VAL(function)[0] == '\\') { lcname = zend_string_alloc(ZSTR_LEN(function) - 1, 0); @@ -3948,6 +3965,9 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_string(zend_s if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } called_scope = NULL; } @@ -3992,6 +4012,9 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_object(zend_o if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } return zend_vm_stack_push_call_frame(call_info, fbc, num_args, object_or_called_scope); @@ -4077,6 +4100,9 @@ static zend_never_inline zend_execute_data *zend_init_dynamic_call_array(zend_ar if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } return zend_vm_stack_push_call_frame(call_info, fbc, num_args, object_or_called_scope); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 2299adf62fe7e..e1d62000e69c1 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -23,6 +23,7 @@ #include "zend_compile.h" #include "zend_hash.h" +#include "zend_instrument.h" #include "zend_operators.h" #include "zend_variables.h" @@ -39,7 +40,19 @@ ZEND_API void zend_init_func_execute_data(zend_execute_data *execute_data, zend_ ZEND_API void zend_init_code_execute_data(zend_execute_data *execute_data, zend_op_array *op_array, zval *return_value); ZEND_API void zend_execute(zend_op_array *op_array, zval *return_value); ZEND_API void execute_ex(zend_execute_data *execute_data); -ZEND_API void execute_internal(zend_execute_data *execute_data, zval *return_value); + +ZEND_API inline void execute_internal(zend_execute_data *execute_data, zval *return_value) { + zend_instrument_fcall_cache *cache = (zend_instrument_fcall_cache *) + ZEND_MAP_PTR_GET(execute_data->func->common.instrument_cache); + if (UNEXPECTED(cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED)) { + zend_instrument_fcall_call_begin(cache, execute_data); + execute_data->func->internal_function.handler(execute_data, return_value); + zend_instrument_fcall_call_end(cache, execute_data, return_value); + } else { + execute_data->func->internal_function.handler(execute_data, return_value); + } +} + ZEND_API zend_class_entry *zend_lookup_class(zend_string *name); ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *lcname, uint32_t flags); ZEND_API zend_class_entry *zend_get_called_scope(zend_execute_data *ex); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 0a7a7e3b15cec..e2b7e067ed0df 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -797,6 +797,10 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / const zend_op *current_opline_before_exception = EG(opline_before_exception); zend_init_func_execute_data(call, &func->op_array, fci->retval); + zend_instrument_fcall_cache *cache = ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } zend_execute_ex(call); EG(opline_before_exception) = current_opline_before_exception; if (call_via_handler) { @@ -807,12 +811,16 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) / int call_via_handler = (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0; ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION); + + if (UNEXPECTED(!ZEND_MAP_PTR_GET(func->common.instrument_cache))) { + zend_instrument_fcall_install(func); + } + ZVAL_NULL(fci->retval); call->prev_execute_data = EG(current_execute_data); EG(current_execute_data) = call; if (EXPECTED(zend_execute_internal == NULL)) { - /* saves one function call if zend_execute_internal is not used */ - func->internal_function.handler(call, fci->retval); + execute_internal(call, fci->retval); } else { zend_execute_internal(call, fci->retval); } diff --git a/Zend/zend_instrument.c b/Zend/zend_instrument.c new file mode 100644 index 0000000000000..2bf38d87ffd0e --- /dev/null +++ b/Zend/zend_instrument.c @@ -0,0 +1,133 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Levi Morrison | + | Sammy Kaye Powers | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "zend_API.h" +#include "zend_instrument.h" + +struct zend_instrument_fcall_init_list { + struct zend_instrument_fcall_init_list *prev; + zend_instrument_fcall_init instrument; +}; +typedef struct zend_instrument_fcall_init_list zend_instrument_fcall_init_list; + +static zend_instrument_fcall_init_list *zend_instrument_fcalls; + +ZEND_API void zend_instrument_init(void) { + zend_instrument_fcalls = NULL; +} + +ZEND_API void zend_instrument_shutdown(void) { + zend_instrument_fcall_init_list *curr, *prev; + for (curr = zend_instrument_fcalls; curr; curr = prev) { + prev = curr->prev; + free(curr); + } +} + +ZEND_API void zend_instrument_fcall_register(zend_instrument_fcall_init cb) { + zend_instrument_fcall_init_list *node = + malloc(sizeof(zend_instrument_fcall_init_list)); + node->instrument = cb; + node->prev = zend_instrument_fcalls; + zend_instrument_fcalls = node; +} + +struct zend_instrument_fcall_list { + struct zend_instrument_fcall_list *prev; + zend_instrument_fcall handlers; + size_t count; +}; +typedef struct zend_instrument_fcall_list zend_instrument_fcall_list; + + +extern inline void zend_instrument_fcall_call_begin( + zend_instrument_fcall_cache *cache, + zend_execute_data *execute_data); + +extern inline void zend_instrument_fcall_call_end( + zend_instrument_fcall_cache *cache, + zend_execute_data *execute_data, + zval *return_value); + +static zend_instrument_fcall_list *zend_instrument_fcall_add( + zend_instrument_fcall_list *instruments, + zend_instrument_fcall handlers) +{ + if (!handlers.begin && !handlers.end) { + return instruments; + } + + zend_instrument_fcall_list *n = + emalloc(sizeof(zend_instrument_fcall_list)); + if (instruments) { + n->prev = instruments; + n->count = instruments->count + 1; + } else { + n->prev = NULL; + n->count = 1; + } + n->handlers = handlers; + return n; +} + +static zend_instrument_fcall_cache *zend_instrument_fcall_list_attach( + zend_function *function, + zend_instrument_fcall_list *handlers_list) +{ + zend_instrument_fcall_cache *cache = + malloc(sizeof(zend_instrument_fcall_cache)); + cache->instruments_len = handlers_list->count; + cache->handlers = + calloc(handlers_list->count, sizeof(zend_instrument_fcall)); + + zend_instrument_fcall *handlers = cache->handlers; + zend_instrument_fcall_list *curr; + for (curr = handlers_list; curr; curr = curr->prev) { + *handlers++ = curr->handlers; + } + + ZEND_MAP_PTR_SET(function->common.instrument_cache, cache); + + return cache; +} + +ZEND_API void zend_instrument_fcall_install(zend_function *function) { + zend_instrument_fcall_list *fcall_list = NULL; + zend_instrument_fcall_init_list *elem; + + for (elem = zend_instrument_fcalls; elem; elem = elem->prev) { + zend_instrument_fcall handlers = elem->instrument(function); + fcall_list = zend_instrument_fcall_add(fcall_list, handlers); + } + + if (fcall_list) { + zend_instrument_fcall_list_attach(function, fcall_list); + + // cleanup fcall_list + zend_instrument_fcall_list *curr, *prev; + for (curr = fcall_list; curr; curr = prev) { + prev = curr->prev; + efree(curr); + } + } else { + ZEND_MAP_PTR_SET(function->common.instrument_cache, + ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED); + } +} diff --git a/Zend/zend_instrument.h b/Zend/zend_instrument.h new file mode 100644 index 0000000000000..9795a91800f02 --- /dev/null +++ b/Zend/zend_instrument.h @@ -0,0 +1,91 @@ +/* + +----------------------------------------------------------------------+ + | Zend Engine | + +----------------------------------------------------------------------+ + | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.00 of the Zend license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.zend.com/license/2_00.txt. | + | If you did not receive a copy of the Zend license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@zend.com so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Levi Morrison | + | Sammy Kaye Powers | + +----------------------------------------------------------------------+ +*/ + +#ifndef ZEND_INSTRUMENT_H +#define ZEND_INSTRUMENT_H + +BEGIN_EXTERN_C() + +struct zend_instrument_fcall { + void (*begin)(zend_execute_data *execute_data); + + /* todo: need to figure out how to tell end that it is exiting normally + * or not; checking for EG(exception) is not enough (unclean shutdown). + */ + void (*end)(zend_execute_data* execute_data, zval *return_value); +}; +typedef struct zend_instrument_fcall zend_instrument_fcall; + +struct zend_instrument_fcall_cache { + // todo: use arena + size_t instruments_len; + zend_instrument_fcall *handlers; +}; +typedef struct zend_instrument_fcall_cache zend_instrument_fcall_cache; + +/* If the fn should not be instrumented then return {NULL, NULL} */ +typedef zend_instrument_fcall (*zend_instrument_fcall_init)(zend_function *func); + +#define ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED ((void *) 1) + +// Call during minit/startup ONLY +ZEND_API void zend_instrument_fcall_register(zend_instrument_fcall_init cb); + +// Called by engine before MINITs +ZEND_API void zend_instrument_init(void); +ZEND_API void zend_instrument_shutdown(void); + +ZEND_API void zend_instrument_fcall_install(zend_function *function); + +inline void zend_instrument_fcall_call_begin( + zend_instrument_fcall_cache *cache, + zend_execute_data *execute_data) +{ + zend_instrument_fcall *handler; + zend_instrument_fcall *stop = + cache->handlers + cache->instruments_len; + + for (handler = cache->handlers; handler != stop; ++handler) { + if (handler->begin) { + handler->begin(execute_data); + } + } +} + +inline void zend_instrument_fcall_call_end( + zend_instrument_fcall_cache *cache, + zend_execute_data *execute_data, + zval *return_value) +{ + zend_instrument_fcall *handler = + cache->handlers + cache->instruments_len; + zend_instrument_fcall *stop = cache->handlers; + + // todo: send return_value to end, maybe protected via zval copy + // todo: decide if this should run in reverse order or not + while (handler-- != stop) { + if (handler->end) { + handler->end(execute_data, return_value); + } + } +} + +END_EXTERN_C() + +#endif /* ZEND_INSTRUMENT_H */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 7abc87d75ec7c..e5e61d0ad4831 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1204,6 +1204,8 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend * The low bit must be zero, to not be interpreted as a MAP_PTR offset. */ static const void *dummy = (void*)(intptr_t)2; + static const zend_instrument_fcall_cache *dummy_handlers = + ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; ZEND_ASSERT(fbc); @@ -1223,6 +1225,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend } func->opcodes = &EG(call_trampoline_op); ZEND_MAP_PTR_INIT(func->run_time_cache, (void***)&dummy); + ZEND_MAP_PTR_INIT(func->instrument_cache, (zend_instrument_fcall_cache **) &dummy_handlers); func->scope = fbc->common.scope; /* reserve space for arguments, local and temporary variables */ func->T = (fbc->type == ZEND_USER_FUNCTION)? MAX(fbc->op_array.last_var + fbc->op_array.T, 2) : 2; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 0dd42f8e6e1ba..a412dcd89cb7a 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -67,6 +67,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->arg_info = NULL; op_array->num_args = 0; op_array->required_num_args = 0; + ZEND_MAP_PTR_INIT(op_array->instrument_cache, NULL); op_array->scope = NULL; op_array->prototype = NULL; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index de0dfa2f357c3..ae1cad7ecaf94 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3468,6 +3468,9 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (OP2_TYPE != IS_CONST) { @@ -3592,6 +3595,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (OP2_TYPE != IS_CONST) { FREE_OP2(); } @@ -3608,6 +3614,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -3658,6 +3667,9 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, @@ -3770,6 +3782,9 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(func->common.instrument_cache))) { + zend_instrument_fcall_install(func); + } } else { zend_type_error("%s(): Argument #1 ($function) must be a valid callback, %s", Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), error); efree(error); @@ -3807,6 +3822,9 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } @@ -3837,6 +3855,9 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } @@ -3853,7 +3874,6 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) { USE_OPLINE zend_execute_data *call = EX(call); - zend_function *fbc = call->func; zval *ret; zval retval; @@ -3864,13 +3884,13 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL)) EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + zend_bool should_throw = zend_internal_call_should_throw(call->func, call); #endif ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -3919,6 +3939,13 @@ ZEND_VM_HOT_HANDLER(130, ZEND_DO_UCALL, ANY, ANY, SPEC(RETVAL)) call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -3943,6 +3970,13 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -3972,7 +4006,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL)) ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -4025,6 +4059,12 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + if (EXPECTED(zend_execute_ex == execute_ex)) { LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -4061,9 +4101,9 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL)) ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); + /* saves one function call if zend_execute_internal is not used */ if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); } else { zend_execute_internal(call, ret); } @@ -4230,6 +4270,16 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } @@ -5331,14 +5381,19 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N ZEND_VM_NEXT_OPCODE_EX(1, 2); } - /* Perform a dummy function call */ + /* Perform a dummy function call to evaluate arguments */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + static const zend_instrument_fcall_cache *dummy_handler = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(call->func->common.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handler); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(constructor->common.instrument_cache))) { + zend_instrument_fcall_install(constructor); + } /* We are not handling overloaded classes right now */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS, @@ -7317,6 +7372,18 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca } /* Uncaught exception */ + + if (execute_data->func) { + zend_function *func = execute_data->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zval undef; + ZVAL_UNDEF(&undef); + zend_instrument_fcall_call_end(cache, execute_data, &undef); + } + } + cleanup_live_vars(execute_data, op_num, 0); if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) { zend_generator *generator = zend_get_running_generator(EXECUTE_DATA_C); @@ -8107,6 +8174,9 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { @@ -8135,9 +8205,10 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY) } ZVAL_NULL(ret); + + /* saves one function call if zend_execute_internal is not used */ if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); } else { zend_execute_internal(call, ret); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 0bf16a6fee812..3a133bbbc9d20 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1216,7 +1216,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV { USE_OPLINE zend_execute_data *call = EX(call); - zend_function *fbc = call->func; zval *ret; zval retval; @@ -1227,13 +1226,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + zend_bool should_throw = zend_internal_call_should_throw(call->func, call); #endif ret = 0 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -1268,7 +1267,6 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV { USE_OPLINE zend_execute_data *call = EX(call); - zend_function *fbc = call->func; zval *ret; zval retval; @@ -1279,13 +1277,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV EG(current_execute_data) = call; #if ZEND_DEBUG - zend_bool should_throw = zend_internal_call_should_throw(fbc, call); + zend_bool should_throw = zend_internal_call_should_throw(call->func, call); #endif ret = 1 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -1334,6 +1332,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1357,6 +1362,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_UCALL_SPEC_RETV call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1381,6 +1393,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1410,7 +1429,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S ret = 0 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -1462,6 +1481,13 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S call->prev_execute_data = execute_data; execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); + + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1491,7 +1517,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S ret = 1 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); #if ZEND_DEBUG if (!EG(exception) && call->func) { @@ -1544,6 +1570,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + if (EXPECTED(zend_execute_ex == execute_ex)) { LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1580,9 +1612,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ret = 0 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); + /* saves one function call if zend_execute_internal is not used */ if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); } else { zend_execute_internal(call, ret); } @@ -1642,6 +1674,12 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 1 EXECUTE_DATA_CC); + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(fbc->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_begin(cache, call); + } + if (EXPECTED(zend_execute_ex == execute_ex)) { LOAD_OPLINE_EX(); ZEND_VM_ENTER_EX(); @@ -1678,9 +1716,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV ret = 1 ? EX_VAR(opline->result.var) : &retval; ZVAL_NULL(ret); + /* saves one function call if zend_execute_internal is not used */ if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); } else { zend_execute_internal(call, ret); } @@ -2522,6 +2560,18 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try } /* Uncaught exception */ + + if (execute_data->func) { + zend_function *func = execute_data->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zval undef; + ZVAL_UNDEF(&undef); + zend_instrument_fcall_call_end(cache, execute_data, &undef); + } + } + cleanup_live_vars(execute_data, op_num, 0); if (UNEXPECTED((EX_CALL_INFO() & ZEND_CALL_GENERATOR) != 0)) { zend_generator *generator = zend_get_running_generator(EXECUTE_DATA_C); @@ -2748,6 +2798,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z if (UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } execute_data = call; i_init_func_execute_data(&fbc->op_array, ret, 0 EXECUTE_DATA_CC); if (EXPECTED(zend_execute_ex == execute_ex)) { @@ -2776,9 +2829,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z } ZVAL_NULL(ret); + + /* saves one function call if zend_execute_internal is not used */ if (!zend_execute_internal) { - /* saves one function call if zend_execute_internal is not used */ - fbc->internal_function.handler(call, ret); + execute_internal(call, ret); } else { zend_execute_internal(call, ret); } @@ -2863,6 +2917,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, @@ -2949,6 +3006,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_NS_FCALL_BY_N if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } @@ -2979,6 +3039,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CO if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } CACHE_PTR(opline->result.num, fbc); } @@ -3523,6 +3586,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_ } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } @@ -5680,6 +5753,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CONST != IS_CONST) { @@ -5803,6 +5879,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CONST != IS_CONST) { } @@ -5819,6 +5898,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -5897,6 +5979,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(func->common.instrument_cache))) { + zend_instrument_fcall_install(func); + } } else { zend_type_error("%s(): Argument #1 ($function) must be a valid callback, %s", Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), error); efree(error); @@ -7855,6 +7940,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -7978,6 +8066,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); } @@ -7994,6 +8085,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -8073,6 +8167,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(func->common.instrument_cache))) { + zend_instrument_fcall_install(func); + } } else { zend_type_error("%s(): Argument #1 ($function) must be a valid callback, %s", Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), error); efree(error); @@ -8721,6 +8818,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_UNUSED != IS_CONST) { } @@ -8737,6 +8837,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -8876,14 +8979,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_CONST_UNUSED_HANDLER( ZEND_VM_NEXT_OPCODE_EX(1, 2); } - /* Perform a dummy function call */ + /* Perform a dummy function call to evaluate arguments */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + static const zend_instrument_fcall_cache *dummy_handler = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(call->func->common.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handler); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(constructor->common.instrument_cache))) { + zend_instrument_fcall_install(constructor); + } /* We are not handling overloaded classes right now */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS, @@ -10111,6 +10219,9 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_ if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CV != IS_CONST) { @@ -10234,6 +10345,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CV != IS_CONST) { } @@ -10250,6 +10364,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -10328,6 +10445,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&func->op_array))) { init_func_run_time_cache(&func->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(func->common.instrument_cache))) { + zend_instrument_fcall_install(func); + } } else { zend_type_error("%s(): Argument #1 ($function) must be a valid callback, %s", Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), error); efree(error); @@ -14401,6 +14521,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CONST != IS_CONST) { @@ -15782,6 +15905,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_T if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -17057,6 +17183,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_TMPVAR_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CV != IS_CONST) { @@ -17377,6 +17506,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HA } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } @@ -19799,6 +19938,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HA } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } @@ -22716,6 +22865,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CONST != IS_CONST) { } @@ -22732,6 +22884,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -24946,6 +25101,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); } @@ -24962,6 +25120,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -26218,6 +26379,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_UNUSED != IS_CONST) { } @@ -26234,6 +26398,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -26373,14 +26540,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_VAR_UNUSED_HANDLER(ZE ZEND_VM_NEXT_OPCODE_EX(1, 2); } - /* Perform a dummy function call */ + /* Perform a dummy function call to evaluate arguments */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + static const zend_instrument_fcall_cache *dummy_handler = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(call->func->common.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handler); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(constructor->common.instrument_cache))) { + zend_instrument_fcall_install(constructor); + } /* We are not handling overloaded classes right now */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS, @@ -28471,6 +28643,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CV != IS_CONST) { } @@ -28487,6 +28662,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_V if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -30533,6 +30711,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CONST != IS_CONST) { @@ -30656,6 +30837,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CONST != IS_CONST) { } @@ -30672,6 +30856,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -32401,6 +32588,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_T if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -32524,6 +32714,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); } @@ -32540,6 +32733,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -32940,6 +33136,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_UNUSED != IS_CONST) { } @@ -32956,6 +33155,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -33095,14 +33297,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NEW_SPEC_UNUSED_UNUSED_HANDLER ZEND_VM_NEXT_OPCODE_EX(1, 2); } - /* Perform a dummy function call */ + /* Perform a dummy function call to evaluate arguments */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + static const zend_instrument_fcall_cache *dummy_handler = ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED; + ZEND_MAP_PTR_INIT(call->func->common.instrument_cache, (zend_instrument_fcall_cache **) &dummy_handler); } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(constructor->common.instrument_cache))) { + zend_instrument_fcall_install(constructor); + } /* We are not handling overloaded classes right now */ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION | ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS, @@ -34795,6 +35002,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_UNUSED_C if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CV != IS_CONST) { @@ -34918,6 +35128,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } if (IS_CV != IS_CONST) { } @@ -34934,6 +35147,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_STATIC_METHOD_CALL_SPEC_U if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (!(fbc->common.fn_flags & ZEND_ACC_STATIC)) { @@ -35732,6 +35948,16 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HAN } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } @@ -39643,6 +39869,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_S if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CONST != IS_CONST) { @@ -43080,6 +43309,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_TMPVA if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if ((IS_TMP_VAR|IS_VAR) != IS_CONST) { @@ -47962,6 +48194,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_METHOD_CALL_SPEC_CV_CV_HA if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); } + if (UNEXPECTED(!ZEND_MAP_PTR_GET(fbc->common.instrument_cache))) { + zend_instrument_fcall_install(fbc); + } } if (IS_CV != IS_CONST) { @@ -52297,6 +52532,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + goto zend_leave_helper_SPEC_LABEL; } @@ -53782,6 +54027,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + goto zend_leave_helper_SPEC_LABEL; } @@ -54059,6 +54314,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + goto zend_leave_helper_SPEC_LABEL; } @@ -55124,6 +55389,16 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } } + + if (EG(current_execute_data)->func) { + zend_function *func = EG(current_execute_data)->func; + zend_instrument_fcall_cache *cache = + ZEND_MAP_PTR_GET(func->common.instrument_cache); + if (cache != ZEND_INSTRUMENT_FCALL_NOT_INSTRUMENTED) { + zend_instrument_fcall_call_end(cache, EG(current_execute_data), return_value); + } + } + goto zend_leave_helper_SPEC_LABEL; } diff --git a/configure.ac b/configure.ac index 5278718f1a7e3..1ef4417454466 100644 --- a/configure.ac +++ b/configure.ac @@ -1462,7 +1462,8 @@ PHP_ADD_SOURCES(Zend, \ zend_iterators.c zend_interfaces.c zend_exceptions.c zend_strtod.c zend_gc.c \ zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \ zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \ - zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c, \ + zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \ + zend_instrument.c, \ -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) dnl Selectively disable optimization due to high RAM usage during compiling the diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 131fc8495b910..90c002c654cc5 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -202,6 +202,9 @@ static void zend_hash_clone_methods(HashTable *ht) if (IN_ARENA(ZEND_MAP_PTR(new_entry->run_time_cache))) { ZEND_MAP_PTR_INIT(new_entry->run_time_cache, ARENA_REALLOC(ZEND_MAP_PTR(new_entry->run_time_cache))); } + if (IN_ARENA(ZEND_MAP_PTR(new_entry->instrument_cache))) { + ZEND_MAP_PTR_INIT(new_entry->instrument_cache, ARENA_REALLOC(ZEND_MAP_PTR(new_entry->instrument_cache))); + } ZEND_MAP_PTR_INIT(new_entry->static_variables_ptr, &new_entry->static_variables); } } diff --git a/ext/opcache/zend_persist.c b/ext/opcache/zend_persist.c index 6a158e73f9e33..64421d089ec38 100644 --- a/ext/opcache/zend_persist.c +++ b/ext/opcache/zend_persist.c @@ -584,6 +584,7 @@ static void zend_persist_op_array(zval *zv) if (!ZCG(current_persistent_script)->corrupted) { op_array->fn_flags |= ZEND_ACC_IMMUTABLE; ZEND_MAP_PTR_NEW(op_array->run_time_cache); + ZEND_MAP_PTR_NEW(op_array->instrument_cache); if (op_array->static_variables) { ZEND_MAP_PTR_NEW(op_array->static_variables_ptr); } @@ -591,6 +592,8 @@ static void zend_persist_op_array(zval *zv) ZEND_MAP_PTR_INIT(op_array->run_time_cache, ZCG(arena_mem)); ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*))); ZEND_MAP_PTR_SET(op_array->run_time_cache, NULL); + ZCG(arena_mem) = (void*)(((char*)ZCG(arena_mem)) + ZEND_ALIGNED_SIZE(sizeof(void*))); + ZEND_MAP_PTR_SET(op_array->instrument_cache, NULL); } } diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 769fe25f9d832..7f8d0205c50d6 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1238,6 +1238,10 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind) func.num_args = 0; func.required_num_args = 0; } + + ZEND_MAP_PTR_INIT(func.instrument_cache, zend_arena_alloc(&CG(arena), sizeof(void*))); + ZEND_MAP_PTR_SET(func.instrument_cache, NULL); + zend_set_function_arg_flags((zend_function*)&func); namelen = strlen(funcs->fname); lc_name = emalloc(namelen+1); diff --git a/main/main.c b/main/main.c index 6143718d05d42..5a2cfed6e69b4 100644 --- a/main/main.c +++ b/main/main.c @@ -71,6 +71,7 @@ #include "zend_highlight.h" #include "zend_extensions.h" #include "zend_ini.h" +#include "zend_instrument.h" #include "zend_dtrace.h" #include "php_content_types.h" @@ -2297,6 +2298,7 @@ int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_mod ahead of all other internals */ php_ini_register_extensions(); + zend_instrument_init(); zend_startup_modules(); /* start Zend extensions */ @@ -2495,6 +2497,8 @@ void php_module_shutdown(void) _set_invalid_parameter_handler(old_invalid_parameter_handler); } #endif + + zend_instrument_shutdown(); } /* }}} */ diff --git a/win32/build/config.w32 b/win32/build/config.w32 index 62dbeb40d9b08..5f3b7b2b308ce 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -236,7 +236,7 @@ ADD_SOURCES("Zend", "zend_language_parser.c zend_language_scanner.c \ zend_object_handlers.c zend_objects_API.c \ zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \ zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \ - zend_inheritance.c zend_smart_str.c zend_cpuinfo.c"); + zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_instrument.c"); ADD_FLAG("CFLAGS_BD_ZEND", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); if (VS_TOOLSET && VCVERS >= 1914) {