On win64, xmm6-xmm15 are preserved registers, but the prologues and
epilogues of JITted code don't handle these. The issue occurs when
calling into the JIT code again via an internal handler
(like call_user_func). Therefore, we want to save/restore xmm registers
upon entering/leaving execute_ex. Since MSVC x64 does not support inline
assembly, we create an assembly wrapper around the real execute_ex
function.
The alternative is to always save/restore these xmm registers into the
fixed call frame, but this causes unnecessary overhead.
The same issue occurs for ARM64 platforms for floating point register
8 to 15. However, there we can use inline asm to fix this.
Closes GH-18352.
The JIT helper `zend_jit_assign_op_to_typed_ref` expects a `zval*` as an
argument, so we have to store to the stack if OP1_DATA(=op3) is in a
register.
Closes GH-18299.
If there's a try-finally where the try_op starts on a basic block with a
single JMP, and the JMP optimization causes that basic block to become
unreachable, then we update try_op.
In this case, there is no catch_op, so try_op is erroneously set to 0,
we should instead set it to `b->start`.
Closes GH-18110.
Preloading shutdown calls request shutdown which will deactivate the
virtual cwd state. However, further startup code still assumes the state
that was set by virtual_cwd_startup(). So we need to reactivate it
manually.
Creating a test was a bit difficult because the INI setting I wanted to
test this with is overridden by the test runner apparently.
To reproduce the issue, create an empty file test.php and execute this
in a ZTS build:
`php -d opcache.preload=./ext/opcache/tests/preload_class_alias_2.inc -d "error_log=" -d "allow_url_include=1" test.php`
Closes GH-18117.
in_array() calls are compiled to frameless calls. Adjust the
optimization appropriately. Luckily, frameless opcodes simplify the
optimization quite a bit.
Fixes GH-18050
Closes GH-18066
A frameless icall with 3 arguments is a special case because it uses
OP_DATA, but this was not added to the list, so the opline pointed to
the wrong address resulting in UBSAN report or crash.
Closes GH-18048.
This is a bit of a theoretical issue, but the maximum string length is
actually ZSTR_MAX_LEN instead of SIZE_MAX. The resulting check is a bit
slower but should still be relatively cheap.
Closes GH-18049.
The FETCH_OBJ_R VM handler has an optimization that directly enters into
a hook if it is a simpler getter hook. This is not compatible with the
minimal JIT because the minimal JIT will try to continue executing the
opcodes after the FETCH_OBJ_R.
To solve this, we check whether the opcode is still the expected one
after the execution of the VM handler. If it is not, we know that we are
going to execute a simple hook. In that case, exit to the VM.
Closes GH-17909.
The generated code tries to initialize the run time cache for even
internal closures, but it should only initialize the run time cache for
user closures. We fix this by adding a check for the function type.
If `func` is known, then we can check the type at code generation time.
Closes GH-17869.
This solely affects the builtin enum functions currently.
Given that these are stored in SHM, we cannot simply hardwire a pointer into the internal function runtime cache on NTS too, but have to use a MAP_PTR (like on ZTS).
Now, by design, the runtime cache of internal functions no longer is reset between requests, hence we need to store them explicitly as static runtime cache.
On NTS builds we cannot trivially move the pointers into CG(internal_run_time_cache) as they're directly stored on the individual functions (on ZTS we could simply iterate the static map_ptrs).
Hence, we have the choice between having opcache managing the internal run_time_cache for its preloaded functions itself or realloc CG(internal_run_time_cache) and iterate through all functions to assign the new address. We choose the latter for simplicity and initial speed.
When read_property fails, it may return `&EG(uninitialized_zval)`, and
the exception is handled in the VM. The VM will try to
`zval_ptr_dtor_nogc` the result, but the result was never set, resulting
in dtor'ing garbage data. To solve this, we check when a different zval*
was returned and initialize the result with UNDEF. We don't need to copy
as the slow_ex handler return values are used directly in a register.
Closes GH-17749.
When a guard check is created for a variable to check if it's a packed array,
it is possible that there was no prior type check for that variable.
This happens in the global scope for example when the variable aliases.
In the test, this causes a dereference of address 8 because the integer
element in `$a` is interpreted as an array address.
This patch adds a check to see if the guard is handled.
If we were not able to determine or guard the type then we also cannot know the array is packed.
Closes GH-17584.
This test has two classes that use the same trait. In function JIT mode
the same cache slot will be used. This causes problems because it is
primed for the first class and then reused for the second class,
resulting in an incorrect type check failure.
The current check for a megamorphic trait call requires current_frame to
not be NULL, but this is only set in tracing mode and not in function
mode.
This patch corrects the check.
Closes GH-17660.
As explained by Snape3058: On 64-bit machines, we typically have 7 bytes
of padding between the zend_string.val[0] char and the following char[].
This means that zend_string.val[1-7] write to and read from the struct
padding, which is a bad idea.
Allocate the given string separately instead.
Fixes GH-17564
Closes GH-17576