Skip to content

Commit 45f1f50

Browse files
committed
Support for assignment FFI CData to another CData array/struct
1 parent c5cf224 commit 45f1f50

File tree

7 files changed

+192
-75
lines changed

7 files changed

+192
-75
lines changed

ext/ffi/ffi.c

+2-2
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

+2
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

+33
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

+2
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

+82-23
Original file line numberDiff line numberDiff line change
@@ -12595,6 +12595,16 @@ static int zend_jit_ffi_read(zend_jit_ctx *jit,
1259512595
res_type = IS_LONG;
1259612596
break;
1259712597
#endif
12598+
case ZEND_FFI_TYPE_BOOL:
12599+
jit_set_Z_TYPE_INFO(jit, res_addr,
12600+
ir_ADD_U32(ir_ZEXT_U32(ir_LOAD_U8(ptr)), ir_CONST_U32(IS_FALSE)));
12601+
return 1;
12602+
case ZEND_FFI_TYPE_CHAR:
12603+
jit_set_Z_PTR(jit, res_addr, ir_LOAD_A(
12604+
ir_ADD_A(ir_CONST_ADDR(zend_one_char_string),
12605+
ir_MUL_L(ir_ZEXT_L(ir_LOAD_U8(ptr)), ir_CONST_LONG(sizeof(void*))))));
12606+
res_type = IS_STRING;
12607+
break;
1259812608
default:
1259912609
ZEND_UNREACHABLE();
1260012610
}
@@ -12649,6 +12659,11 @@ static int zend_jit_ffi_guard(zend_jit_ctx *jit,
1264912659
return 1;
1265012660
}
1265112661

12662+
static ir_ref jit_FFI_CDATA_PTR(zend_jit_ctx *jit, ir_ref obj_ref)
12663+
{
12664+
return ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
12665+
}
12666+
1265212667
static int zend_jit_ffi_fetch_dim_read(zend_jit_ctx *jit,
1265312668
const zend_op *opline,
1265412669
zend_ssa *ssa,
@@ -12675,7 +12690,8 @@ static int zend_jit_ffi_fetch_dim_read(zend_jit_ctx *jit,
1267512690
return 0;
1267612691
}
1267712692

12678-
ir_ref cdata_ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
12693+
ir_ref cdata_ref = jit_FFI_CDATA_PTR(jit, obj_ref);
12694+
// ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
1267912695

1268012696
if (op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER) {
1268112697
cdata_ref = ir_LOAD_A(cdata_ref);
@@ -13361,14 +13377,17 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1336113377
zend_ffi_type *ffi_type,
1336213378
ir_ref ptr,
1336313379
uint32_t val_info,
13364-
zend_jit_addr val_addr)
13380+
zend_jit_addr val_addr,
13381+
zend_ffi_type *val_ffi_type)
1336513382
{
1336613383
switch (ffi_type->kind) {
1336713384
case ZEND_FFI_TYPE_FLOAT:
1336813385
if (val_info == MAY_BE_LONG) {
1336913386
ir_STORE(ptr, ir_INT2F(jit_Z_LVAL(jit, val_addr)));
1337013387
} else if (val_info == MAY_BE_DOUBLE) {
1337113388
ir_STORE(ptr, ir_D2F(jit_Z_DVAL(jit, val_addr)));
13389+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13390+
ir_STORE(ptr, ir_LOAD_F(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1337213391
} else {
1337313392
ZEND_UNREACHABLE();
1337413393
}
@@ -13378,34 +13397,57 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1337813397
ir_STORE(ptr, ir_INT2D(jit_Z_LVAL(jit, val_addr)));
1337913398
} else if (val_info == MAY_BE_DOUBLE) {
1338013399
ir_STORE(ptr, jit_Z_DVAL(jit, val_addr));
13400+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13401+
ir_STORE(ptr, ir_LOAD_D(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1338113402
} else {
1338213403
ZEND_UNREACHABLE();
1338313404
}
1338413405
break;
13406+
case ZEND_FFI_TYPE_BOOL:
13407+
if (val_info == MAY_BE_FALSE) {
13408+
ir_STORE(ptr, IR_FALSE);
13409+
return 1;
13410+
} else if (val_info == MAY_BE_TRUE) {
13411+
ir_STORE(ptr, IR_TRUE);
13412+
return 1;
13413+
} else if (val_info == (MAY_BE_FALSE|MAY_BE_TRUE)) {
13414+
ir_STORE(ptr, ir_SUB_U8(jit_Z_TYPE(jit, val_addr), ir_CONST_U8(IS_FALSE)));
13415+
return 1;
13416+
}
13417+
ZEND_FALLTHROUGH;
1338513418
case ZEND_FFI_TYPE_UINT8:
1338613419
if (val_info == MAY_BE_LONG) {
1338713420
ir_STORE(ptr, ir_TRUNC_U8(jit_Z_LVAL(jit, val_addr)));
13421+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13422+
ir_STORE(ptr, ir_LOAD_U8(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1338813423
} else {
1338913424
ZEND_UNREACHABLE();
1339013425
}
1339113426
break;
1339213427
case ZEND_FFI_TYPE_SINT8:
13428+
case ZEND_FFI_TYPE_CHAR:
1339313429
if (val_info == MAY_BE_LONG) {
1339413430
ir_STORE(ptr, ir_TRUNC_I8(jit_Z_LVAL(jit, val_addr)));
13431+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13432+
ir_STORE(ptr, ir_LOAD_I8(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1339513433
} else {
1339613434
ZEND_UNREACHABLE();
1339713435
}
1339813436
break;
1339913437
case ZEND_FFI_TYPE_UINT16:
1340013438
if (val_info == MAY_BE_LONG) {
1340113439
ir_STORE(ptr, ir_TRUNC_U16(jit_Z_LVAL(jit, val_addr)));
13440+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13441+
ir_STORE(ptr, ir_LOAD_U16(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1340213442
} else {
1340313443
ZEND_UNREACHABLE();
1340413444
}
1340513445
break;
1340613446
case ZEND_FFI_TYPE_SINT16:
1340713447
if (val_info == MAY_BE_LONG) {
1340813448
ir_STORE(ptr, ir_TRUNC_I16(jit_Z_LVAL(jit, val_addr)));
13449+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13450+
ir_STORE(ptr, ir_LOAD_I16(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1340913451
} else {
1341013452
ZEND_UNREACHABLE();
1341113453
}
@@ -13414,13 +13456,17 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1341413456
case ZEND_FFI_TYPE_UINT32:
1341513457
if (val_info == MAY_BE_LONG) {
1341613458
ir_STORE(ptr, ir_TRUNC_U32(jit_Z_LVAL(jit, val_addr)));
13459+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13460+
ir_STORE(ptr, ir_LOAD_U32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1341713461
} else {
1341813462
ZEND_UNREACHABLE();
1341913463
}
1342013464
break;
1342113465
case ZEND_FFI_TYPE_SINT32:
1342213466
if (val_info == MAY_BE_LONG) {
1342313467
ir_STORE(ptr, ir_TRUNC_I32(jit_Z_LVAL(jit, val_addr)));
13468+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13469+
ir_STORE(ptr, ir_LOAD_I32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1342413470
} else {
1342513471
ZEND_UNREACHABLE();
1342613472
}
@@ -13429,6 +13475,8 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1342913475
case ZEND_FFI_TYPE_SINT64:
1343013476
if (val_info == MAY_BE_LONG) {
1343113477
ir_STORE(ptr, jit_Z_LVAL(jit, val_addr));
13478+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13479+
ir_STORE(ptr, ir_LOAD_I64(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1343213480
} else {
1343313481
ZEND_UNREACHABLE();
1343413482
}
@@ -13438,6 +13486,8 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
1343813486
case ZEND_FFI_TYPE_SINT32:
1343913487
if (val_info == MAY_BE_LONG) {
1344013488
ir_STORE(ptr, jit_Z_LVAL(jit, val_addr));
13489+
} else if (val_ffi_type && val_ffi_type->kind == ffi_type->kind) {
13490+
ir_STORE(ptr, ir_LOAD_I32(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr))));
1344113491
} else {
1344213492
ZEND_UNREACHABLE();
1344313493
}
@@ -13464,6 +13514,7 @@ static int zend_jit_ffi_assign_dim(zend_jit_ctx *jit,
1346413514
zend_jit_addr val_def_addr,
1346513515
zend_jit_addr res_addr,
1346613516
zend_ffi_type *op1_ffi_type,
13517+
zend_ffi_type *val_ffi_type,
1346713518
zend_jit_ffi_info *ffi_info)
1346813519
{
1346913520
zend_ffi_type *el_type = ZEND_FFI_TYPE(op1_ffi_type->array.type);
@@ -13485,7 +13536,7 @@ static int zend_jit_ffi_assign_dim(zend_jit_ctx *jit,
1348513536

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

13488-
if (!zend_jit_ffi_write(jit, el_type, ptr, val_info, val_addr)) {
13539+
if (!zend_jit_ffi_write(jit, el_type, ptr, val_info, val_addr, val_ffi_type)) {
1348913540
return 0;
1349013541
}
1349113542

@@ -13779,6 +13830,16 @@ static int zend_jit_ffi_assign_op_helper(zend_jit_ctx *jit,
1377913830
return 0;
1378013831
}
1378113832
break;
13833+
case ZEND_FFI_TYPE_BOOL:
13834+
type = IR_U8;
13835+
ZEND_ASSERT(opcode == ZEND_BW_AND || opcode == ZEND_BW_OR);
13836+
if (op2_info == MAY_BE_LONG) {
13837+
op2 = ir_TRUNC_U8(jit_Z_LVAL(jit, op2_addr));
13838+
} else {
13839+
ZEND_UNREACHABLE();
13840+
return 0;
13841+
}
13842+
break;
1378213843
case ZEND_FFI_TYPE_UINT8:
1378313844
type = IR_U8;
1378413845
if (op2_info == MAY_BE_LONG) {
@@ -13789,6 +13850,7 @@ static int zend_jit_ffi_assign_op_helper(zend_jit_ctx *jit,
1378913850
}
1379013851
break;
1379113852
case ZEND_FFI_TYPE_SINT8:
13853+
case ZEND_FFI_TYPE_CHAR:
1379213854
type = IR_I8;
1379313855
if (op2_info == MAY_BE_LONG) {
1379413856
op2 = ir_TRUNC_I8(jit_Z_LVAL(jit, op2_addr));
@@ -14917,6 +14979,7 @@ static int zend_jit_ffi_assign_obj(zend_jit_ctx *jit,
1491714979
zend_jit_addr val_def_addr,
1491814980
zend_jit_addr res_addr,
1491914981
zend_ffi_type *op1_ffi_type,
14982+
zend_ffi_type *val_ffi_type,
1492014983
zend_jit_ffi_info *ffi_info)
1492114984
{
1492214985
zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
@@ -14929,7 +14992,7 @@ static int zend_jit_ffi_assign_obj(zend_jit_ctx *jit,
1492914992
ir_ref cdata_ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
1493014993
ir_ref ptr = ir_ADD_A(cdata_ref, ir_CONST_LONG(field->offset));
1493114994

14932-
if (!zend_jit_ffi_write(jit, field_type, ptr, val_info, val_addr)) {
14995+
if (!zend_jit_ffi_write(jit, field_type, ptr, val_info, val_addr, val_ffi_type)) {
1493314996
return 0;
1493414997
}
1493514998

@@ -17612,13 +17675,10 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1761217675
zend_ffi_type *op1_ffi_type = (zend_ffi_type*)(trace+2)->ptr;
1761317676
if (op1_ffi_type
1761417677
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
17615-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind >= ZEND_FFI_TYPE_FLOAT
17616-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind <= ZEND_FFI_TYPE_ENUM
17617-
#if defined(IR_TARGET_X86)
17618-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_UINT64
17619-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_SINT64
17620-
#endif
17621-
&& op2_info == MAY_BE_LONG) {
17678+
&& op2_info == MAY_BE_LONG
17679+
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind < ZEND_FFI_TYPE_POINTER
17680+
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_VOID
17681+
&& zend_jit_ffi_supported_type(ZEND_FFI_TYPE(op1_ffi_type->array.type))) {
1762217682
return 1;
1762317683
}
1762417684
}
@@ -17674,20 +17734,19 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1767417734
&& (trace+1)->op == ZEND_JIT_TRACE_OP1_TYPE
1767517735
&& (trace+2)->op == ZEND_JIT_TRACE_OP1_FFI_TYPE) {
1767617736
zend_ffi_type *op1_ffi_type = (zend_ffi_type*)(trace+2)->ptr;
17737+
zend_ffi_type *op3_ffi_type = NULL;
17738+
uint32_t op1_data_info = OP1_DATA_INFO();
17739+
17740+
if ((trace+3)->op == ZEND_JIT_TRACE_OP3_TYPE
17741+
&& (trace+4)->op == ZEND_JIT_TRACE_OP3_FFI_TYPE) {
17742+
op3_ffi_type = (zend_ffi_type*)(trace+4)->ptr;
17743+
}
17744+
1767717745
if (op1_ffi_type
1767817746
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
17679-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind >= ZEND_FFI_TYPE_FLOAT
17680-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind <= ZEND_FFI_TYPE_ENUM
17681-
#if defined(IR_TARGET_X86)
17682-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_UINT64
17683-
&& ZEND_FFI_TYPE(op1_ffi_type->array.type)->kind != ZEND_FFI_TYPE_SINT64
17684-
#endif
17685-
&& op2_info == MAY_BE_LONG) {
17686-
uint32_t op1_data_info = OP1_DATA_INFO();
17687-
17688-
if (op1_data_info == MAY_BE_LONG || op1_data_info == MAY_BE_DOUBLE) {
17689-
return 1;
17690-
}
17747+
&& op2_info == MAY_BE_LONG
17748+
&& zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)) {
17749+
return 1;
1769117750
}
1769217751
}
1769317752
#endif

0 commit comments

Comments
 (0)