diff options
Diffstat (limited to 'Zend/zend_observer.c')
-rw-r--r-- | Zend/zend_observer.c | 128 |
1 files changed, 88 insertions, 40 deletions
diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index b124de5cc3..5544039c3e 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -23,6 +23,21 @@ #include "zend_llist.h" #include "zend_vm.h" +#define ZEND_OBSERVER_DATA(op_array) \ + ZEND_OP_ARRAY_EXTENSION(op_array, zend_observer_fcall_op_array_extension) + +#define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2) + +#define ZEND_OBSERVABLE_FN(fn_flags) \ + (!(fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_FAKE_CLOSURE))) + +typedef struct _zend_observer_fcall_data { + // points after the last handler + zend_observer_fcall_handlers *end; + // a variadic array using "struct hack" + zend_observer_fcall_handlers handlers[1]; +} zend_observer_fcall_data; + zend_llist zend_observers_fcall_list; zend_llist zend_observer_error_callbacks; @@ -30,12 +45,6 @@ int zend_observer_fcall_op_array_extension = -1; ZEND_TLS zend_arena *fcall_handlers_arena = NULL; -ZEND_API extern inline void zend_observer_maybe_fcall_call_begin( - zend_execute_data *execute_data); -ZEND_API extern inline void zend_observer_maybe_fcall_call_end( - zend_execute_data *execute_data, - zval *return_value); - // Call during minit/startup ONLY ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init init) { /* We don't want to get an extension handle unless an ext installs an observer */ @@ -80,7 +89,7 @@ ZEND_API void zend_observer_shutdown(void) { zend_llist_destroy(&zend_observer_error_callbacks); } -ZEND_API void zend_observer_fcall_install(zend_function *function) { +static void zend_observer_fcall_install(zend_function *function) { zend_llist_element *element; zend_llist *list = &zend_observers_fcall_list; zend_op_array *op_array = &function->op_array; @@ -92,11 +101,11 @@ ZEND_API void zend_observer_fcall_install(zend_function *function) { ZEND_ASSERT(function->type != ZEND_INTERNAL_FUNCTION); zend_llist handlers_list; - zend_llist_init(&handlers_list, sizeof(zend_observer_fcall), NULL, 0); + zend_llist_init(&handlers_list, sizeof(zend_observer_fcall_handlers), NULL, 0); for (element = list->head; element; element = element->next) { zend_observer_fcall_init init; memcpy(&init, element->data, sizeof init); - zend_observer_fcall handlers = init(function); + zend_observer_fcall_handlers handlers = init(function); if (handlers.begin || handlers.end) { zend_llist_add_element(&handlers_list, &handlers); } @@ -105,58 +114,97 @@ ZEND_API void zend_observer_fcall_install(zend_function *function) { ZEND_ASSERT(RUN_TIME_CACHE(op_array)); void *ext; if (handlers_list.count) { - size_t size = sizeof(zend_observer_fcall_cache) + (handlers_list.count - 1) * sizeof(zend_observer_fcall); - zend_observer_fcall_cache *cache = zend_arena_alloc(&fcall_handlers_arena, size); - zend_observer_fcall *handler = cache->handlers; + size_t size = sizeof(zend_observer_fcall_data) + (handlers_list.count - 1) * sizeof(zend_observer_fcall_handlers); + zend_observer_fcall_data *fcall_data = zend_arena_alloc(&fcall_handlers_arena, size); + zend_observer_fcall_handlers *handlers = fcall_data->handlers; for (element = handlers_list.head; element; element = element->next) { - memcpy(handler++, element->data, sizeof *handler); + memcpy(handlers++, element->data, sizeof *handlers); } - cache->end = handler; - ext = cache; + fcall_data->end = handlers; + ext = fcall_data; } else { ext = ZEND_OBSERVER_NOT_OBSERVED; } - ZEND_OBSERVER_HANDLERS(op_array) = ext; + ZEND_OBSERVER_DATA(op_array) = ext; zend_llist_destroy(&handlers_list); } -ZEND_API void zend_observe_fcall_begin( - zend_observer_fcall_cache *cache, - zend_execute_data *execute_data) +static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_data) { - zend_observer_fcall *handler, *end = cache->end; - for (handler = cache->handlers; handler != end; ++handler) { - if (handler->begin) { - handler->begin(execute_data); + zend_op_array *op_array; + uint32_t fn_flags; + zend_observer_fcall_data *fcall_data; + zend_observer_fcall_handlers *handlers, *end; + + if (!ZEND_OBSERVER_ENABLED) { + return; + } + + op_array = &execute_data->func->op_array; + fn_flags = op_array->fn_flags; + + if (!ZEND_OBSERVABLE_FN(fn_flags)) { + return; + } + + fcall_data = ZEND_OBSERVER_DATA(op_array); + if (!fcall_data) { + zend_observer_fcall_install((zend_function *)op_array); + fcall_data = ZEND_OBSERVER_DATA(op_array); + } + + ZEND_ASSERT(fcall_data); + if (fcall_data == ZEND_OBSERVER_NOT_OBSERVED) { + return; + } + + end = fcall_data->end; + for (handlers = fcall_data->handlers; handlers != end; ++handlers) { + if (handlers->begin) { + handlers->begin(execute_data); } } } -ZEND_API void zend_observer_fcall_call_end_helper( - zend_execute_data *execute_data, - zval *return_value) +ZEND_API void ZEND_FASTCALL zend_observer_generator_resume(zend_execute_data *execute_data) { - zend_function *func = execute_data->func; - ZEND_ASSUME(ZEND_OBSERVABLE_FN(func->common.fn_flags)); - void *observer_handlers = ZEND_OBSERVER_HANDLERS(&func->op_array); - // TODO: Fix exceptions from generators - // ZEND_ASSERT(observer_handlers); - if (observer_handlers && observer_handlers != ZEND_OBSERVER_NOT_OBSERVED) { - zend_observer_fcall_cache *cache = observer_handlers; - zend_observe_fcall_end(cache, execute_data, return_value); + _zend_observe_fcall_begin(execute_data); +} + +ZEND_API void ZEND_FASTCALL zend_observer_fcall_begin(zend_execute_data *execute_data) +{ + ZEND_ASSUME(execute_data->func); + if (!(execute_data->func->common.fn_flags & ZEND_ACC_GENERATOR)) { + _zend_observe_fcall_begin(execute_data); } } -ZEND_API void zend_observe_fcall_end( - zend_observer_fcall_cache *cache, +ZEND_API void ZEND_FASTCALL zend_observer_fcall_end( zend_execute_data *execute_data, zval *return_value) { - zend_observer_fcall *handler = cache->end, *end = cache->handlers; - while (handler-- != end) { - if (handler->end) { - handler->end(execute_data, return_value); + zend_function *func = execute_data->func; + zend_observer_fcall_data *fcall_data; + zend_observer_fcall_handlers *handlers, *end; + + if (!ZEND_OBSERVER_ENABLED + || !ZEND_OBSERVABLE_FN(func->common.fn_flags)) { + return; + } + + fcall_data = (zend_observer_fcall_data*)ZEND_OBSERVER_DATA(&func->op_array); + // TODO: Fix exceptions from generators + // ZEND_ASSERT(fcall_data); + if (!fcall_data || fcall_data == ZEND_OBSERVER_NOT_OBSERVED) { + return; + } + + handlers = fcall_data->end; + end = fcall_data->handlers; + while (handlers-- != end) { + if (handlers->end) { + handlers->end(execute_data, return_value); } } } |