Inline the lookup whether a function is observed at all.
This strategy is also used for FRAMELESS calls. If the frameless call is observed, we instead allocate a call frame and push the arguments, to call the the function afterwards.
Doing so is still a performance benefit as opposed to executing individual INIT_FCALL+SEND_VAL ops. Thus, even if the frameless call turns out to be observed, the call overhead is slightly lower than before.
If the internal function is not observed at all, the unavoidable overhead is fetching the FLF zend_function pointer and the run-time cache needs to be inspected.
As part of this work, it turned out to be most viable to put the result operand on the ZEND_OP_DATA instead of ZEND_FRAMELESS_ICALL_3, allowing seamless interoperability with the DO_ICALL opcode.
This is a bit unusual in comparison to all other ZEND_OP_DATA usages, but seems to not pose problems overall.
There is also a small issue resolved: trampolines would always use the ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER function due to zend_observer_fcall_op_array_extension being set to -1 too late.
* Mark many functions as static
Multiple functions are missing the static qualifier.
* remove unused struct sigactions
struct sigaction act, old_term, old_quit, old_int;
all unused.
* optimizer: minXOR and maxXOR are unused
`zend_call_method_with_1_params()` causes needless overhead, due to the
capability of looking up the function by name. It’s also very rarely used (only
in ext/spl).
`zend_call_known_function()` is the standard methodology to call a known
function and going through `Z_OBJCE_P()` avoids the repeated hardcoding of the
CE name.
* Make sure core module has number 0
Some places, possibly also outside PHP, assume the core extension has
module number 0. After 8a812c3fda this wasn't the case anymore as
reported in [1]. Fix it by changing how the next module ID is computed.
[1] https://github.com/php/php-src/pull/12246#issuecomment-1731432377
* Add assertion
* Add test
When we try to load an extension multiple times, we still overwrite the
type, module number, and handle. If the module number is used to
indicate module boundaries (e.g. in reflection and in dom, see e.g.
dom_objects_set_class_ex), then all sorts of errors can happen.
In the case of ext/dom, OP's error happens because the following
happens:
- The property handler is set up incorrectly in
dom_objects_set_class_ex() because the wrong module number is
specified. The class highest in the hierarchy is DOMNode, so the
property handler is incorrectly set to that of DOMNode instead of
DOMDocument.
- The documentElement property doesn't exist on DOMNode, it only exists
on DOMDocument, so it tries to read using zend_std_read_property().
As there is no user property called documentElement, that read
operation returns an undef value.
However, the type is still checked, resulting in the strange exception.
Solve this by changing the API such that the data is only overwritten if
it's owned data.
Closes GH-12246.
We can't increase the refcount of internal classes during request time.
To work around this problem we simply don't refcount aliases anymore and
add a check in the destruction to skip aliases entirely.
There were also some checks which checked for an alias implicitly by
comparing the refcount, these have been replaced by checking the type of
the zval instead.
This occurs because the array of properties is a single element with an
integer key, not an associative array. Therefore it is a packed array
and thus the assumption the iteration macro makes is invalid.
This restores the behaviour of PHP<8.2.
Closes GH-10209
Co-authored-by: Deltik <deltik@gmx.com>
Signed-off-by: George Peter Banyard <girgias@php.net>
This occurs because the array of properties is a single element with an
integer key, not an associative array. Therefore it is a packed array
and thus the assumption the iteration macro makes is invalid.
This restores the behaviour of PHP<8.2.
Closes GH-10209
Co-authored-by: Deltik <deltik@gmx.com>
Signed-off-by: George Peter Banyard <girgias@php.net>
- running: true if garbage collection is currently running
- protected: true if the garbage collector is protected and root
additions are forbidden
- full: true if the garbage collector buffer size exceeds GC_MAX_BUF_SIZE
- buffer_size: current garbage collector buffer size
Documentation for existing fields:
- runs: the number of times the garbage collector has been run
- collected: the number of objects collected
- threshold: the number of roots in the buffer which will trigger
garbage collection
- roots: the current number of roots in the buffer
Updated manual example output:
array(8) {
["running"]=>
bool(false)
["protected"]=>
bool(false)
["full"]=>
bool(false)
["runs"]=>
int(5)
["collected"]=>
int(100002)
["threshold"]=>
int(50001)
["buffer_size"]=>
int(131072)
["roots"]=>
int(0)
}
* Support the `#[\AllowDynamicProperties]` attribute in stubs
* Use `#[\AllowDynamicProperties]` attribute in stubs
* Disallow applying both `@strict-properties` and `#[\AllowDynamicProperties]`
- for packed arrays we store just an array of zvals without keys.
- the elements of packed array are accessible throuf as ht->arPacked[i]
instead of ht->arData[i]
- in addition to general ZEND_HASH_FOREACH_* macros, we introduced similar
familied for packed (ZEND_HASH_PACKED_FORECH_*) and real hashes
(ZEND_HASH_MAP_FOREACH_*)
- introduced an additional family of macros to access elements of array
(packed or real hashes) ZEND_ARRAY_ELEMET_SIZE, ZEND_ARRAY_ELEMET_EX,
ZEND_ARRAY_ELEMET, ZEND_ARRAY_NEXT_ELEMENT, ZEND_ARRAY_PREV_ELEMENT
- zend_hash_minmax() prototype was changed to compare only values
Because of smaller data set, this patch may show performance improvement
on some apps and benchmarks that use packed arrays. (~1% on PHP-Parser)
TODO:
- sapi/phpdbg needs special support for packed arrays (WATCH_ON_BUCKET).
- zend_hash_sort_ex() may require converting packed arrays to hash.
Convert zend_hash_find_ex(..., 1) to zend_hash_find_known_hash(...)
Convert zend_hash_find_ex(..., 0) to zend_hash_find(...)
Also add serializable changes to UPGRADING.INTERNALS summary
This makes debug_print_backtrace() use the same formatting as exception
backtraces. The only difference is that the final #{main} is omitted,
because it wouldn't make sense for limited backtraces, and wasn't there
previously either.