Polymorphic calls pass this and the function to side traces via snapshotting.
However, we assume that this/func are in registers, when in fact they may be
spilled.
Here I update snapshotting of poly_func/poly_this to support spilling:
- In zend_jit_snapshot_handler, keep track of the C stack offset
of the spilled register, in a way similar to how stack variables.
- In zend_jit_start, do not pre-load the registers if they were spilled.
- In zend_jit_trace_exit / zend_jit_trace_deoptimization, load from the
stack if the register was spilled.
- Store a reference to poly_func/poly_this in zend_jit_ctx so we can use that
directly in the side trace.
Closes GH-18408
Add a new exit flag (ZEND_JIT_EXIT_CHECK_EXCEPTION) that enables exception
checking during exit/deoptimization.
We already checked for exceptions during exit/deoptimization, but only when
ZEND_JIT_EXIT_FREE_OP1 or ZEND_JIT_EXIT_FREE_OP2 were set (presumably to
handle exceptions thrown during dtor). The new flag makes it possible to request
it explicitly.
This also fixes two issues in zend_jit_trace_exit():
- By returning 1, we were telling the caller (zend_jit_trace_exit_stub()) to
execute the original op handler of EG(current_execute_data)->opline, but in
reality we want to execute EX(opline), which should be EG(exception_op).
- EX(opline) is set to the value of %r15 in zend_jit_trace_exit_stub() before
calling zend_jit_trace_exit(), but this may be the address of a
zend_execute_data when the register is being reused to cache EX(call).
Fixes GH-18262
Closes GH-18297
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.
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.
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.
The code to update the call_level in that case skips the opline itself,
as that's handled by the tail handler, and then wants to set the opline
to the last opline of the block because the code below the switch will
update the call_level for that opline.
However, the test has a block with a single opline (THROW). The block
after that has ZEND_INIT_FCALL, because `i` points to ZEND_INIT_FCALL
now, it erroneously causes the call_level after the switch.
Closes GH-17438.
`bcadd(...)` is a closure for an internal function, and
`zend_jit_push_call_frame` takes into account both last_var and the
difference in argument numbers not only for user code but also for
internal code. However, this is inconsistent with
`zend_vm_calc_used_stack`, causing argument corruption.
Making this consistent fixes the issue.
I could only reproduce the assertion failure when using Valgrind.
Closes GH-17319.
Minimal JIT shouldn't generate a call to the complex handler, but
instead rely on the VM and then check for a two-way jump.
This moves the frameless codegen under the check `JIT_G(opt_level) >=
ZEND_JIT_LEVEL_INLINE`.
EX(opline) / opline can be stale if the IP is not stored, like in this
case on a trace enter. We always need to make sure that the opline is up
to date to make sure we don't use stale data.
Closes GH-17260.
ZEND_FETCH_DIM_FUNC_ARG should also be repeated on undefined access,
consistent to how ZEND_FETCH_DIM_R is handled. The opcode was just
missing from the assertion list.
Closes GH-17148.
Co-authored-by: Dmitry Stogov <dmitry@zend.com>
This is a quick fix for the problem.
It'll work while all the JIT-ed functions have the same "fixed stack frame".
Unwinder uses hard-coded unwind data for this "fixed stack frame".
* Preallocate space for Win64 shadow args
* typo
* Setup unwinder for JIT functions
* Revert "Dynamically xfail test case which fails on CI"
This reverts commit 7cc327fd5a.
* Revert "Dynamically xfail test case which fails on CI"
This reverts commit bdde797159.
* Revert "Dynamically xfail test cases which fail on CI (GH-15710)"
This reverts commit 6d5962074f.
* Remove XFAIL sections
* Add hard-coded SEH unwind data for EXITCALL
* Fix unwind data
* Fix Windows multi-process support
* Typo