Skip to content

Commit 1e357c5

Browse files
committed
Support for assignment FFI CData to another CData array/struct
1 parent a5c58a5 commit 1e357c5

File tree

7 files changed

+192
-75
lines changed

7 files changed

+192
-75
lines changed

ext/ffi/ffi.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ static ZEND_FUNCTION(ffi_trampoline);
103103
static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type);
104104
static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type);
105105
static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type);
106-
static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type);
106+
//???static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type);
107107

108108
#if FFI_CLOSURES
109109
static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value);
@@ -188,7 +188,7 @@ static bool zend_ffi_func_ptr_are_compatible(zend_ffi_type *dst_type, zend_ffi_t
188188
}
189189
/* }}} */
190190

191-
static bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
191+
PHP_FFI_API bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
192192
{
193193
while (1) {
194194
if (dst_type == src_type) {

ext/ffi/php_ffi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,4 +401,6 @@ typedef struct _zend_ffi_scope {
401401
#define ZEND_FFI_TYPE_IS_OWNED(t) \
402402
(((uintptr_t)(t)) & ZEND_FFI_TYPE_OWNED)
403403

404+
PHP_FFI_API bool zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type);
405+
404406
#endif /* PHP_FFI_H */

ext/opcache/jit/zend_jit.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,39 @@ typedef struct zend_jit_ffi_info {
5151
zend_ffi_type *type;
5252
uint32_t info;
5353
} zend_jit_ffi_info;
54+
55+
static bool zend_jit_ffi_supported_type(zend_ffi_type *type) {
56+
#if defined(IR_TARGET_X86)
57+
if (ZEND_FFI_TYPE(type->kind == ZEND_FFI_TYPE_UINT64)
58+
|| ZEND_FFI_TYPE(type->kind == ZEND_FFI_TYPE_SINT64)) {
59+
return false;
60+
}
61+
#endif
62+
return true;
63+
}
64+
65+
static bool zend_jit_ffi_compatible(zend_ffi_type *dst_type, uint32_t src_info, zend_ffi_type *src_type)
66+
{
67+
dst_type = ZEND_FFI_TYPE(dst_type);
68+
if (!zend_jit_ffi_supported_type(dst_type)) {
69+
return false;
70+
} else if (src_info == MAY_BE_LONG || src_info == MAY_BE_DOUBLE) {
71+
return dst_type->kind < ZEND_FFI_TYPE_POINTER && dst_type->kind != ZEND_FFI_TYPE_VOID;
72+
} else if (src_info == MAY_BE_FALSE || src_info == MAY_BE_TRUE || src_info == (MAY_BE_FALSE|MAY_BE_TRUE)) {
73+
return dst_type->kind == ZEND_FFI_TYPE_BOOL;
74+
} else if (src_type) {
75+
if (!zend_jit_ffi_supported_type(src_type)) {
76+
return false;
77+
}
78+
if (src_type->kind >= ZEND_FFI_TYPE_POINTER) {
79+
return false;
80+
}
81+
if (dst_type == src_type || zend_ffi_is_compatible_type(dst_type, src_type)) {
82+
return true;
83+
}
84+
}
85+
return false;
86+
}
5487
#endif
5588

5689
#ifdef HAVE_PTHREAD_JIT_WRITE_PROTECT_NP

ext/opcache/jit/zend_jit_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,10 @@ typedef enum _zend_jit_trace_op {
345345
ZEND_JIT_TRACE_VM,
346346
ZEND_JIT_TRACE_OP1_TYPE,
347347
ZEND_JIT_TRACE_OP2_TYPE,
348+
ZEND_JIT_TRACE_OP3_TYPE,
348349
ZEND_JIT_TRACE_OP1_FFI_TYPE,
349350
ZEND_JIT_TRACE_OP2_FFI_TYPE,
351+
ZEND_JIT_TRACE_OP3_FFI_TYPE,
350352
ZEND_JIT_TRACE_VAL_INFO,
351353
ZEND_JIT_TRACE_INIT_CALL,
352354
ZEND_JIT_TRACE_DO_ICALL,

ext/opcache/jit/zend_jit_ir.c

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12552,6 +12552,16 @@ static int zend_jit_ffi_read(zend_jit_ctx *jit,
1255212552
res_type = IS_LONG;
1255312553
break;
1255412554
#endif
12555+
case ZEND_FFI_TYPE_BOOL:
12556+
jit_set_Z_TYPE_INFO(jit, res_addr,
12557+
ir_ADD_U32(ir_ZEXT_U32(ir_LOAD_U8(ptr)), ir_CONST_U32(IS_FALSE)));
12558+
return 1;
12559+
case ZEND_FFI_TYPE_CHAR:
12560+
jit_set_Z_PTR(jit, res_addr, ir_LOAD_A(
12561+
ir_ADD_A(ir_CONST_ADDR(zend_one_char_string),
12562+
ir_MUL_L(ir_ZEXT_L(ir_LOAD_U8(ptr)), ir_CONST_LONG(sizeof(void*))))));
12563+
res_type = IS_STRING;
12564+
break;
1255512565
default:
1255612566
ZEND_UNREACHABLE();
1255712567
}
@@ -12606,6 +12616,11 @@ static int zend_jit_ffi_guard(zend_jit_ctx *jit,
1260612616
return 1;
1260712617
}
1260812618

12619+
static ir_ref jit_FFI_CDATA_PTR(zend_jit_ctx *jit, ir_ref obj_ref)
12620+
{
12621+
return ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
12622+
}
12623+
1260912624
static int zend_jit_ffi_fetch_dim_read(zend_jit_ctx *jit,
1261012625
const zend_op *opline,
1261112626
zend_ssa *ssa,
@@ -12632,7 +12647,8 @@ static int zend_jit_ffi_fetch_dim_read(zend_jit_ctx *jit,
1263212647
return 0;
1263312648
}
1263412649

12635-
ir_ref cdata_ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
12650+
ir_ref cdata_ref = jit_FFI_CDATA_PTR(jit, obj_ref);
12651+
// ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
1263612652

1263712653
if (op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER) {
1263812654
cdata_ref = ir_LOAD_A(cdata_ref);
@@ -13318,14 +13334,17 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1331813334
zend_ffi_type *ffi_type,
1331913335
ir_ref ptr,
1332013336
uint32_t val_info,
13321-
zend_jit_addr val_addr)
13337+
zend_jit_addr val_addr,
13338+
zend_ffi_type *val_ffi_type)
1332213339
{
1332313340
switch (ffi_type->kind) {
1332413341
case ZEND_FFI_TYPE_FLOAT:
1332513342
if (val_info == MAY_BE_LONG) {
1332613343
ir_STORE(ptr, ir_INT2F(jit_Z_LVAL(jit, val_addr)));
1332713344
} else if (val_info == MAY_BE_DOUBLE) {
1332813345
ir_STORE(ptr, ir_D2F(jit_Z_DVAL(jit, val_addr)));
13346+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13347+
ir_STORE(ptr, ir_LOAD_F(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1332913348
} else {
1333013349
ZEND_UNREACHABLE();
1333113350
}
@@ -13335,34 +13354,57 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1333513354
ir_STORE(ptr, ir_INT2D(jit_Z_LVAL(jit, val_addr)));
1333613355
} else if (val_info == MAY_BE_DOUBLE) {
1333713356
ir_STORE(ptr, jit_Z_DVAL(jit, val_addr));
13357+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13358+
ir_STORE(ptr, ir_LOAD_D(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1333813359
} else {
1333913360
ZEND_UNREACHABLE();
1334013361
}
1334113362
break;
13363+
case ZEND_FFI_TYPE_BOOL:
13364+
if (val_info == MAY_BE_FALSE) {
13365+
ir_STORE(ptr, IR_FALSE);
13366+
return 1;
13367+
} else if (val_info == MAY_BE_TRUE) {
13368+
ir_STORE(ptr, IR_TRUE);
13369+
return 1;
13370+
} else if (val_info == (MAY_BE_FALSE|MAY_BE_TRUE)) {
13371+
ir_STORE(ptr, ir_SUB_U8(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(IS_FALSE)));
13372+
return 1;
13373+
}
13374+
ZEND_FALLTHROUGH;
1334213375
case ZEND_FFI_TYPE_UINT8:
1334313376
if (val_info == MAY_BE_LONG) {
1334413377
ir_STORE(ptr, ir_TRUNC_U8(jit_Z_LVAL(jit, val_addr)));
13378+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13379+
ir_STORE(ptr, ir_LOAD_U8(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1334513380
} else {
1334613381
ZEND_UNREACHABLE();
1334713382
}
1334813383
break;
1334913384
case ZEND_FFI_TYPE_SINT8:
13385+
case ZEND_FFI_TYPE_CHAR:
1335013386
if (val_info == MAY_BE_LONG) {
1335113387
ir_STORE(ptr, ir_TRUNC_I8(jit_Z_LVAL(jit, val_addr)));
13388+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13389+
ir_STORE(ptr, ir_LOAD_I8(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1335213390
} else {
1335313391
ZEND_UNREACHABLE();
1335413392
}
1335513393
break;
1335613394
case ZEND_FFI_TYPE_UINT16:
1335713395
if (val_info == MAY_BE_LONG) {
1335813396
ir_STORE(ptr, ir_TRUNC_U16(jit_Z_LVAL(jit, val_addr)));
13397+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13398+
ir_STORE(ptr, ir_LOAD_U16(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1335913399
} else {
1336013400
ZEND_UNREACHABLE();
1336113401
}
1336213402
break;
1336313403
case ZEND_FFI_TYPE_SINT16:
1336413404
if (val_info == MAY_BE_LONG) {
1336513405
ir_STORE(ptr, ir_TRUNC_I16(jit_Z_LVAL(jit, val_addr)));
13406+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13407+
ir_STORE(ptr, ir_LOAD_I16(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1336613408
} else {
1336713409
ZEND_UNREACHABLE();
1336813410
}
@@ -13371,13 +13413,17 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1337113413
case ZEND_FFI_TYPE_UINT32:
1337213414
if (val_info == MAY_BE_LONG) {
1337313415
ir_STORE(ptr, ir_TRUNC_U32(jit_Z_LVAL(jit, val_addr)));
13416+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13417+
ir_STORE(ptr, ir_LOAD_U32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1337413418
} else {
1337513419
ZEND_UNREACHABLE();
1337613420
}
1337713421
break;
1337813422
case ZEND_FFI_TYPE_SINT32:
1337913423
if (val_info == MAY_BE_LONG) {
1338013424
ir_STORE(ptr, ir_TRUNC_I32(jit_Z_LVAL(jit, val_addr)));
13425+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13426+
ir_STORE(ptr, ir_LOAD_I32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1338113427
} else {
1338213428
ZEND_UNREACHABLE();
1338313429
}
@@ -13386,6 +13432,8 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1338613432
case ZEND_FFI_TYPE_SINT64:
1338713433
if (val_info == MAY_BE_LONG) {
1338813434
ir_STORE(ptr, jit_Z_LVAL(jit, val_addr));
13435+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13436+
ir_STORE(ptr, ir_LOAD_I64(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1338913437
} else {
1339013438
ZEND_UNREACHABLE();
1339113439
}
@@ -13395,6 +13443,8 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1339513443
case ZEND_FFI_TYPE_SINT32:
1339613444
if (val_info == MAY_BE_LONG) {
1339713445
ir_STORE(ptr, jit_Z_LVAL(jit, val_addr));
13446+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13447+
ir_STORE(ptr, ir_LOAD_I32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1339813448
} else {
1339913449
ZEND_UNREACHABLE();
1340013450
}
@@ -13421,6 +13471,7 @@ static int zend_jit_ffi_assign_dim(zend_jit_ctx *jit,
1342113471
zend_jit_addr val_def_addr,
1342213472
zend_jit_addr res_addr,
1342313473
zend_ffi_type *op1_ffi_type,
13474+
zend_ffi_type *val_ffi_type,
1342413475
zend_jit_ffi_info *ffi_info)
1342513476
{
1342613477
zend_ffi_type *el_type = ZEND_FFI_TYPE(op1_ffi_type->array.type);
@@ -13442,7 +13493,7 @@ static int zend_jit_ffi_assign_dim(zend_jit_ctx *jit,
1344213493

1344313494
ir_ref ptr = ir_ADD_A(cdata_ref, ir_MUL_L(jit_Z_LVAL(jit, op2_addr), ir_CONST_LONG(el_type->size)));
1344413495

13445-
if (!zend_jit_ffi_write(jit, el_type, ptr, val_info, val_addr)) {
13496+
if (!zend_jit_ffi_write(jit, el_type, ptr, val_info, val_addr, val_ffi_type)) {
1344613497
return 0;
1344713498
}
1344813499

@@ -13736,6 +13787,16 @@ static int zend_jit_ffi_assign_op_helper(zend_jit_ctx *jit,
1373613787
return 0;
1373713788
}
1373813789
break;
13790+
case ZEND_FFI_TYPE_BOOL:
13791+
type = IR_U8;
13792+
ZEND_ASSERT(opcode == ZEND_BW_AND || opcode == ZEND_BW_OR);
13793+
if (op2_info == MAY_BE_LONG) {
13794+
op2 = ir_TRUNC_U8(jit_Z_LVAL(jit, op2_addr));
13795+
} else {
13796+
ZEND_UNREACHABLE();
13797+
return 0;
13798+
}
13799+
break;
1373913800
case ZEND_FFI_TYPE_UINT8:
1374013801
type = IR_U8;
1374113802
if (op2_info == MAY_BE_LONG) {
@@ -13746,6 +13807,7 @@ static int zend_jit_ffi_assign_op_helper(zend_jit_ctx *jit,
1374613807
}
1374713808
break;
1374813809
case ZEND_FFI_TYPE_SINT8:
13810+
case ZEND_FFI_TYPE_CHAR:
1374913811
type = IR_I8;
1375013812
if (op2_info == MAY_BE_LONG) {
1375113813
op2 = ir_TRUNC_I8(jit_Z_LVAL(jit, op2_addr));
@@ -14872,6 +14934,7 @@ static int zend_jit_ffi_assign_obj(zend_jit_ctx *jit,
1487214934
zend_jit_addr val_def_addr,
1487314935
zend_jit_addr res_addr,
1487414936
zend_ffi_type *op1_ffi_type,
14937+
zend_ffi_type *val_ffi_type,
1487514938
zend_jit_ffi_info *ffi_info)
1487614939
{
1487714940
zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
@@ -14884,7 +14947,7 @@ static int zend_jit_ffi_assign_obj(zend_jit_ctx *jit,
1488414947
ir_ref cdata_ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
1488514948
ir_ref ptr = ir_ADD_A(cdata_ref, ir_CONST_LONG(field->offset));
1488614949

14887-
if (!zend_jit_ffi_write(jit, field_type, ptr, val_info, val_addr)) {
14950+
if (!zend_jit_ffi_write(jit, field_type, ptr, val_info, val_addr, val_ffi_type)) {
1488814951
return 0;
1488914952
}
1489014953

@@ -17567,13 +17630,10 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1756717630
zend_ffi_type *op1_ffi_type = (zend_ffi_type*)(trace+2)->ptr;
1756817631
if (op1_ffi_type
1756917632
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
17570-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind >= ZEND_FFI_TYPE_FLOAT
17571-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind <= ZEND_FFI_TYPE_ENUM
17572-
#if defined(IR_TARGET_X86)
17573-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_UINT64
17574-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_SINT64
17575-
#endif
17576-
&& op2_info == MAY_BE_LONG) {
17633+
&& op2_info == MAY_BE_LONG
17634+
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind < ZEND_FFI_TYPE_POINTER
17635+
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_VOID
17636+
&& zend_jit_ffi_supported_type(ZEND_FFI_TYPE(op1_ffi_type->array.type))) {
1757717637
return 1;
1757817638
}
1757917639
}
@@ -17629,20 +17689,19 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1762917689
&& (trace+1)->op == ZEND_JIT_TRACE_OP1_TYPE
1763017690
&& (trace+2)->op == ZEND_JIT_TRACE_OP1_FFI_TYPE) {
1763117691
zend_ffi_type *op1_ffi_type = (zend_ffi_type*)(trace+2)->ptr;
17692+
zend_ffi_type *op3_ffi_type = NULL;
17693+
uint32_t op1_data_info = OP1_DATA_INFO();
17694+
17695+
if ((trace+3)->op == ZEND_JIT_TRACE_OP3_TYPE
17696+
&& (trace+4)->op == ZEND_JIT_TRACE_OP3_FFI_TYPE) {
17697+
op3_ffi_type = (zend_ffi_type*)(trace+4)->ptr;
17698+
}
17699+
1763217700
if (op1_ffi_type
1763317701
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
17634-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind >= ZEND_FFI_TYPE_FLOAT
17635-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind <= ZEND_FFI_TYPE_ENUM
17636-
#if defined(IR_TARGET_X86)
17637-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_UINT64
17638-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_SINT64
17639-
#endif
17640-
&& op2_info == MAY_BE_LONG) {
17641-
uint32_t op1_data_info = OP1_DATA_INFO();
17642-
17643-
if (op1_data_info == MAY_BE_LONG || op1_data_info == MAY_BE_DOUBLE) {
17644-
return 1;
17645-
}
17702+
&& op2_info == MAY_BE_LONG
17703+
&& zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)) {
17704+
return 1;
1764617705
}
1764717706
}
1764817707
#endif

0 commit comments

Comments
 (0)