Skip to content

Commit 6f89d0e

Browse files
committed
JIT/FFI support for closure calls (pointers to functions)
1 parent 693ef28 commit 6f89d0e

File tree

2 files changed

+107
-32
lines changed

2 files changed

+107
-32
lines changed

ext/opcache/jit/zend_jit_ir_ffi.c

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ static int zend_jit_ffi_symbols_guard(zend_jit_ctx *jit,
3030
HashTable *ffi_symbols,
3131
zend_jit_ffi_info *ffi_info);
3232

33+
static int zend_jit_ffi_guard(zend_jit_ctx *jit,
34+
const zend_op *opline,
35+
zend_ssa *ssa,
36+
int use,
37+
int def,
38+
ir_ref ref,
39+
zend_ffi_type *ffi_type,
40+
zend_jit_ffi_info *ffi_info);
41+
3342
static int zend_jit_ffi_init_call_sym(zend_jit_ctx *jit,
3443
const zend_op *opline,
3544
const zend_op_array *op_array,
@@ -39,12 +48,56 @@ static int zend_jit_ffi_init_call_sym(zend_jit_ctx *jit,
3948
zend_jit_addr op1_addr,
4049
zend_ffi_symbol *sym,
4150
HashTable *op1_ffi_symbols,
42-
zend_jit_ffi_info *ffi_info)
51+
zend_jit_ffi_info *ffi_info,
52+
ir_ref *ffi_func_ref)
4353
{
54+
zend_ffi_type *type;
55+
56+
ZEND_ASSERT(sym->kind == ZEND_FFI_SYM_FUNC);
57+
type = ZEND_FFI_TYPE(sym->type);
58+
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
59+
4460
if (!zend_jit_ffi_symbols_guard(jit, opline, ssa, ssa_op->op1_use, -1, op1_addr, op1_ffi_symbols, ffi_info)) {
4561
return 0;
4662
}
4763

64+
if (type->func.abi == ZEND_FFI_ABI_FASTCALL) {
65+
*ffi_func_ref = ir_CONST_FC_FUNC(sym->addr);
66+
} else {
67+
*ffi_func_ref = ir_CONST_FUNC(sym->addr);
68+
}
69+
return 1;
70+
}
71+
72+
static int zend_jit_ffi_init_call_obj(zend_jit_ctx *jit,
73+
const zend_op *opline,
74+
const zend_op_array *op_array,
75+
zend_ssa *ssa,
76+
const zend_ssa_op *ssa_op,
77+
uint32_t op1_info,
78+
zend_jit_addr op1_addr,
79+
uint32_t op2_info,
80+
zend_jit_addr op2_addr,
81+
zend_ffi_type *op2_ffi_type,
82+
zend_jit_ffi_info *ffi_info,
83+
ir_ref *ffi_func_ref)
84+
{
85+
ir_ref obj_ref = jit_Z_PTR(jit, op2_addr);
86+
zend_ffi_type *type;
87+
88+
ZEND_ASSERT(op2_ffi_type->kind == ZEND_FFI_TYPE_POINTER);
89+
type = ZEND_FFI_TYPE(op2_ffi_type->pointer.type);
90+
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
91+
92+
if (!zend_jit_ffi_guard(jit, opline, ssa, ssa_op->op2_use, -1, obj_ref, op2_ffi_type, ffi_info)) {
93+
return 0;
94+
}
95+
96+
*ffi_func_ref = ir_LOAD_A(jit_FFI_CDATA_PTR(jit, obj_ref));
97+
if (type->func.abi == ZEND_FFI_ABI_FASTCALL) {
98+
*ffi_func_ref = ir_CAST_FC_FUNC(*ffi_func_ref);
99+
}
100+
48101
return 1;
49102
}
50103

@@ -60,12 +113,9 @@ static int zend_jit_ffi_send_val(zend_jit_ctx *jit,
60113
{
61114
zend_jit_trace_stack_frame *call = JIT_G(current_frame)->call;
62115
zend_jit_trace_stack *stack = call->stack;
63-
zend_ffi_symbol *sym = (zend_ffi_symbol*)(void*)call->call_opline;
64-
zend_ffi_type *type;
116+
zend_ffi_type *type = (zend_ffi_type*)(void*)call->call_opline;
65117
ir_ref ref = IR_UNUSED;
66118

67-
ZEND_ASSERT(sym->kind == ZEND_FFI_SYM_FUNC);
68-
type = ZEND_FFI_TYPE(sym->type);
69119
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
70120
if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
71121
ZEND_ASSERT(TRACE_FRAME_NUM_ARGS(call) >= zend_hash_num_elements(type->func.args));
@@ -225,22 +275,20 @@ static int zend_jit_ffi_send_val(zend_jit_ctx *jit,
225275
return 1;
226276
}
227277

228-
static int zend_jit_ffi_do_call_sym(zend_jit_ctx *jit,
229-
const zend_op *opline,
230-
const zend_op_array *op_array,
231-
zend_ssa *ssa,
232-
const zend_ssa_op *ssa_op,
233-
zend_jit_addr res_addr)
278+
static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
279+
const zend_op *opline,
280+
const zend_op_array *op_array,
281+
zend_ssa *ssa,
282+
const zend_ssa_op *ssa_op,
283+
zend_jit_addr res_addr)
234284
{
235285
zend_jit_trace_stack_frame *call = JIT_G(current_frame)->call;
236-
zend_ffi_symbol *sym = (zend_ffi_symbol*)(void*)call->call_opline;
286+
zend_ffi_type *type = (zend_ffi_type*)(void*)call->call_opline;
287+
ir_ref func_ref = (intptr_t)(void*)call->ce;
237288
uint32_t i, num_args;
238-
zend_ffi_type *type;
239289
ir_type ret_type = IR_VOID;
240290
ir_ref ref = IR_UNUSED;
241291

242-
ZEND_ASSERT(sym->kind == ZEND_FFI_SYM_FUNC);
243-
type = ZEND_FFI_TYPE(sym->type);
244292
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
245293

246294
switch (ZEND_FFI_TYPE(type->func.ret_type)->kind) {
@@ -300,18 +348,10 @@ static int zend_jit_ffi_do_call_sym(zend_jit_ctx *jit,
300348
for (i = 0; i < num_args; i++) {
301349
args[i] = STACK_REF(stack, i);
302350
}
303-
if (type->func.abi == ZEND_FFI_ABI_FASTCALL) {
304-
ref = ir_CALL_N(ret_type, ir_CONST_FC_FUNC(sym->addr), num_args, args);
305-
} else {
306-
ref = ir_CALL_N(ret_type, ir_CONST_FUNC(sym->addr), num_args, args);
307-
}
351+
ref = ir_CALL_N(ret_type, func_ref, num_args, args);
308352
} else {
309353
ZEND_ASSERT(!type->func.args);
310-
if (type->func.abi == ZEND_FFI_ABI_FASTCALL) {
311-
ref = ir_CALL(ret_type, ir_CONST_FC_FUNC(sym->addr));
312-
} else {
313-
ref = ir_CALL(ret_type, ir_CONST_FUNC(sym->addr));
314-
}
354+
ref = ir_CALL(ret_type, func_ref);
315355
}
316356

317357
if (RETURN_VALUE_USED(opline)) {

ext/opcache/jit/zend_jit_trace.c

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4136,7 +4136,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
41364136
uint32_t frame_flags = 0;
41374137
#ifdef HAVE_FFI
41384138
zend_jit_ffi_info *ffi_info = NULL;
4139-
zend_ffi_symbol *frame_ffi_sym = NULL;
4139+
zend_ffi_type *frame_ffi_func_type = NULL;
4140+
ir_ref frame_ffi_func_ref = IR_UNUSED;
41404141
#endif
41414142

41424143
JIT_G(current_trace) = trace_buffer;
@@ -4473,7 +4474,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
44734474

44744475
frame_flags = 0;
44754476
#ifdef HAVE_FFI
4476-
frame_ffi_sym = NULL;
4477+
frame_ffi_func_type = NULL;
4478+
frame_ffi_func_ref = IR_UNUSED;
44774479
#endif
44784480

44794481
switch (opline->opcode) {
@@ -5715,7 +5717,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
57155717
if (JIT_G(current_frame)
57165718
&& JIT_G(current_frame)->call
57175719
&& TRACE_FRAME_FFI(JIT_G(current_frame)->call)) {
5718-
if (!zend_jit_ffi_do_call_sym(&ctx, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
5720+
if (!zend_jit_ffi_do_call(&ctx, opline, op_array, ssa, ssa_op, RES_REG_ADDR())) {
57195721
goto jit_failure;
57205722
}
57215723
goto done;
@@ -6811,17 +6813,20 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
68116813
if (sym
68126814
&& sym->kind == ZEND_FFI_SYM_FUNC
68136815
&& zend_jit_ffi_supported_func(ZEND_FFI_TYPE(sym->type))) {
6816+
ir_ref ffi_func_ref;
6817+
68146818
if (!ffi_info) {
68156819
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
68166820
}
68176821
if (!zend_jit_ffi_init_call_sym(&ctx, opline, op_array, ssa, ssa_op,
68186822
op1_info, op1_addr,
68196823
sym,
6820-
op1_ffi_symbols, ffi_info)) {
6824+
op1_ffi_symbols, ffi_info, &ffi_func_ref)) {
68216825
goto jit_failure;
68226826
}
68236827
frame_flags = TRACE_FRAME_MASK_FFI;
6824-
frame_ffi_sym = sym;
6828+
frame_ffi_func_type = ZEND_FFI_TYPE(sym->type);
6829+
frame_ffi_func_ref = ffi_func_ref;
68256830
goto done;
68266831
}
68276832
}
@@ -6854,12 +6859,41 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
68546859
}
68556860
goto done;
68566861
case ZEND_INIT_DYNAMIC_CALL:
6862+
#ifdef HAVE_FFI
6863+
if (orig_op2_type != IS_OBJECT
6864+
|| (op2_ce != zend_ce_closure && !op2_ffi_type)) {
6865+
break;
6866+
}
6867+
#else
68576868
if (orig_op2_type != IS_OBJECT || op2_ce != zend_ce_closure) {
68586869
break;
68596870
}
6871+
#endif
68606872
op2_info = OP2_INFO();
68616873
CHECK_OP2_TRACE_TYPE();
68626874
frame_flags = TRACE_FRAME_MASK_NESTED;
6875+
#ifdef HAVE_FFI
6876+
if (op2_ffi_type
6877+
&& op2_ffi_type->kind == ZEND_FFI_TYPE_POINTER
6878+
&& ZEND_FFI_TYPE(op2_ffi_type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC
6879+
&& zend_jit_ffi_supported_func(ZEND_FFI_TYPE(op2_ffi_type->pointer.type))) {
6880+
ir_ref ffi_func_ref;
6881+
6882+
if (!ffi_info) {
6883+
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
6884+
}
6885+
if (!zend_jit_ffi_init_call_obj(&ctx, opline, op_array, ssa, ssa_op,
6886+
op1_info, op1_addr,
6887+
op2_info, OP2_REG_ADDR(),
6888+
op2_ffi_type, ffi_info, &ffi_func_ref)) {
6889+
goto jit_failure;
6890+
}
6891+
frame_flags = TRACE_FRAME_MASK_FFI;
6892+
frame_ffi_func_type = ZEND_FFI_TYPE(op2_ffi_type->pointer.type);
6893+
frame_ffi_func_ref = ffi_func_ref;
6894+
goto done;
6895+
}
6896+
#endif
68636897
if (!zend_jit_init_closure_call(&ctx, opline, op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1, op_array, ssa, ssa_op, frame->call_level, p + 1, peek_checked_stack - checked_stack)) {
68646898
goto jit_failure;
68656899
}
@@ -7457,8 +7491,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
74577491
TRACE_FRAME_INIT(call, p->func, frame_flags, num_args);
74587492
#ifdef HAVE_FFI
74597493
if (TRACE_FRAME_FFI(call)) {
7460-
ZEND_ASSERT(frame_ffi_sym != NULL);
7461-
call->call_opline = (const zend_op*)(void*)frame_ffi_sym;
7494+
ZEND_ASSERT(frame_ffi_func_type != NULL);
7495+
call->call_opline = (const zend_op*)(void*)frame_ffi_func_type;
7496+
call->ce = (zend_class_entry*)(intptr_t)frame_ffi_func_ref;
74627497
}
74637498
#endif
74647499
call->prev = frame->call;

0 commit comments

Comments
 (0)