Skip to content

Commit 247927e

Browse files
committed
Improve FFI type compatibility checks
1 parent 453226a commit 247927e

File tree

3 files changed

+57
-42
lines changed

3 files changed

+57
-42
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -115,51 +115,55 @@ static bool zend_jit_ffi_compatible(zend_ffi_type *dst_type, uint32_t src_info,
115115
} else if ((src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
116116
|| (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) {
117117
return dst_type->kind < ZEND_FFI_TYPE_POINTER && dst_type->kind != ZEND_FFI_TYPE_VOID;
118-
} else if (src_info == MAY_BE_FALSE || src_info == MAY_BE_TRUE || src_info == (MAY_BE_FALSE|MAY_BE_TRUE)) {
118+
} else if ((src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_FALSE
119+
|| (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_TRUE
120+
|| (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == (MAY_BE_FALSE|MAY_BE_TRUE)) {
119121
return dst_type->kind == ZEND_FFI_TYPE_BOOL;
122+
} else if ((src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING) {
123+
return dst_type->kind == ZEND_FFI_TYPE_CHAR;
124+
} else if ((src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_NULL) {
125+
return dst_type->kind == ZEND_FFI_TYPE_POINTER;
120126
} else if (src_type) {
121127
if (!zend_jit_ffi_supported_type(src_type)) {
122128
return false;
123129
}
124-
if (src_type->kind >= ZEND_FFI_TYPE_POINTER) {
125-
return false;
126-
}
127130
if (dst_type == src_type
128-
// TODO: calls between shared extensions doesn't work on Windows
129-
// || zend_ffi_is_compatible_type(dst_type, src_type)
130-
) {
131+
|| zend_ffi_api->is_compatible_type(dst_type, src_type)) {
131132
return true;
132133
}
133134
}
134135
return false;
135136
}
136137

137-
static bool zend_jit_ffi_compatible_addr(zend_ffi_type *dst_type, uint32_t src_info, zend_ffi_type *src_type)
138+
static bool zend_jit_ffi_compatible_op(zend_ffi_type *dst_type, uint32_t src_info, zend_ffi_type *src_type, uint8_t op)
138139
{
139-
if (dst_type->kind == ZEND_FFI_TYPE_POINTER) {
140-
if (src_info == MAY_BE_NULL) {
141-
return true;
142-
} else if (src_type
143-
&& src_type->kind == ZEND_FFI_TYPE_POINTER
144-
&& (dst_type == src_type
145-
|| ZEND_FFI_TYPE(dst_type->pointer.type) == ZEND_FFI_TYPE(src_type->pointer.type)
146-
|| ZEND_FFI_TYPE(dst_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID
147-
|| ZEND_FFI_TYPE(src_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID
148-
// TODO: calls between shared extensions doesn't work on Windows
149-
// || zend_ffi_is_compatible_type(dst_type, src_type)
150-
)) {
151-
return true;
152-
}
153-
}
154-
return false;
155-
}
156-
157-
static bool zend_jit_ffi_compatible_addr_op(zend_ffi_type *dst_type, uint32_t src_info, zend_ffi_type *src_type, uint8_t opcode)
158-
{
159-
if (dst_type->kind == ZEND_FFI_TYPE_POINTER
140+
dst_type = ZEND_FFI_TYPE(dst_type);
141+
if (!zend_jit_ffi_supported_type(dst_type)) {
142+
return false;
143+
} else if (dst_type->kind == ZEND_FFI_TYPE_FLOAT || dst_type->kind == ZEND_FFI_TYPE_DOUBLE) {
144+
return (op == ZEND_ADD || op == ZEND_SUB || op == ZEND_MUL)
145+
&& ((src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE
146+
|| (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG);
147+
} else if (dst_type->kind == ZEND_FFI_TYPE_BOOL) {
148+
return (op == ZEND_BW_AND || op == ZEND_BW_OR)
149+
&& (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG;
150+
} else if (dst_type->kind == ZEND_FFI_TYPE_UINT8
151+
|| dst_type->kind == ZEND_FFI_TYPE_UINT16
152+
|| dst_type->kind == ZEND_FFI_TYPE_UINT32
153+
|| dst_type->kind == ZEND_FFI_TYPE_UINT64
154+
|| dst_type->kind == ZEND_FFI_TYPE_SINT8
155+
|| dst_type->kind == ZEND_FFI_TYPE_SINT16
156+
|| dst_type->kind == ZEND_FFI_TYPE_SINT32
157+
|| dst_type->kind == ZEND_FFI_TYPE_SINT64
158+
|| dst_type->kind == ZEND_FFI_TYPE_CHAR) {
159+
return (op == ZEND_ADD || op == ZEND_SUB || op == ZEND_MUL
160+
|| op == ZEND_BW_AND || op == ZEND_BW_OR || op == ZEND_BW_XOR
161+
|| op == ZEND_SL || op == ZEND_SR || op == ZEND_MOD)
162+
&& (src_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG;
163+
} else if (dst_type->kind == ZEND_FFI_TYPE_POINTER
160164
&& ZEND_FFI_TYPE(dst_type->pointer.type)->size != 0
161165
&& src_info == MAY_BE_LONG
162-
&& (opcode == ZEND_ADD || opcode == ZEND_SUB)) {
166+
&& (op == ZEND_ADD || op == ZEND_SUB)) {
163167
return true;
164168
}
165169
return false;

ext/opcache/jit/zend_jit_ir_ffi.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1292,6 +1292,11 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
12921292
|| ZEND_FFI_TYPE(val_ffi_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID
12931293
|| ZEND_FFI_TYPE(ffi_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID)) {
12941294
ref = ir_LOAD_A(jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr)));
1295+
} else if (val_ffi_type
1296+
&& val_ffi_type->kind == ZEND_FFI_TYPE_ARRAY
1297+
&& (ZEND_FFI_TYPE(val_ffi_type->pointer.type) == ZEND_FFI_TYPE(ffi_type->pointer.type)
1298+
|| ZEND_FFI_TYPE(ffi_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID)) {
1299+
ref = jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr));
12951300
} else {
12961301
ZEND_UNREACHABLE();
12971302
}
@@ -1302,6 +1307,18 @@ static int zend_jit_ffi_write(zend_jit_ctx *jit,
13021307
}
13031308
break;
13041309
default:
1310+
if (val_ffi_type
1311+
&& (val_ffi_type == ffi_type
1312+
|| (zend_ffi_api->is_compatible_type(ffi_type, val_ffi_type)
1313+
&& ffi_type->size == val_ffi_type->size))) {
1314+
ref = jit_FFI_CDATA_PTR(jit, jit_Z_PTR(jit, val_addr));
1315+
ir_CALL_3(IR_ADDR, ir_CONST_FUNC(memcpy), ptr, ref, ir_CONST_LONG(ffi_type->size));
1316+
if (res_addr) {
1317+
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_zval_ffi_obj),
1318+
jit_ZVAL_ADDR(jit, res_addr), ir_CONST_ADDR(ffi_type), ref);
1319+
}
1320+
break;
1321+
}
13051322
ZEND_UNREACHABLE();
13061323
}
13071324

ext/opcache/jit/zend_jit_trace.c

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4920,8 +4920,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
49204920
if (op1_ffi_type
49214921
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
49224922
&& op2_info == MAY_BE_LONG
4923-
&& (zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)
4924-
|| zend_jit_ffi_compatible_addr_op(op1_ffi_type->array.type, op1_data_info, op3_ffi_type, opline->extended_value))) {
4923+
&& zend_jit_ffi_compatible_op(op1_ffi_type->array.type, op1_data_info, op3_ffi_type, opline->extended_value)) {
49254924
if (!ffi_info) {
49264925
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
49274926
}
@@ -5191,8 +5190,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
51915190
if (field
51925191
&& !field->is_const
51935192
&& !field->bits
5194-
&& (zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)
5195-
|| zend_jit_ffi_compatible_addr_op(field->type, op1_data_info, op3_ffi_type, opline->extended_value))) {
5193+
&& zend_jit_ffi_compatible_op(field->type, op1_data_info, op3_ffi_type, opline->extended_value)) {
51965194
if (!ffi_info) {
51975195
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
51985196
}
@@ -5224,8 +5222,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
52245222
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
52255223
if (sym
52265224
&& sym->kind == ZEND_FFI_SYM_VAR
5227-
&& (zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)
5228-
|| zend_jit_ffi_compatible_addr_op(sym->type, op1_data_info, op3_ffi_type, opline->extended_value))) {
5225+
&& zend_jit_ffi_compatible_op(sym->type, op1_data_info, op3_ffi_type, opline->extended_value)) {
52295226
if (!ffi_info) {
52305227
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
52315228
}
@@ -5330,8 +5327,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
53305327
if (field
53315328
&& !field->is_const
53325329
&& !field->bits
5333-
&& (zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)
5334-
|| zend_jit_ffi_compatible_addr(field->type, op1_data_info, op3_ffi_type))) {
5330+
&& zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)) {
53355331
if (!ffi_info) {
53365332
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
53375333
}
@@ -5375,8 +5371,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
53755371
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
53765372
if (sym
53775373
&& sym->kind == ZEND_FFI_SYM_VAR
5378-
&& (zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)
5379-
|| zend_jit_ffi_compatible_addr(sym->type, op1_data_info, op3_ffi_type))) {
5374+
&& zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)) {
53805375
if (!ffi_info) {
53815376
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
53825377
}
@@ -5451,8 +5446,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
54515446
if (op1_ffi_type
54525447
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
54535448
&& op2_info == MAY_BE_LONG
5454-
&& (zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)
5455-
|| zend_jit_ffi_compatible_addr(op1_ffi_type->array.type, op1_data_info, op3_ffi_type))) {
5449+
&& zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)) {
54565450
if (!ffi_info) {
54575451
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
54585452
}

0 commit comments

Comments
 (0)