Skip to content

Commit be7d6c3

Browse files
committed
Improve FFI type compatibility checks
1 parent a30ca8b commit be7d6c3

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
@@ -4930,8 +4930,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
49304930
if (op1_ffi_type
49314931
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
49324932
&& op2_info == MAY_BE_LONG
4933-
&& (zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)
4934-
|| zend_jit_ffi_compatible_addr_op(op1_ffi_type->array.type, op1_data_info, op3_ffi_type, opline->extended_value))) {
4933+
&& zend_jit_ffi_compatible_op(op1_ffi_type->array.type, op1_data_info, op3_ffi_type, opline->extended_value)) {
49354934
if (!ffi_info) {
49364935
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
49374936
}
@@ -5198,8 +5197,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
51985197
if (field
51995198
&& !field->is_const
52005199
&& !field->bits
5201-
&& (zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)
5202-
|| zend_jit_ffi_compatible_addr_op(field->type, op1_data_info, op3_ffi_type, opline->extended_value))) {
5200+
&& zend_jit_ffi_compatible_op(field->type, op1_data_info, op3_ffi_type, opline->extended_value)) {
52035201
if (!ffi_info) {
52045202
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
52055203
}
@@ -5231,8 +5229,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
52315229
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
52325230
if (sym
52335231
&& sym->kind == ZEND_FFI_SYM_VAR
5234-
&& (zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)
5235-
|| zend_jit_ffi_compatible_addr_op(sym->type, op1_data_info, op3_ffi_type, opline->extended_value))) {
5232+
&& zend_jit_ffi_compatible_op(sym->type, op1_data_info, op3_ffi_type, opline->extended_value)) {
52365233
if (!ffi_info) {
52375234
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
52385235
}
@@ -5337,8 +5334,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
53375334
if (field
53385335
&& !field->is_const
53395336
&& !field->bits
5340-
&& (zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)
5341-
|| zend_jit_ffi_compatible_addr(field->type, op1_data_info, op3_ffi_type))) {
5337+
&& zend_jit_ffi_compatible(field->type, op1_data_info, op3_ffi_type)) {
53425338
if (!ffi_info) {
53435339
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
53445340
}
@@ -5382,8 +5378,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
53825378
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
53835379
if (sym
53845380
&& sym->kind == ZEND_FFI_SYM_VAR
5385-
&& (zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)
5386-
|| zend_jit_ffi_compatible_addr(sym->type, op1_data_info, op3_ffi_type))) {
5381+
&& zend_jit_ffi_compatible(sym->type, op1_data_info, op3_ffi_type)) {
53875382
if (!ffi_info) {
53885383
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
53895384
}
@@ -5458,8 +5453,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
54585453
if (op1_ffi_type
54595454
&& (op1_ffi_type->kind == ZEND_FFI_TYPE_ARRAY || op1_ffi_type->kind == ZEND_FFI_TYPE_POINTER)
54605455
&& op2_info == MAY_BE_LONG
5461-
&& (zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)
5462-
|| zend_jit_ffi_compatible_addr(op1_ffi_type->array.type, op1_data_info, op3_ffi_type))) {
5456+
&& zend_jit_ffi_compatible(op1_ffi_type->array.type, op1_data_info, op3_ffi_type)) {
54635457
if (!ffi_info) {
54645458
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
54655459
}

0 commit comments

Comments
 (0)