Skip to content

Commit 0b324f4

Browse files
committed
FFI JIT for PRE/POST_INC/DEC_OBJ
1 parent 437e080 commit 0b324f4

File tree

2 files changed

+316
-0
lines changed

2 files changed

+316
-0
lines changed

ext/opcache/jit/zend_jit_ir.c

+269
Original file line numberDiff line numberDiff line change
@@ -16556,6 +16556,275 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1655616556
return 1;
1655716557
}
1655816558

16559+
#ifdef HAVE_FFI
16560+
static int zend_jit_ffi_incdec_helper(zend_jit_ctx *jit,
16561+
const zend_op *opline,
16562+
uint8_t opcode,
16563+
zend_ffi_type *el_type,
16564+
ir_ref op1,
16565+
zend_jit_addr res_addr)
16566+
{
16567+
ir_op op;
16568+
ir_type type;
16569+
ir_ref op2;
16570+
ir_ref ref = IR_UNUSED;
16571+
16572+
switch (opcode) {
16573+
case ZEND_PRE_INC_OBJ:
16574+
case ZEND_POST_INC_OBJ:
16575+
op = IR_ADD;
16576+
break;
16577+
case ZEND_PRE_DEC_OBJ:
16578+
case ZEND_POST_DEC_OBJ:
16579+
op = IR_SUB;
16580+
break;
16581+
default:
16582+
ZEND_UNREACHABLE();
16583+
return 0;
16584+
}
16585+
16586+
switch (el_type->kind) {
16587+
case ZEND_FFI_TYPE_FLOAT:
16588+
type = IR_FLOAT;
16589+
op2 = ir_CONST_FLOAT(1.0);
16590+
break;
16591+
case ZEND_FFI_TYPE_DOUBLE:
16592+
type = IR_DOUBLE;
16593+
op2 = ir_CONST_DOUBLE(1.0);
16594+
break;
16595+
case ZEND_FFI_TYPE_UINT8:
16596+
type = IR_U8;
16597+
op2 = ir_CONST_U8(1);
16598+
break;
16599+
case ZEND_FFI_TYPE_SINT8:
16600+
case ZEND_FFI_TYPE_CHAR:
16601+
type = IR_I8;
16602+
op2 = ir_CONST_I8(1);
16603+
break;
16604+
case ZEND_FFI_TYPE_UINT16:
16605+
type = IR_U16;
16606+
op2 = ir_CONST_U16(1);
16607+
break;
16608+
case ZEND_FFI_TYPE_SINT16:
16609+
type = IR_I16;
16610+
op2 = ir_CONST_I16(1);
16611+
break;
16612+
case ZEND_FFI_TYPE_UINT32:
16613+
type = IR_U32;
16614+
op2 = ir_CONST_U32(1);
16615+
break;
16616+
case ZEND_FFI_TYPE_SINT32:
16617+
type = IR_I32;
16618+
op2 = ir_CONST_I32(1);
16619+
break;
16620+
case ZEND_FFI_TYPE_UINT64:
16621+
type = IR_U64;
16622+
op2 = ir_CONST_U64(1);
16623+
break;
16624+
case ZEND_FFI_TYPE_SINT64:
16625+
type = IR_I64;
16626+
op2 = ir_CONST_I64(1);
16627+
break;
16628+
case ZEND_FFI_TYPE_POINTER:
16629+
ZEND_ASSERT(ZEND_FFI_TYPE(el_type->pointer.type)->size != 0);
16630+
type = IR_ADDR;
16631+
op2 = ir_CONST_LONG(ZEND_FFI_TYPE(el_type->pointer.type)->size);
16632+
break;
16633+
default:
16634+
ZEND_UNREACHABLE();
16635+
return 0;
16636+
}
16637+
16638+
ref = ir_LOAD(type, op1);
16639+
16640+
if (res_addr && (opcode == ZEND_POST_INC_OBJ || opcode == ZEND_POST_DEC_OBJ)) {
16641+
uint32_t res_type = IS_UNDEF;
16642+
16643+
switch (type) {
16644+
case IR_FLOAT:
16645+
jit_set_Z_DVAL(jit, res_addr, ir_F2D(ref));
16646+
res_type = IS_DOUBLE;
16647+
break;
16648+
case IR_DOUBLE:
16649+
jit_set_Z_DVAL(jit, res_addr, ref);
16650+
res_type = IS_DOUBLE;
16651+
break;
16652+
case IR_I8:
16653+
case IR_I16:
16654+
#ifdef ZEND_ENABLE_ZVAL_LONG64
16655+
case IR_I32:
16656+
jit_set_Z_LVAL(jit, res_addr, ir_SEXT_L(ref));
16657+
res_type = IS_LONG;
16658+
break;
16659+
case IR_I64:
16660+
#else
16661+
case IR_I32:
16662+
#endif
16663+
jit_set_Z_LVAL(jit, res_addr, ref);
16664+
res_type = IS_LONG;
16665+
break;
16666+
case IR_U8:
16667+
case IR_U16:
16668+
#ifdef ZEND_ENABLE_ZVAL_LONG64
16669+
case IR_U32:
16670+
jit_set_Z_LVAL(jit, res_addr, ir_ZEXT_L(ref));
16671+
res_type = IS_LONG;
16672+
break;
16673+
case IR_U64:
16674+
#else
16675+
case IR_U32:
16676+
#endif
16677+
jit_set_Z_LVAL(jit, res_addr, ref);
16678+
res_type = IS_LONG;
16679+
break;
16680+
case IR_ADDR:
16681+
if ((el_type->attr & ZEND_FFI_ATTR_CONST)
16682+
&& ZEND_FFI_TYPE(el_type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
16683+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_zval_string), jit_ZVAL_ADDR(jit, res_addr), ref);
16684+
} else {
16685+
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_zval_ffi_ptr),
16686+
jit_ZVAL_ADDR(jit, res_addr), ir_CONST_ADDR(el_type), ref);
16687+
}
16688+
break;
16689+
default:
16690+
ZEND_UNREACHABLE();
16691+
return 0;
16692+
}
16693+
if (res_type && Z_MODE(res_addr) != IS_REG) {
16694+
jit_set_Z_TYPE_INFO(jit, res_addr, res_type);
16695+
}
16696+
}
16697+
16698+
ref = ir_BINARY_OP(op, type, ref, op2);
16699+
ir_STORE(op1, ref);
16700+
16701+
if (res_addr && (opcode == ZEND_PRE_INC_OBJ || opcode == ZEND_PRE_DEC_OBJ)) {
16702+
uint32_t res_type = IS_UNDEF;
16703+
16704+
switch (type) {
16705+
case IR_FLOAT:
16706+
jit_set_Z_DVAL(jit, res_addr, ir_F2D(ref));
16707+
res_type = IS_DOUBLE;
16708+
break;
16709+
case IR_DOUBLE:
16710+
jit_set_Z_DVAL(jit, res_addr, ref);
16711+
res_type = IS_DOUBLE;
16712+
break;
16713+
case IR_I8:
16714+
case IR_I16:
16715+
#ifdef ZEND_ENABLE_ZVAL_LONG64
16716+
case IR_I32:
16717+
jit_set_Z_LVAL(jit, res_addr, ir_SEXT_L(ref));
16718+
res_type = IS_LONG;
16719+
break;
16720+
case IR_I64:
16721+
#else
16722+
case IR_I32:
16723+
#endif
16724+
jit_set_Z_LVAL(jit, res_addr, ref);
16725+
res_type = IS_LONG;
16726+
break;
16727+
case IR_U8:
16728+
case IR_U16:
16729+
#ifdef ZEND_ENABLE_ZVAL_LONG64
16730+
case IR_U32:
16731+
jit_set_Z_LVAL(jit, res_addr, ir_ZEXT_L(ref));
16732+
res_type = IS_LONG;
16733+
break;
16734+
case IR_U64:
16735+
#else
16736+
case IR_U32:
16737+
#endif
16738+
jit_set_Z_LVAL(jit, res_addr, ref);
16739+
res_type = IS_LONG;
16740+
break;
16741+
case IR_ADDR:
16742+
if ((el_type->attr & ZEND_FFI_ATTR_CONST)
16743+
&& ZEND_FFI_TYPE(el_type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
16744+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_zval_string), jit_ZVAL_ADDR(jit, res_addr), ref);
16745+
} else {
16746+
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_zval_ffi_ptr),
16747+
jit_ZVAL_ADDR(jit, res_addr), ir_CONST_ADDR(el_type), ref);
16748+
}
16749+
break;
16750+
default:
16751+
ZEND_UNREACHABLE();
16752+
return 0;
16753+
}
16754+
if (res_type && Z_MODE(res_addr) != IS_REG) {
16755+
jit_set_Z_TYPE_INFO(jit, res_addr, res_type);
16756+
}
16757+
}
16758+
16759+
return 1;
16760+
}
16761+
16762+
static int zend_jit_ffi_incdec_obj(zend_jit_ctx *jit,
16763+
const zend_op *opline,
16764+
const zend_op_array *op_array,
16765+
zend_ssa *ssa,
16766+
const zend_ssa_op *ssa_op,
16767+
uint32_t op1_info,
16768+
zend_jit_addr op1_addr,
16769+
bool op1_indirect,
16770+
zend_ffi_field *field,
16771+
zend_jit_addr res_addr,
16772+
zend_ffi_type *op1_ffi_type,
16773+
zend_jit_ffi_info *ffi_info)
16774+
{
16775+
zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
16776+
ir_ref obj_ref = jit_Z_PTR(jit, op1_addr);
16777+
16778+
if (!zend_jit_ffi_guard(jit, opline, ssa, ssa_op->op1_use, ssa_op->op1_def, obj_ref, op1_ffi_type, ffi_info)) {
16779+
return 0;
16780+
}
16781+
16782+
ir_ref cdata_ref = ir_LOAD_A(ir_ADD_OFFSET(obj_ref, offsetof(zend_ffi_cdata, ptr)));
16783+
ir_ref ptr = ir_ADD_A(cdata_ref, ir_CONST_LONG(field->offset));
16784+
16785+
if (!zend_jit_ffi_incdec_helper(jit, opline, opline->opcode, field_type, ptr, res_addr)) {
16786+
return 0;
16787+
}
16788+
16789+
if (!op1_indirect) {
16790+
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
16791+
}
16792+
16793+
return 1;
16794+
}
16795+
16796+
static int zend_jit_ffi_incdec_sym(zend_jit_ctx *jit,
16797+
const zend_op *opline,
16798+
const zend_op_array *op_array,
16799+
zend_ssa *ssa,
16800+
const zend_ssa_op *ssa_op,
16801+
uint32_t op1_info,
16802+
zend_jit_addr op1_addr,
16803+
bool op1_indirect,
16804+
zend_ffi_symbol *sym,
16805+
zend_jit_addr res_addr,
16806+
HashTable *op1_ffi_symbols,
16807+
zend_jit_ffi_info *ffi_info)
16808+
{
16809+
zend_ffi_type *sym_type = ZEND_FFI_TYPE(sym->type);
16810+
16811+
if (!zend_jit_ffi_symbols_guard(jit, opline, ssa, ssa_op->op1_use, ssa_op->op1_def, op1_addr, op1_ffi_symbols, ffi_info)) {
16812+
return 0;
16813+
}
16814+
16815+
ir_ref ptr = ir_CONST_ADDR(sym->addr);
16816+
if (!zend_jit_ffi_incdec_helper(jit, opline, opline->opcode, sym_type, ptr, res_addr)) {
16817+
return 0;
16818+
}
16819+
16820+
if (!op1_indirect) {
16821+
jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline);
16822+
}
16823+
16824+
return 1;
16825+
}
16826+
#endif
16827+
1655916828
static int zend_jit_incdec_obj(zend_jit_ctx *jit,
1656016829
const zend_op *opline,
1656116830
const zend_op_array *op_array,

ext/opcache/jit/zend_jit_trace.c

+47
Original file line numberDiff line numberDiff line change
@@ -4823,6 +4823,53 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
48234823
on_this = op_array->opcodes[op_array_ssa->vars[op_array_ssa->ops[opline-op_array->opcodes].op1_use].definition].opcode == ZEND_FETCH_THIS;
48244824
}
48254825
}
4826+
#ifdef HAVE_FFI
4827+
if (op1_ffi_type && op1_ffi_type->kind == ZEND_FFI_TYPE_STRUCT) {
4828+
zend_ffi_field *field = zend_hash_find_ptr(&op1_ffi_type->record.fields,
4829+
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
4830+
4831+
if (field
4832+
&& !field->is_const
4833+
&& !field->bits
4834+
&& ZEND_FFI_TYPE(field->type)->kind != ZEND_FFI_TYPE_VOID
4835+
&& zend_jit_ffi_supported_type(field->type)
4836+
&& (ZEND_FFI_TYPE(field->type)->kind < ZEND_FFI_TYPE_POINTER
4837+
|| (ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_POINTER
4838+
&& ZEND_FFI_TYPE(ZEND_FFI_TYPE(field->type)->pointer.type)->size != 0))) {
4839+
if (!ffi_info) {
4840+
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
4841+
}
4842+
if (!zend_jit_ffi_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
4843+
op1_info, op1_addr, op1_indirect, field,
4844+
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
4845+
op1_ffi_type, ffi_info)) {
4846+
goto jit_failure;
4847+
}
4848+
goto done;
4849+
}
4850+
} else if (op1_ffi_symbols) {
4851+
zend_ffi_symbol *sym = zend_hash_find_ptr(op1_ffi_symbols,
4852+
Z_STR_P(RT_CONSTANT(opline, opline->op2)));
4853+
if (sym
4854+
&& sym->kind == ZEND_FFI_SYM_VAR
4855+
&& ZEND_FFI_TYPE(sym->type)->kind != ZEND_FFI_TYPE_VOID
4856+
&& zend_jit_ffi_supported_type(sym->type)
4857+
&& (ZEND_FFI_TYPE(sym->type)->kind < ZEND_FFI_TYPE_POINTER
4858+
|| (ZEND_FFI_TYPE(sym->type)->kind == ZEND_FFI_TYPE_POINTER
4859+
&& ZEND_FFI_TYPE(ZEND_FFI_TYPE(sym->type)->pointer.type)->size != 0))) {
4860+
if (!ffi_info) {
4861+
ffi_info = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_jit_ffi_info));
4862+
}
4863+
if (!zend_jit_ffi_incdec_sym(&ctx, opline, op_array, ssa, ssa_op,
4864+
op1_info, op1_addr, op1_indirect, sym,
4865+
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
4866+
op1_ffi_symbols, ffi_info)) {
4867+
goto jit_failure;
4868+
}
4869+
goto done;
4870+
}
4871+
}
4872+
#endif
48264873
if (!zend_jit_incdec_obj(&ctx, opline, op_array, ssa, ssa_op,
48274874
op1_info, op1_addr,
48284875
op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,

0 commit comments

Comments
 (0)