op1 of ZEND_MATCH_ERROR, which refers to the match expression, is not freed by
MATCH_ERROR itself. Instead, it is freed by ZEND_HANDLE_EXCEPTION. For normal
control flow, a FREE is placed at the end of the match expression.
Since FREE may appear after MATCH_ERROR in the opcode sequence, we need to
correctly handle op1 of MATCH_ERROR as alive.
Fixes GH-17106
Closes GH-17108
- GH-11958: DNF types in trait properties do not get bound properly
- GH-11883: Memory leak in zend_type_release() for non-arena allocated DNF types
- Internal trait bound to userland class would not be arena allocated
- Property DNF types were not properly deep copied during lazy loading
Co-authored-by: Ilija Tovilo <ilija.tovilo@me.com>
Co-authored-by: ju1ius <jules.bernable@gmail.com>
`zend_uchar` suggests that the value is an ASCII character, but here,
it's about very small integers. This is misleading, so let's use a
C99 integer instead.
On all architectures currently supported by PHP, `zend_uchar` and
`uint8_t` are identical. This change is only about code readability.
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 avoids a possible significant performance penalty, when some leaf function was observed, deep in the stack.
As a side effect, we are not iterating over prev_execute_data anymore and thus, non-observed fake frames, possibly on stack, cannot have any impact on the observer anymore (especially within zend_observer_fcall_end_all).
Saving the previous observer happens now directly on the VM stack. If there is any observer, function frames are allocated an extra zval (the last temporary), which will, on observed frames, contain the previous observed frame address.
==109253== 280 (56 direct, 224 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==109253== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==109253== by 0x6D9FA2: __zend_malloc (zend_alloc.c:3068)
==109253== by 0x745138: zend_add_attribute (zend_attributes.c:226)
==109253== by 0x6680D1: zend_add_parameter_attribute (zend_attributes.h:102)
==109253== by 0x66B787: zm_startup_zend_test (test.c:478)
==109253== by 0x7224CD: zend_startup_module_ex (zend_API.c:2202)
==109253== by 0x72252C: zend_startup_module_zval (zend_API.c:2217)
==109253== by 0x734288: zend_hash_apply (zend_hash.c:2011)
==109253== by 0x722C30: zend_startup_modules (zend_API.c:2328)
==109253== by 0x67409B: php_module_startup (main.c:2256)
==109253== by 0x88EDDE: php_cli_startup (php_cli.c:409)
==109253== by 0x890F61: main (php_cli.c:1334)
While JMPZNZ can avoid execution of a separate JMP opcode in some
cases, it also prevents smart branch optimization, so creating
JMPZNZ may actually have a negative effect. It also adds additional
complexity for optimizations.
Drop JMPZNZ in favor of JMPZ+JMP or JMPNZ+JMP.
Closes GH-7857.
Previously, code such as subclasses of SplFixedArray would check for method
overrides when instantiating the objects.
This optimization was mentioned as a followup to GH-6552
Class constants from parents should always be directly reused,
rather than re-evaluated as a separate copy. Previously this used
to happen automatically, as we'd just inherit the class constant
entry from the parent class. With mutable data there may now be
a separate copy of the constant, so we need to use that copy
when updating constants. Otherwise we may evaluate the same
constant multiple times.
Closes GH-7658.
- 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.
This can happen in degenerate cases where we know that the
SWITCH_STRING argument is not refcounted. We should be treating it
in the same way as SWITCH_LONG here.
Currently, classes that can't be linked get moved back into the original script
and are not preloaded. As such classes may be referenced from functions that
did get preloaded, there is a preload autoload mechanism to load them at
runtime.
Since PHP 8.1, we can safely preload unlinked classes, which will then go
through usual lazy loading. This means that we no longer need the preload
autoload mechanism. However, we need to be careful not to modify any hash
table buckets in-place, and should create new buckets for lazy loaded classes.
This adds support for internal enums with the same basic approach
as userland enums. Enum values are stored as CONSTANT_AST and
objects created during constant updating at runtime. This means
that we need to use mutable_data for internal enums.
This just adds basic support and APIs, it does not include the
stubs integration from #7212.
Closes GH-7302.
static_members, mutable_data and static vars in methods are cleaned
up during an earlier shutdown phase (because this has to happen
before we destroy the object store). There is no need to repeat
this cleanup when destroying the classes.
When running without opcache, static_members_table is shared with
default_static_members_table. This is visible in reflection output,
because ReflectionProperty::getDefaultValue() will return the
current value, rather than the default value.
Address this by never sharing the table, which matches the behavior
we already see under opcache.
Fixes bug #80821.
Closes GH-7299.
Userland property infos are no longer duplicated since PHP 7.4, when we
stopped setting SHADOW flags on inherited private properties. Stop duplicating
internal property infos as well.
This requires switching class destruction to work in reverse order, as child
classes may be reusing structures from parent classes, and as such should be
destroyed first.
Currently, dynamically declared functions and closures are inserted
into the function table under a runtime definition key, and then later
possibly renamed. When opcache is not used and a file containing a
closure is repeatedly included, this leads to a very large memory leak,
as the no longer needed closure declarations will never be freed
(https://bugs.php.net/bug.php?id=76982).
With this patch, dynamic functions are instead stored in a
dynamic_func_defs member on the op_array, which opcodes reference
by index. When the parent op_array is destroyed, the dynamic_func_defs
it contains are also destroyed (unless they are stilled used elsewhere,
e.g. because they have been bound, or are used by a live closure). This
resolves the fundamental part of the leak, though doesn't completely
fix it yet due to some arena allocations.
The main non-obvious change here is to static variable handling:
We can't destroy static_variables_ptr in destroy_op_array, as e.g.
that would clear the static variables in a dynamic function when
the op_array containing it is destroyed. Static variable destruction
is separated out for this reason (we already do static variable
destruction separately for normal functions, so we only need to
handle main scripts).
Closes GH-5595.
When a method is inherited, the static variables will now always
use the initial values, rather than the values at the time of
inheritance. As such, behavior no longer depends on whether
inheritance happens before or after a method has been called.
This is implemented by always keeping static_variables as the
original values, and static_variables_ptr as the modified copy.
Closes GH-6705.
This is a new transparent technology that eliminates overhead of PHP class inheritance.
PHP classes are compiled and cached (by opcahce) separately, however their "linking" was done at run-time - on each request. The process of "linking" may involve a number of compatibility checks and borrowing methods/properties/constants form parent and traits. This takes significant time, but the result is the same on each request.
Inheritance Cache performs "linking" for unique set of all the depending classes (parent, interfaces, traits, property types, method types involved into compatibility checks) once and stores result in opcache shared memory. As a part of the this patch, I removed limitations for immutable classes (unresolved constants, typed properties and covariant type checks). So now all classes stored in opcache are "immutable". They may be lazily loaded into process memory, if necessary, but this usually occurs just once (on first linking).
The patch shows 8% improvement on Symphony "Hello World" app.