Skip to content

Commit c7f0fea

Browse files
committed
Fix JIT handling of interrupts
Before, opcode handlers would handle an interrupt and return the next opline to execute. Now they return interrupt_op so we must execute it to fetch the next opline. We cannot call interrupt_op->handler directly as this doesn't return: we need to call the non-tailcalling helper instead.
1 parent 78d2dfe commit c7f0fea

6 files changed

Lines changed: 45 additions & 0 deletions

File tree

Zend/zend_vm.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,18 @@ ZEND_API void ZEND_FASTCALL zend_serialize_opcode_handler(zend_op *op);
3232
ZEND_API void ZEND_FASTCALL zend_deserialize_opcode_handler(zend_op *op);
3333
ZEND_API const void* ZEND_FASTCALL zend_get_opcode_handler_func(const zend_op *op);
3434
ZEND_API const zend_op *zend_get_halt_op(void);
35+
ZEND_API const zend_op *zend_get_interrupt_op(void);
3536
ZEND_API int ZEND_FASTCALL zend_vm_call_opcode_handler(zend_execute_data *ex);
3637
ZEND_API int zend_vm_kind(void);
3738
ZEND_API bool zend_gcc_global_regs(void);
3839

3940
void zend_vm_init(void);
4041
void zend_vm_dtor(void);
4142

43+
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
44+
const struct _zend_op *zend_vm_handle_interrupt(struct _zend_execute_data *execute_data, const struct _zend_op *opline);
45+
#endif
46+
4247
END_EXTERN_C()
4348

4449
#define ZEND_VM_SET_OPCODE_HANDLER(opline) zend_vm_set_opcode_handler(opline)

Zend/zend_vm_execute.h

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Zend/zend_vm_execute.skl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,22 @@ ZEND_API const zend_op *zend_get_halt_op(void)
161161
#endif
162162
}
163163

164+
ZEND_API const zend_op *zend_get_interrupt_op(void)
165+
{
166+
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
167+
return &call_interrupt_op;
168+
#else
169+
return NULL;
170+
#endif
171+
}
172+
173+
#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
174+
ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_vm_handle_interrupt(ZEND_OPCODE_HANDLER_ARGS)
175+
{
176+
return zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
177+
}
178+
#endif
179+
164180
ZEND_API int zend_vm_kind(void)
165181
{
166182
return ZEND_VM_KIND;

ext/opcache/jit/zend_jit.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ int zend_jit_profile_counter_rid = -1;
7878
int16_t zend_jit_hot_counters[ZEND_HOT_COUNTERS_COUNT];
7979

8080
const zend_op *zend_jit_halt_op = NULL;
81+
const zend_op *zend_jit_interrupt_op = NULL;
8182
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP
8283
static int zend_write_protect = 1;
8384
#endif
@@ -3777,6 +3778,7 @@ int zend_jit_check_support(void)
37773778
void zend_jit_startup(void *buf, size_t size, bool reattached)
37783779
{
37793780
zend_jit_halt_op = zend_get_halt_op();
3781+
zend_jit_interrupt_op = zend_get_interrupt_op();
37803782
zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
37813783

37823784
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP

ext/opcache/jit/zend_jit_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ typedef struct _zend_jit_op_array_hot_extension {
177177
zend_jit_hash((op_array)->opcodes)
178178

179179
extern const zend_op *zend_jit_halt_op;
180+
extern const zend_op *zend_jit_interrupt_op;
180181

181182
#ifdef HAVE_GCC_GLOBAL_REGS
182183
# define EXECUTE_DATA_D void

ext/opcache/jit/zend_jit_vm_helpers.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,11 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
10721072
if (UNEXPECTED(opline == zend_jit_halt_op)) {
10731073
#else
10741074
opline = handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
1075+
# if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL
1076+
while (UNEXPECTED(opline == zend_jit_interrupt_op)) {
1077+
opline = zend_vm_handle_interrupt(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
1078+
}
1079+
# endif
10751080
if (UNEXPECTED(((uintptr_t)opline & ~ZEND_VM_ENTER_BIT) == 0)) {
10761081
#endif
10771082
if (prev_opline->opcode == ZEND_YIELD || prev_opline->opcode == ZEND_YIELD_FROM) {

0 commit comments

Comments
 (0)