mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Pass zend_execute_data instead of zend_function to fcall init
The motivation for this change is to prevent extensions from having to check executor globals for the current execute_data during function call init. A previous implementation of the observer API initialized the function call from runtime cache initialization before execute_data was allocated which is why zend_function was passed in. But now that the observer API is implemented via opcode specialization, it makes sense to pass in the execute_data. This also keeps the API a bit more consistent for existing extensions that already hook zend_execute_ex. Closes GH-6209
This commit is contained in:
parent
a91cb2f48c
commit
e42abeafec
4 changed files with 139 additions and 6 deletions
|
@ -89,9 +89,10 @@ ZEND_API void zend_observer_shutdown(void) {
|
||||||
zend_llist_destroy(&zend_observer_error_callbacks);
|
zend_llist_destroy(&zend_observer_error_callbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zend_observer_fcall_install(zend_function *function) {
|
static void zend_observer_fcall_install(zend_execute_data *execute_data) {
|
||||||
zend_llist_element *element;
|
zend_llist_element *element;
|
||||||
zend_llist *list = &zend_observers_fcall_list;
|
zend_llist *list = &zend_observers_fcall_list;
|
||||||
|
zend_function *function = execute_data->func;
|
||||||
zend_op_array *op_array = &function->op_array;
|
zend_op_array *op_array = &function->op_array;
|
||||||
|
|
||||||
if (fcall_handlers_arena == NULL) {
|
if (fcall_handlers_arena == NULL) {
|
||||||
|
@ -105,7 +106,7 @@ static void zend_observer_fcall_install(zend_function *function) {
|
||||||
for (element = list->head; element; element = element->next) {
|
for (element = list->head; element; element = element->next) {
|
||||||
zend_observer_fcall_init init;
|
zend_observer_fcall_init init;
|
||||||
memcpy(&init, element->data, sizeof init);
|
memcpy(&init, element->data, sizeof init);
|
||||||
zend_observer_fcall_handlers handlers = init(function);
|
zend_observer_fcall_handlers handlers = init(execute_data);
|
||||||
if (handlers.begin || handlers.end) {
|
if (handlers.begin || handlers.end) {
|
||||||
zend_llist_add_element(&handlers_list, &handlers);
|
zend_llist_add_element(&handlers_list, &handlers);
|
||||||
}
|
}
|
||||||
|
@ -150,7 +151,7 @@ static void ZEND_FASTCALL _zend_observe_fcall_begin(zend_execute_data *execute_d
|
||||||
|
|
||||||
fcall_data = ZEND_OBSERVER_DATA(op_array);
|
fcall_data = ZEND_OBSERVER_DATA(op_array);
|
||||||
if (!fcall_data) {
|
if (!fcall_data) {
|
||||||
zend_observer_fcall_install((zend_function *)op_array);
|
zend_observer_fcall_install(execute_data);
|
||||||
fcall_data = ZEND_OBSERVER_DATA(op_array);
|
fcall_data = ZEND_OBSERVER_DATA(op_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ typedef struct _zend_observer_fcall_handlers {
|
||||||
} zend_observer_fcall_handlers;
|
} zend_observer_fcall_handlers;
|
||||||
|
|
||||||
/* If the fn should not be observed then return {NULL, NULL} */
|
/* If the fn should not be observed then return {NULL, NULL} */
|
||||||
typedef zend_observer_fcall_handlers (*zend_observer_fcall_init)(zend_function *func);
|
typedef zend_observer_fcall_handlers (*zend_observer_fcall_init)(zend_execute_data *execute_data);
|
||||||
|
|
||||||
// Call during minit/startup ONLY
|
// Call during minit/startup ONLY
|
||||||
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init);
|
ZEND_API void zend_observer_fcall_register(zend_observer_fcall_init);
|
||||||
|
|
|
@ -36,6 +36,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
|
||||||
int observer_observe_functions;
|
int observer_observe_functions;
|
||||||
int observer_show_return_type;
|
int observer_show_return_type;
|
||||||
int observer_show_return_value;
|
int observer_show_return_value;
|
||||||
|
int observer_show_init_backtrace;
|
||||||
int observer_nesting_depth;
|
int observer_nesting_depth;
|
||||||
ZEND_END_MODULE_GLOBALS(zend_test)
|
ZEND_END_MODULE_GLOBALS(zend_test)
|
||||||
|
|
||||||
|
@ -315,9 +316,10 @@ PHP_INI_BEGIN()
|
||||||
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
|
STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
|
||||||
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_type", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_type, zend_zend_test_globals, zend_test_globals)
|
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_type", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_type, zend_zend_test_globals, zend_test_globals)
|
||||||
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
|
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
|
||||||
|
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
|
||||||
PHP_INI_END()
|
PHP_INI_END()
|
||||||
|
|
||||||
static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc);
|
static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
|
||||||
|
|
||||||
PHP_MINIT_FUNCTION(zend_test)
|
PHP_MINIT_FUNCTION(zend_test)
|
||||||
{
|
{
|
||||||
|
@ -498,10 +500,34 @@ static void observer_show_init(zend_function *fbc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static zend_observer_fcall_handlers observer_fcall_init(zend_function *fbc)
|
static void observer_show_init_backtrace(zend_execute_data *execute_data)
|
||||||
{
|
{
|
||||||
|
zend_execute_data *ex = execute_data;
|
||||||
|
php_printf("%*s<!--\n", 2 * ZT_G(observer_nesting_depth), "");
|
||||||
|
do {
|
||||||
|
zend_function *fbc = ex->func;
|
||||||
|
int indent = 2 * ZT_G(observer_nesting_depth) + 4;
|
||||||
|
if (fbc->common.function_name) {
|
||||||
|
if (fbc->common.scope) {
|
||||||
|
php_printf("%*s%s::%s()\n", indent, "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
|
||||||
|
} else {
|
||||||
|
php_printf("%*s%s()\n", indent, "", ZSTR_VAL(fbc->common.function_name));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
php_printf("%*s{main} %s\n", indent, "", ZSTR_VAL(fbc->op_array.filename));
|
||||||
|
}
|
||||||
|
} while ((ex = ex->prev_execute_data) != NULL);
|
||||||
|
php_printf("%*s-->\n", 2 * ZT_G(observer_nesting_depth), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data)
|
||||||
|
{
|
||||||
|
zend_function *fbc = execute_data->func;
|
||||||
if (ZT_G(observer_show_output)) {
|
if (ZT_G(observer_show_output)) {
|
||||||
observer_show_init(fbc);
|
observer_show_init(fbc);
|
||||||
|
if (ZT_G(observer_show_init_backtrace)) {
|
||||||
|
observer_show_init_backtrace(execute_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ZT_G(observer_observe_all)) {
|
if (ZT_G(observer_observe_all)) {
|
||||||
|
|
106
ext/zend_test/tests/observer_backtrace_01.phpt
Normal file
106
ext/zend_test/tests/observer_backtrace_01.phpt
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
--TEST--
|
||||||
|
Observer: Show backtrace on init
|
||||||
|
--SKIPIF--
|
||||||
|
<?php if (!extension_loaded('zend-test')) die('skip: zend-test extension required'); ?>
|
||||||
|
--INI--
|
||||||
|
zend_test.observer.enabled=1
|
||||||
|
zend_test.observer.observe_all=1
|
||||||
|
zend_test.observer.show_init_backtrace=1
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class TestClass
|
||||||
|
{
|
||||||
|
private function bar($number)
|
||||||
|
{
|
||||||
|
return $number + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function foo()
|
||||||
|
{
|
||||||
|
return array_map(function ($value) {
|
||||||
|
return $this->bar($value);
|
||||||
|
}, [40, 1335]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function gen()
|
||||||
|
{
|
||||||
|
$test = new TestClass();
|
||||||
|
yield $test->foo();
|
||||||
|
}
|
||||||
|
|
||||||
|
function foo()
|
||||||
|
{
|
||||||
|
return gen()->current();
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(foo());
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
<!-- init '%s/observer_backtrace_%d.php' -->
|
||||||
|
<!--
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<file '%s/observer_backtrace_%d.php'>
|
||||||
|
<!-- init foo() -->
|
||||||
|
<!--
|
||||||
|
foo()
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<foo>
|
||||||
|
<!-- init gen() -->
|
||||||
|
<!--
|
||||||
|
gen()
|
||||||
|
Generator::current()
|
||||||
|
foo()
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<gen>
|
||||||
|
<!-- init TestClass::foo() -->
|
||||||
|
<!--
|
||||||
|
TestClass::foo()
|
||||||
|
gen()
|
||||||
|
Generator::current()
|
||||||
|
foo()
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<TestClass::foo>
|
||||||
|
<!-- init TestClass::{closure}() -->
|
||||||
|
<!--
|
||||||
|
TestClass::{closure}()
|
||||||
|
array_map()
|
||||||
|
TestClass::foo()
|
||||||
|
gen()
|
||||||
|
Generator::current()
|
||||||
|
foo()
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<TestClass::{closure}>
|
||||||
|
<!-- init TestClass::bar() -->
|
||||||
|
<!--
|
||||||
|
TestClass::bar()
|
||||||
|
TestClass::{closure}()
|
||||||
|
array_map()
|
||||||
|
TestClass::foo()
|
||||||
|
gen()
|
||||||
|
Generator::current()
|
||||||
|
foo()
|
||||||
|
{main} %s/observer_backtrace_%d.php
|
||||||
|
-->
|
||||||
|
<TestClass::bar>
|
||||||
|
</TestClass::bar>
|
||||||
|
</TestClass::{closure}>
|
||||||
|
<TestClass::{closure}>
|
||||||
|
<TestClass::bar>
|
||||||
|
</TestClass::bar>
|
||||||
|
</TestClass::{closure}>
|
||||||
|
</TestClass::foo>
|
||||||
|
</gen>
|
||||||
|
</foo>
|
||||||
|
array(2) {
|
||||||
|
[0]=>
|
||||||
|
int(42)
|
||||||
|
[1]=>
|
||||||
|
int(1337)
|
||||||
|
}
|
||||||
|
</file '%s/observer_backtrace_%d.php'>
|
Loading…
Add table
Add a link
Reference in a new issue