summaryrefslogtreecommitdiff
path: root/Zend/zend_observer.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_observer.c')
-rw-r--r--Zend/zend_observer.c128
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);
}
}
}