mirror of
https://github.com/php/php-src.git
synced 2024-11-23 01:44:06 +08:00
Interrupt while internal frame is on the stack (#14627)
* Check VM interrupt while internal frame is on top * Use tab instead of spaces * fix frame used in interrupt and refactor * remove unused failures for zend_jit_check_timeout * Fix JIT support Co-authored-by: Bob Weinand <bobwei9@hotmail.com> * Fix the missing store to vm_interrupt * Rename new functions * Special case zend_interrupt_function in JIT code * refactor to use ZEND_VM_SET_OPCODE_NO_INTERRUPT * Split atomic exchange into load + store It is difficult to determine performance of atomics sometimes. In this case, the separate load+store is still correct, and a load does not cause a modification, and might be faster for some platforms than an exchange. A load+store is slower than an exchange, but we're fine trading the penalty to the slow path and keeping the happy path faster. --------- Co-authored-by: Bob Weinand <bobwei9@hotmail.com>
This commit is contained in:
parent
816aea797b
commit
6435bb5ae1
@ -377,6 +377,11 @@ PHP 8.4 INTERNALS UPGRADE NOTES
|
||||
4. OpCode changes
|
||||
========================
|
||||
|
||||
* DO_ICALL, DO_FCALL, and DO_FCALL_BY_NAME now call zend_interrupt_function
|
||||
while the internal frame is still on the stack. This means interrupt handlers
|
||||
will now see the internal call. If your interrupt handler does something like
|
||||
switching EG(current_execute_data), it should not do so if an internal func
|
||||
is on top.
|
||||
* New FRAMELESS_ICALL_[0,3] opcodes for faster internal function calls have been
|
||||
added. These opcodes don't create a stack frame, but pass arguments via opcode
|
||||
operands. They only work for functions that are known at compile-time, and
|
||||
|
@ -17,7 +17,7 @@ pcntl_signal(SIGUSR1, function (): void {
|
||||
$fiber = new Fiber(function (): void {
|
||||
echo "Fiber start\n";
|
||||
posix_kill(posix_getpid(), SIGUSR1);
|
||||
time_nanosleep(1);
|
||||
time_nanosleep(1, 0);
|
||||
echo "Fiber end\n";
|
||||
});
|
||||
|
||||
@ -30,8 +30,9 @@ Fiber start
|
||||
Fatal error: Uncaught FiberError: Cannot switch fibers in current execution context in %ssignal-async.php:%d
|
||||
Stack trace:
|
||||
#0 %ssignal-async.php(%d): Fiber::suspend()
|
||||
#1 %ssignal-async.php(%d): {closure:%s:%d}(%d, Array)
|
||||
#2 [internal function]: {closure:%s:%d}()
|
||||
#3 %ssignal-async.php(%d): Fiber->start()
|
||||
#4 {main}
|
||||
#1 [internal function]: {closure:%s:%d}(%d, Array)
|
||||
#2 %ssignal-async.php(%d): posix_kill(%d, %d)
|
||||
#3 [internal function]: {closure:%s:%d}()
|
||||
#4 %ssignal-async.php(%d): Fiber->start()
|
||||
#5 {main}
|
||||
thrown in %ssignal-async.php on line %d
|
||||
|
15
Zend/zend.h
15
Zend/zend.h
@ -341,7 +341,22 @@ extern ZEND_API size_t (*zend_printf)(const char *format, ...) ZEND_ATTRIBUTE_PT
|
||||
extern ZEND_API zend_write_func_t zend_write;
|
||||
extern ZEND_API FILE *(*zend_fopen)(zend_string *filename, zend_string **opened_path);
|
||||
extern ZEND_API void (*zend_ticks_function)(int ticks);
|
||||
|
||||
/* Called by the VM in certain places like at the loop header, user function
|
||||
* entry, and after internal function calls, if EG(vm_interrupt) has been set.
|
||||
*
|
||||
* If this is used to switch the EG(current_execute_data), such as implementing
|
||||
* a coroutine scheduler, then it needs to check the top frame to see if it's
|
||||
* an internal function. If an internal function is on top, then the frame
|
||||
* shouldn't be switched away.
|
||||
*
|
||||
* Prior to PHP 8.0, this check was not necessary. In PHP 8.0,
|
||||
* zend_call_function started calling zend_interrupt_function, and in 8.4 the
|
||||
* DO_*CALL* opcodes started calling the zend_interrupt_function while the
|
||||
* internal frame is still on top.
|
||||
*/
|
||||
extern ZEND_API void (*zend_interrupt_function)(zend_execute_data *execute_data);
|
||||
|
||||
extern ZEND_API void (*zend_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
|
||||
extern ZEND_API void (*zend_on_timeout)(int seconds);
|
||||
extern ZEND_API zend_result (*zend_stream_open_function)(zend_file_handle *handle);
|
||||
|
@ -4095,6 +4095,16 @@ ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *exec
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call)
|
||||
{
|
||||
zend_atomic_bool_store_ex(&EG(vm_interrupt), false);
|
||||
if (zend_atomic_bool_load_ex(&EG(timed_out))) {
|
||||
zend_timeout();
|
||||
} else if (zend_interrupt_function) {
|
||||
zend_interrupt_function(call);
|
||||
}
|
||||
}
|
||||
|
||||
#define ZEND_VM_INTERRUPT_CHECK() do { \
|
||||
if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
|
||||
ZEND_VM_INTERRUPT(); \
|
||||
@ -4107,6 +4117,12 @@ ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *exec
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ZEND_VM_FCALL_INTERRUPT_CHECK(call) do { \
|
||||
if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { \
|
||||
zend_fcall_interrupt(call); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Stack Frame Layout (the whole stack frame is allocated at once)
|
||||
* ==================
|
||||
@ -5541,9 +5557,12 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint
|
||||
CHECK_SYMBOL_TABLES() \
|
||||
OPLINE = new_op
|
||||
|
||||
#define ZEND_VM_SET_OPCODE(new_op) \
|
||||
#define ZEND_VM_SET_OPCODE_NO_INTERRUPT(new_op) \
|
||||
CHECK_SYMBOL_TABLES() \
|
||||
OPLINE = new_op; \
|
||||
OPLINE = new_op
|
||||
|
||||
#define ZEND_VM_SET_OPCODE(new_op) \
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(new_op); \
|
||||
ZEND_VM_INTERRUPT_CHECK()
|
||||
|
||||
#define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
|
||||
|
@ -542,6 +542,11 @@ ZEND_COLD void zend_magic_get_property_type_inconsistency_error(const zend_prope
|
||||
|
||||
ZEND_COLD void zend_match_unhandled_error(const zval *value);
|
||||
|
||||
/* Call this to handle the timeout or the interrupt function. It will set
|
||||
* EG(vm_interrupt) to false.
|
||||
*/
|
||||
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call);
|
||||
|
||||
static zend_always_inline void *zend_get_bad_ptr(void)
|
||||
{
|
||||
ZEND_UNREACHABLE();
|
||||
|
@ -55,10 +55,11 @@ void zend_startup_system_id(void)
|
||||
zend_system_id[0] = '\0';
|
||||
}
|
||||
|
||||
#define ZEND_HOOK_AST_PROCESS (1 << 0)
|
||||
#define ZEND_HOOK_COMPILE_FILE (1 << 1)
|
||||
#define ZEND_HOOK_EXECUTE_EX (1 << 2)
|
||||
#define ZEND_HOOK_EXECUTE_INTERNAL (1 << 3)
|
||||
#define ZEND_HOOK_AST_PROCESS (1 << 0)
|
||||
#define ZEND_HOOK_COMPILE_FILE (1 << 1)
|
||||
#define ZEND_HOOK_EXECUTE_EX (1 << 2)
|
||||
#define ZEND_HOOK_EXECUTE_INTERNAL (1 << 3)
|
||||
#define ZEND_HOOK_INTERRUPT_FUNCTION (1 << 4)
|
||||
|
||||
void zend_finalize_system_id(void)
|
||||
{
|
||||
@ -77,6 +78,9 @@ void zend_finalize_system_id(void)
|
||||
if (zend_execute_internal) {
|
||||
hooks |= ZEND_HOOK_EXECUTE_INTERNAL;
|
||||
}
|
||||
if (zend_interrupt_function) {
|
||||
hooks |= ZEND_HOOK_INTERRUPT_FUNCTION;
|
||||
}
|
||||
PHP_MD5Update(&context, &hooks, sizeof hooks);
|
||||
|
||||
for (int16_t i = 0; i < 256; i++) {
|
||||
|
@ -4084,6 +4084,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
}
|
||||
#endif
|
||||
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
zend_vm_stack_free_args(call);
|
||||
@ -4107,7 +4108,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -4205,6 +4206,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
}
|
||||
#endif
|
||||
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
@ -4235,7 +4237,7 @@ ZEND_VM_C_LABEL(fcall_by_name_end):
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -4325,6 +4327,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
|
||||
}
|
||||
#endif
|
||||
ZEND_OBSERVER_FCALL_END(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
@ -4353,8 +4356,7 @@ ZEND_VM_C_LABEL(fcall_end):
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
|
36
Zend/zend_vm_execute.h
generated
36
Zend/zend_vm_execute.h
generated
@ -1299,6 +1299,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
zend_vm_stack_free_args(call);
|
||||
|
||||
@ -1321,7 +1323,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1361,6 +1363,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
zend_vm_stack_free_args(call);
|
||||
|
||||
@ -1383,7 +1387,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1424,6 +1428,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBS
|
||||
}
|
||||
#endif
|
||||
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
zend_vm_stack_free_args(call);
|
||||
@ -1447,7 +1452,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_OBS
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1591,6 +1596,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
goto fcall_by_name_end;
|
||||
@ -1620,7 +1627,7 @@ fcall_by_name_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1691,6 +1698,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
goto fcall_by_name_end;
|
||||
@ -1720,7 +1729,7 @@ fcall_by_name_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1793,6 +1802,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
|
||||
}
|
||||
#endif
|
||||
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
@ -1823,7 +1833,7 @@ fcall_by_name_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -1912,6 +1922,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
goto fcall_end;
|
||||
@ -1939,8 +1951,7 @@ fcall_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -2029,6 +2040,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
|
||||
}
|
||||
#endif
|
||||
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
goto fcall_end;
|
||||
@ -2056,8 +2069,7 @@ fcall_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
@ -2147,6 +2159,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
|
||||
}
|
||||
#endif
|
||||
zend_observer_fcall_end(call, EG(exception) ? NULL : ret);
|
||||
ZEND_VM_FCALL_INTERRUPT_CHECK(call);
|
||||
|
||||
EG(current_execute_data) = execute_data;
|
||||
|
||||
@ -2175,8 +2188,7 @@ fcall_end:
|
||||
zend_rethrow_exception(execute_data);
|
||||
HANDLE_EXCEPTION();
|
||||
}
|
||||
|
||||
ZEND_VM_SET_OPCODE(opline + 1);
|
||||
ZEND_VM_SET_OPCODE_NO_INTERRUPT(opline + 1);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
|
||||
|
@ -1425,9 +1425,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
|
||||
zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start);
|
||||
}
|
||||
if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) {
|
||||
if (!zend_jit_check_timeout(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start, NULL)) {
|
||||
goto jit_failure;
|
||||
}
|
||||
zend_jit_check_timeout(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start, NULL);
|
||||
}
|
||||
if (!ssa->cfg.blocks[b].len) {
|
||||
zend_jit_bb_end(&ctx, b);
|
||||
|
@ -1857,7 +1857,7 @@ static void jit_OBJ_RELEASE(zend_jit_ctx *jit, ir_ref ref)
|
||||
ir_MERGE_list(end_inputs);
|
||||
}
|
||||
|
||||
static int zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
|
||||
static void zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, const void *exit_addr)
|
||||
{
|
||||
ir_ref ref = ir_LOAD_U8(jit_EG(vm_interrupt));
|
||||
|
||||
@ -1873,7 +1873,6 @@ static int zend_jit_check_timeout(zend_jit_ctx *jit, const zend_op *opline, cons
|
||||
ir_IJMP(jit_STUB_ADDR(jit, jit_stub_interrupt_handler));
|
||||
ir_IF_FALSE(if_timeout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* stubs */
|
||||
@ -2451,9 +2450,7 @@ static int zend_jit_trace_exit_stub(zend_jit_ctx *jit)
|
||||
}
|
||||
|
||||
// check for interrupt (try to avoid this ???)
|
||||
if (!zend_jit_check_timeout(jit, NULL, NULL)) {
|
||||
return 0;
|
||||
}
|
||||
zend_jit_check_timeout(jit, NULL, NULL);
|
||||
|
||||
addr = zend_jit_orig_opline_handler(jit);
|
||||
if (GCC_GLOBAL_REGS) {
|
||||
@ -3078,6 +3075,7 @@ static void zend_jit_setup_disasm(void)
|
||||
REGISTER_HELPER(zend_jit_pre_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_post_dec_obj_helper);
|
||||
REGISTER_HELPER(zend_jit_rope_end);
|
||||
REGISTER_HELPER(zend_fcall_interrupt);
|
||||
|
||||
#ifndef ZTS
|
||||
REGISTER_DATA(EG(current_execute_data));
|
||||
@ -10199,6 +10197,19 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
jit_observer_fcall_end(jit, rx, res_ref);
|
||||
}
|
||||
|
||||
/* When zend_interrupt_function is set, it gets called while
|
||||
* the frame is still on top. This is less efficient than
|
||||
* doing it later once it's popped off. There is code further
|
||||
* down that handles when there isn't an interrupt function.
|
||||
*/
|
||||
if (zend_interrupt_function) {
|
||||
// JIT: if (EG(vm_interrupt)) zend_fcall_interrupt(execute_data);
|
||||
ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt)));
|
||||
ir_IF_TRUE_cold(if_interrupt);
|
||||
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_fcall_interrupt), rx);
|
||||
ir_MERGE_WITH_EMPTY_FALSE(if_interrupt);
|
||||
}
|
||||
|
||||
// JIT: EG(current_execute_data) = execute_data;
|
||||
ir_STORE(jit_EG(current_execute_data), jit_FP(jit));
|
||||
|
||||
@ -10299,20 +10310,23 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
|
||||
ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)),
|
||||
jit_STUB_ADDR(jit, jit_stub_icall_throw));
|
||||
|
||||
// TODO: Can we avoid checking for interrupts after each call ???
|
||||
if (trace && jit->last_valid_opline != opline) {
|
||||
int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
|
||||
/* If there isn't a zend_interrupt_function, the timeout is
|
||||
* handled here because it's more efficient.
|
||||
*/
|
||||
if (!zend_interrupt_function) {
|
||||
// TODO: Can we avoid checking for interrupts after each call ???
|
||||
if (trace && jit->last_valid_opline != opline) {
|
||||
int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM);
|
||||
|
||||
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
|
||||
if (!exit_addr) {
|
||||
return 0;
|
||||
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
|
||||
if (!exit_addr) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
exit_addr = NULL;
|
||||
}
|
||||
} else {
|
||||
exit_addr = NULL;
|
||||
}
|
||||
|
||||
if (!zend_jit_check_timeout(jit, opline + 1, exit_addr)) {
|
||||
return 0;
|
||||
zend_jit_check_timeout(jit, opline + 1, exit_addr);
|
||||
}
|
||||
|
||||
if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) {
|
||||
@ -10347,7 +10361,7 @@ static int zend_jit_constructor(zend_jit_ctx *jit, const zend_op *opline, const
|
||||
}
|
||||
}
|
||||
|
||||
/* override predecessors of the next block */
|
||||
/* override predecessors of the next block */
|
||||
ZEND_ASSERT(jit->ssa->cfg.blocks[next_block].predecessors_count == 1);
|
||||
if (!jit->ctx.control) {
|
||||
ZEND_ASSERT(jit->bb_edges[jit->bb_predecessors[next_block]]);
|
||||
|
Loading…
Reference in New Issue
Block a user