Skip to content

Commit b077dcf

Browse files
committed
JIT for FFI::addr()
1 parent 4b9cb6c commit b077dcf

File tree

5 files changed

+178
-2
lines changed

5 files changed

+178
-2
lines changed

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,4 +3420,117 @@ static void ZEND_FASTCALL zend_jit_zval_ffi_obj(zval *zv, zend_ffi_type *type, v
34203420
ZVAL_OBJ(zv, &cdata->std);
34213421
}
34223422
}
3423+
3424+
static zend_ffi_cdata* ZEND_FASTCALL zend_jit_zval_ffi_addr(zval *zv)
3425+
{
3426+
zend_ffi_cdata *cdata, *new_cdata;
3427+
zend_ffi_type *type, *new_type;
3428+
3429+
if (Z_TYPE_P(zv) == IS_INDIRECT) {
3430+
zv = Z_INDIRECT_P(zv);
3431+
}
3432+
ZVAL_DEREF(zv);
3433+
ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
3434+
3435+
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3436+
type = ZEND_FFI_TYPE(cdata->type);
3437+
3438+
// if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
3439+
// && cdata->ptr == &cdata->ptr_holder) {
3440+
// zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
3441+
// return NULL;
3442+
// }
3443+
3444+
new_type = emalloc(sizeof(zend_ffi_type));
3445+
new_type->kind = ZEND_FFI_TYPE_POINTER;
3446+
new_type->attr = 0;
3447+
new_type->size = sizeof(void*);
3448+
new_type->align = _Alignof(void*);
3449+
/* life-time (source must relive the resulting pointer) ??? */
3450+
new_type->pointer.type = type;
3451+
3452+
new_cdata = emalloc(sizeof(zend_ffi_cdata));
3453+
// inlined zend_ffi_object_init()
3454+
GC_SET_REFCOUNT(&new_cdata->std, 1);
3455+
GC_TYPE_INFO(&new_cdata->std) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT);
3456+
new_cdata->std.extra_flags = 0;
3457+
new_cdata->std.ce = zend_ffi_api->cdata_ce;
3458+
new_cdata->std.handlers = zend_ffi_api->cdata_ce->default_object_handlers; /* zend_ffi_cdata_handlers */
3459+
new_cdata->std.properties = NULL;
3460+
zend_objects_store_put(&new_cdata->std);
3461+
new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
3462+
new_cdata->flags = 0;
3463+
3464+
new_cdata->ptr = (void*)&new_cdata->ptr_holder;
3465+
new_cdata->ptr_holder = cdata->ptr;
3466+
3467+
return new_cdata;
3468+
}
3469+
3470+
static zend_ffi_cdata* ZEND_FASTCALL zend_jit_zval_ffi_addr_var(zval *zv)
3471+
{
3472+
zend_ffi_cdata *cdata, *new_cdata;
3473+
zend_ffi_type *type, *new_type;
3474+
zval *arg = zv;
3475+
3476+
if (Z_TYPE_P(zv) == IS_INDIRECT) {
3477+
zv = Z_INDIRECT_P(zv);
3478+
}
3479+
ZVAL_DEREF(zv);
3480+
ZEND_ASSERT(Z_TYPE_P(zv) == IS_OBJECT);
3481+
3482+
cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3483+
type = ZEND_FFI_TYPE(cdata->type);
3484+
3485+
// if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
3486+
// && cdata->ptr == &cdata->ptr_holder) {
3487+
// zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
3488+
// return NULL;
3489+
// }
3490+
3491+
new_type = emalloc(sizeof(zend_ffi_type));
3492+
new_type->kind = ZEND_FFI_TYPE_POINTER;
3493+
new_type->attr = 0;
3494+
new_type->size = sizeof(void*);
3495+
new_type->align = _Alignof(void*);
3496+
/* life-time (source must relive the resulting pointer) ??? */
3497+
new_type->pointer.type = type;
3498+
3499+
new_cdata = emalloc(sizeof(zend_ffi_cdata));
3500+
// inlined zend_ffi_object_init()
3501+
GC_SET_REFCOUNT(&new_cdata->std, 1);
3502+
GC_TYPE_INFO(&new_cdata->std) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT);
3503+
new_cdata->std.extra_flags = 0;
3504+
new_cdata->std.ce = zend_ffi_api->cdata_ce;
3505+
new_cdata->std.handlers = zend_ffi_api->cdata_ce->default_object_handlers; /* zend_ffi_cdata_handlers */
3506+
new_cdata->std.properties = NULL;
3507+
zend_objects_store_put(&new_cdata->std);
3508+
new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
3509+
new_cdata->flags = 0;
3510+
3511+
new_cdata->ptr = (void*)&new_cdata->ptr_holder;
3512+
new_cdata->ptr_holder = cdata->ptr;
3513+
3514+
if (Z_REFCOUNTED_P(arg)) {
3515+
zend_refcounted *ref = Z_COUNTED_P(arg);
3516+
3517+
if (!GC_DELREF(ref)) {
3518+
if (ref == (zend_refcounted*)cdata || GC_REFCOUNT(&cdata->std) == 1) {
3519+
if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
3520+
/* transfer type ownership */
3521+
cdata->type = type;
3522+
new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
3523+
}
3524+
if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
3525+
/* transfer ownership */
3526+
cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
3527+
new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
3528+
}
3529+
}
3530+
rc_dtor_func(ref);
3531+
}
3532+
}
3533+
3534+
return new_cdata;
3535+
}
34233536
#endif

ext/opcache/jit/zend_jit_internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,7 @@ struct _zend_jit_trace_stack_frame {
575575
#define TRACE_FRAME_MASK_ALWAYS_RELEASE_THIS 0x00000400
576576

577577
#define TRACE_FRAME_MASK_FFI 0x00000800
578+
#define TRACE_FRAME_MASK_FFI_ADDR 0x00001000
578579

579580

580581
#define TRACE_FRAME_INIT(frame, _func, _flags, num_args) do { \
@@ -616,6 +617,8 @@ struct _zend_jit_trace_stack_frame {
616617
((frame)->_info & TRACE_FRAME_MASK_ALWAYS_RELEASE_THIS)
617618
#define TRACE_FRAME_FFI(frame) \
618619
((frame)->_info & TRACE_FRAME_MASK_FFI)
620+
#define TRACE_FRAME_FFI_ADDR(frame) \
621+
((frame)->_info & TRACE_FRAME_MASK_FFI_ADDR)
619622

620623
#define TRACE_FRAME_SET_UNKNOWN_NUM_ARGS(frame) do { \
621624
(frame)->_info |= (0xffffu << TRACE_FRAME_SHIFT_NUM_ARGS); \

ext/opcache/jit/zend_jit_ir.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,6 +3104,8 @@ static void zend_jit_setup_disasm(void)
31043104
REGISTER_HELPER(zend_jit_zval_string);
31053105
REGISTER_HELPER(zend_jit_zval_ffi_ptr);
31063106
REGISTER_HELPER(zend_jit_zval_ffi_obj);
3107+
REGISTER_HELPER(zend_jit_zval_ffi_addr);
3108+
REGISTER_HELPER(zend_jit_zval_ffi_addr_var);
31073109
#endif
31083110

31093111
#ifndef ZTS

ext/opcache/jit/zend_jit_ir_ffi.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ static int zend_jit_ffi_send_val(zend_jit_ctx *jit,
115115
uint8_t arg_type = IS_UNDEF;
116116
uint8_t arg_flags = 0;
117117

118+
if (!type) {
119+
ZEND_ASSERT(TRACE_FRAME_FFI_ADDR(call));
120+
ZEND_ASSERT(opline->op2.num == 1);
121+
ZEND_ASSERT(op1_ffi_type);
122+
123+
if (opline->op1_type == IS_VAR) {
124+
ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_ffi_addr_var),
125+
jit_ZVAL_ADDR(jit, op1_addr));
126+
} else {
127+
ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_zval_ffi_addr),
128+
jit_ZVAL_ADDR(jit, op1_addr));
129+
}
130+
131+
SET_STACK_TYPE(stack, 0, IS_OBJECT, 0);
132+
SET_STACK_REF_EX(stack, 0, ref, 0);
133+
134+
return 1;
135+
}
118136
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
119137
if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
120138
ZEND_ASSERT(TRACE_FRAME_NUM_ARGS(call) >= zend_hash_num_elements(type->func.args));
@@ -318,13 +336,25 @@ static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
318336
zend_jit_addr res_addr)
319337
{
320338
zend_jit_trace_stack_frame *call = JIT_G(current_frame)->call;
339+
zend_jit_trace_stack *stack = call->stack;
321340
zend_ffi_type *type = (zend_ffi_type*)(void*)call->call_opline;
322341
ir_ref func_ref = (intptr_t)(void*)call->ce;
323342
uint32_t i, num_args;
324343
ir_type ret_type = IR_VOID;
325344
ir_ref ref = IR_UNUSED;
326345
zend_ffi_type_kind type_kind;
327346

347+
if (!type) {
348+
ZEND_ASSERT(TRACE_FRAME_FFI_ADDR(call));
349+
350+
ref = STACK_REF(stack, 0);
351+
352+
jit_set_Z_PTR(jit, res_addr, ref);
353+
jit_set_Z_TYPE_INFO(jit, res_addr, IS_OBJECT_EX);
354+
355+
return 1;
356+
}
357+
328358
ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
329359

330360
type_kind = ZEND_FFI_TYPE(type->func.ret_type)->kind;
@@ -390,7 +420,6 @@ static int zend_jit_ffi_do_call(zend_jit_ctx *jit,
390420
num_args = TRACE_FRAME_NUM_ARGS(call);
391421
if (num_args) {
392422
ir_ref *args = alloca(sizeof(ir_ref) * num_args);
393-
zend_jit_trace_stack *stack = call->stack;
394423

395424
for (i = 0; i < num_args; i++) {
396425
uint8_t type = STACK_TYPE(stack, i);

ext/opcache/jit/zend_jit_trace.c

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5605,6 +5605,17 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
56055605
break;
56065606
}
56075607
op1_info = OP1_INFO();
5608+
#ifdef HAVE_FFI
5609+
if (JIT_G(current_frame)
5610+
&& JIT_G(current_frame)->call
5611+
&& TRACE_FRAME_FFI(JIT_G(current_frame)->call)) {
5612+
if (!zend_jit_ffi_send_val(&ctx, opline, op_array, ssa, ssa_op,
5613+
op1_info, OP1_REG_ADDR(), 0, op1_ffi_type)) {
5614+
goto jit_failure;
5615+
}
5616+
goto done;
5617+
}
5618+
#endif
56085619
if (!zend_jit_send_ref(&ctx, opline, op_array,
56095620
op1_info, 0)) {
56105621
goto jit_failure;
@@ -6861,6 +6872,25 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
68616872
|| (opline->op1.num & ZEND_FETCH_CLASS_MASK) == ZEND_FETCH_CLASS_PARENT))))) {
68626873
break;
68636874
}
6875+
#ifdef HAVE_FFI
6876+
if (opline->op1_type == IS_CONST
6877+
&& opline->op2_type == IS_CONST) {
6878+
zval *zv = RT_CONSTANT(opline, opline->op1);
6879+
if (Z_TYPE_P(zv) == IS_STRING
6880+
&& (zend_string_equals_literal_ci(Z_STR_P(zv), "FFI")
6881+
|| zend_string_equals_literal_ci(Z_STR_P(zv), "\\FFI"))) {
6882+
zval *zv = RT_CONSTANT(opline, opline->op2);
6883+
if (Z_TYPE_P(zv) == IS_STRING
6884+
&& zend_string_equals_literal(Z_STR_P(zv), "addr")
6885+
&& opline->extended_value == 1) {
6886+
frame_flags = TRACE_FRAME_MASK_FFI | TRACE_FRAME_MASK_FFI_ADDR;
6887+
frame_ffi_func_type = NULL;
6888+
frame_ffi_func_ref = IR_UNUSED;
6889+
goto done;
6890+
}
6891+
}
6892+
}
6893+
#endif
68646894
if (!zend_jit_init_static_method_call(&ctx, opline,
68656895
op_array_ssa->cfg.map ? op_array_ssa->cfg.map[opline - op_array->opcodes] : -1,
68666896
op_array, ssa, ssa_op, frame->call_level,
@@ -7501,7 +7531,6 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
75017531
TRACE_FRAME_INIT(call, p->func, frame_flags, num_args);
75027532
#ifdef HAVE_FFI
75037533
if (TRACE_FRAME_FFI(call)) {
7504-
ZEND_ASSERT(frame_ffi_func_type != NULL);
75057534
call->call_opline = (const zend_op*)(void*)frame_ffi_func_type;
75067535
call->ce = (zend_class_entry*)(intptr_t)frame_ffi_func_ref;
75077536
}

0 commit comments

Comments
 (0)