Skip to content

Commit 58c281a

Browse files
authored
JIT: Add CPU registers support for ASSIGN_OBJ and ASSIGN_OBJ_OP (#14303)
* JIT: Add CPU registers support for ASSIGN_OBJ and ASSIGN_OBJ_OP * Fix tests failures * Fix tests failures * Add missing GUARD
1 parent 706e9ed commit 58c281a

File tree

3 files changed

+152
-26
lines changed

3 files changed

+152
-26
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1817,7 +1817,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
18171817
}
18181818
}
18191819
if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
1820-
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_RANGE(),
1820+
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
18211821
0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN)) {
18221822
goto jit_failure;
18231823
}
@@ -1861,7 +1861,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
18611861
}
18621862
}
18631863
if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
1864-
op1_info, op1_addr, OP1_DATA_INFO(),
1864+
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
1865+
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
18651866
0, ce, ce_is_instanceof, on_this, 0, NULL, IS_UNKNOWN,
18661867
zend_may_throw(opline, ssa_op, op_array, ssa))) {
18671868
goto jit_failure;

ext/opcache/jit/zend_jit_ir.c

Lines changed: 144 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6254,7 +6254,7 @@ static int zend_jit_assign_to_variable(zend_jit_ctx *jit,
62546254
if (Z_MODE(val_addr) == IS_REG) {
62556255
zend_jit_addr real_addr;
62566256

6257-
if (opline->opcode == ZEND_ASSIGN_DIM) {
6257+
if (opline->opcode == ZEND_ASSIGN_DIM || opline->opcode == ZEND_ASSIGN_OBJ) {
62586258
real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
62596259
} else {
62606260
ZEND_ASSERT(opline->opcode == ZEND_ASSIGN);
@@ -14143,6 +14143,9 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1414314143
uint32_t op1_info,
1414414144
zend_jit_addr op1_addr,
1414514145
uint32_t val_info,
14146+
zend_jit_addr val_addr,
14147+
zend_jit_addr val_def_addr,
14148+
zend_jit_addr res_addr,
1414614149
bool op1_indirect,
1414714150
zend_class_entry *ce,
1414814151
bool ce_is_instanceof,
@@ -14155,17 +14158,21 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1415514158
zval *member;
1415614159
zend_string *name;
1415714160
zend_property_info *prop_info;
14158-
zend_jit_addr val_addr = OP1_DATA_ADDR();
14159-
zend_jit_addr res_addr = 0;
1416014161
zend_jit_addr prop_addr;
1416114162
ir_ref obj_ref = IR_UNUSED;
1416214163
ir_ref prop_ref = IR_UNUSED;
1416314164
ir_ref delayed_end_input = IR_UNUSED;
1416414165
ir_ref end_inputs = IR_UNUSED;
1416514166
ir_ref slow_inputs = IR_UNUSED;
14167+
uint32_t res_info = RES_INFO();
1416614168

14167-
if (RETURN_VALUE_USED(opline)) {
14168-
res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14169+
if (val_addr != val_def_addr && val_def_addr) {
14170+
if (!zend_jit_update_regs(jit, (opline+1)->op1.var, val_addr, val_def_addr, val_info)) {
14171+
return 0;
14172+
}
14173+
if (Z_MODE(val_def_addr) == IS_REG && Z_MODE(val_addr) != IS_REG) {
14174+
val_addr = val_def_addr;
14175+
}
1416914176
}
1417014177

1417114178
ZEND_ASSERT(opline->op2_type == IS_CONST);
@@ -14206,7 +14213,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1420614213
jit_ZVAL_ADDR(jit, op1_addr),
1420714214
ir_CONST_ADDR(ZSTR_VAL(name)));
1420814215

14209-
if (RETURN_VALUE_USED(opline)) {
14216+
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) != IS_REG) {
1421014217
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
1421114218
}
1421214219

@@ -14276,25 +14283,51 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1427614283
prop_addr = ZEND_ADDR_REF_ZVAL(prop_ref);
1427714284

1427814285
if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) {
14286+
ir_ref arg3, arg4;
1427914287
ir_ref prop_info_ref = ir_LOAD_A(
1428014288
ir_ADD_OFFSET(run_time_cache, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2));
1428114289
ir_ref if_has_prop_info = ir_IF(prop_info_ref);
1428214290
ir_IF_TRUE_cold(if_has_prop_info);
1428314291

14292+
if (Z_MODE(val_addr) == IS_REG) {
14293+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14294+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14295+
return 0;
14296+
}
14297+
arg3 = jit_ZVAL_ADDR(jit, real_addr);
14298+
} else {
14299+
arg3 = jit_ZVAL_ADDR(jit, val_addr);
14300+
}
14301+
14302+
if (!RETURN_VALUE_USED(opline)) {
14303+
arg4 = IR_NULL;
14304+
} else if (Z_MODE(res_addr) == IS_REG) {
14305+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14306+
arg4 = jit_ZVAL_ADDR(jit, real_addr);
14307+
} else {
14308+
arg4 = jit_ZVAL_ADDR(jit, res_addr);
14309+
}
1428414310
// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
1428514311
jit_SET_EX_OPLINE(jit, opline);
1428614312
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
1428714313
prop_ref,
1428814314
prop_info_ref,
14289-
jit_ZVAL_ADDR(jit, val_addr),
14290-
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
14315+
arg3,
14316+
arg4);
1429114317

1429214318
if ((opline+1)->op1_type == IS_CONST) {
1429314319
// TODO: ???
1429414320
// if (Z_TYPE_P(value) == orig_type) {
1429514321
// CACHE_PTR_EX(cache_slot + 2, NULL);
1429614322
}
1429714323

14324+
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14325+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14326+
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14327+
return 0;
14328+
}
14329+
}
14330+
1429814331
ir_END_list(end_inputs);
1429914332
ir_IF_FALSE(if_has_prop_info);
1430014333
}
@@ -14319,7 +14352,7 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1431914352
}
1432014353
}
1432114354
if (ZEND_TYPE_IS_SET(prop_info->type)) {
14322-
ir_ref ref;
14355+
ir_ref ref, arg3, arg4;
1432314356

1432414357
// JIT: value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC);
1432514358
jit_SET_EX_OPLINE(jit, opline);
@@ -14333,18 +14366,43 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1433314366
ref = ir_LOAD_A(ir_ADD_OFFSET(ref, offsetof(zend_class_entry, properties_info_table)));
1433414367
ref = ir_LOAD_A(ir_ADD_OFFSET(ref, prop_info_offset));
1433514368
}
14369+
if (Z_MODE(val_addr) == IS_REG) {
14370+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14371+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14372+
return 0;
14373+
}
14374+
arg3 = jit_ZVAL_ADDR(jit, real_addr);
14375+
} else {
14376+
arg3 = jit_ZVAL_ADDR(jit, val_addr);
14377+
}
14378+
if (!RETURN_VALUE_USED(opline)) {
14379+
arg4 = IR_NULL;
14380+
} else if (Z_MODE(res_addr) == IS_REG) {
14381+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14382+
arg4 = jit_ZVAL_ADDR(jit, real_addr);
14383+
} else {
14384+
arg4 = jit_ZVAL_ADDR(jit, res_addr);
14385+
}
1433614386
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_to_typed_prop),
1433714387
prop_ref,
1433814388
ref,
14339-
jit_ZVAL_ADDR(jit, val_addr),
14340-
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
14389+
arg3,
14390+
arg4);
1434114391

14392+
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14393+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14394+
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14395+
return 0;
14396+
}
14397+
}
1434214398
ir_END_list(end_inputs);
1434314399
}
1434414400
}
1434514401

1434614402
if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) {
14347-
if (opline->result_type == IS_UNUSED) {
14403+
if (Z_MODE(val_addr) != IS_REG
14404+
&& (res_addr == 0 || Z_MODE(res_addr) != IS_REG)
14405+
&& opline->result_type == IS_UNUSED) {
1434814406
if (!zend_jit_assign_to_variable_call(jit, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) {
1434914407
return 0;
1435014408
}
@@ -14365,18 +14423,44 @@ static int zend_jit_assign_obj(zend_jit_ctx *jit,
1436514423
}
1436614424

1436714425
if (slow_inputs) {
14426+
ir_ref arg3, arg5;
14427+
1436814428
ir_MERGE_list(slow_inputs);
1436914429
jit_SET_EX_OPLINE(jit, opline);
1437014430

14431+
if (Z_MODE(val_addr) == IS_REG) {
14432+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14433+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14434+
return 0;
14435+
}
14436+
arg3 = jit_ZVAL_ADDR(jit, real_addr);
14437+
} else {
14438+
arg3 = jit_ZVAL_ADDR(jit, val_addr);
14439+
}
14440+
if (!RETURN_VALUE_USED(opline)) {
14441+
arg5 = IR_NULL;
14442+
} else if (Z_MODE(res_addr) == IS_REG) {
14443+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14444+
arg5 = jit_ZVAL_ADDR(jit, real_addr);
14445+
} else {
14446+
arg5 = jit_ZVAL_ADDR(jit, res_addr);
14447+
}
14448+
1437114449
// JIT: value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value));
1437214450
ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
1437314451
ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_helper),
1437414452
obj_ref,
1437514453
ir_CONST_ADDR(name),
14376-
jit_ZVAL_ADDR(jit, val_addr),
14454+
arg3,
1437714455
ir_ADD_OFFSET(run_time_cache, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
14378-
RETURN_VALUE_USED(opline) ? jit_ZVAL_ADDR(jit, res_addr) : IR_NULL);
14456+
arg5);
1437914457

14458+
if (RETURN_VALUE_USED(opline) && Z_MODE(res_addr) == IS_REG) {
14459+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
14460+
if (!zend_jit_load_reg(jit, real_addr, res_addr, res_info)) {
14461+
return 0;
14462+
}
14463+
}
1438014464
ir_END_list(end_inputs);
1438114465
}
1438214466

@@ -14412,6 +14496,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1441214496
uint32_t op1_info,
1441314497
zend_jit_addr op1_addr,
1441414498
uint32_t val_info,
14499+
zend_jit_addr val_addr,
1441514500
zend_ssa_range *val_range,
1441614501
bool op1_indirect,
1441714502
zend_class_entry *ce,
@@ -14424,7 +14509,6 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1442414509
zval *member;
1442514510
zend_string *name;
1442614511
zend_property_info *prop_info;
14427-
zend_jit_addr val_addr = OP1_DATA_ADDR();
1442814512
zend_jit_addr prop_addr;
1442914513
bool use_prop_guard = 0;
1443014514
bool may_throw = 0;
@@ -14579,12 +14663,22 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1457914663
}
1458014664
}
1458114665
if (ZEND_TYPE_IS_SET(prop_info->type)) {
14582-
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
14666+
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
1458314667

1458414668
may_throw = 1;
1458514669

1458614670
jit_SET_EX_OPLINE(jit, opline);
1458714671

14672+
if (Z_MODE(val_addr) == IS_REG) {
14673+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14674+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14675+
return 0;
14676+
}
14677+
arg2 = jit_ZVAL_ADDR(jit, real_addr);
14678+
} else {
14679+
arg2 = jit_ZVAL_ADDR(jit, val_addr);
14680+
}
14681+
1458814682
if_ref = jit_if_Z_TYPE(jit, prop_addr, IS_REFERENCE);
1458914683
ir_IF_FALSE(if_ref);
1459014684
noref_path = ir_END();
@@ -14599,7 +14693,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1459914693

1460014694
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
1460114695
reference,
14602-
jit_ZVAL_ADDR(jit, val_addr),
14696+
arg2,
1460314697
ir_CONST_FC_FUNC(binary_op));
1460414698

1460514699
ir_END_list(end_inputs);
@@ -14623,7 +14717,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1462314717
ir_CALL_4(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_prop),
1462414718
prop_ref,
1462514719
ref,
14626-
jit_ZVAL_ADDR(jit, val_addr),
14720+
arg2,
1462714721
ir_CONST_FC_FUNC(binary_op));
1462814722

1462914723
ir_END_list(end_inputs);
@@ -14647,7 +14741,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1464714741
}
1464814742

1464914743
if (var_info & MAY_BE_REF) {
14650-
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref;
14744+
ir_ref if_ref, if_typed, noref_path, ref_path, reference, ref, arg2;
1465114745

1465214746
may_throw = 1;
1465314747

@@ -14665,9 +14759,18 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1466514759

1466614760
jit_SET_EX_OPLINE(jit, opline);
1466714761

14762+
if (Z_MODE(val_addr) == IS_REG) {
14763+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14764+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14765+
return 0;
14766+
}
14767+
arg2 = jit_ZVAL_ADDR(jit, real_addr);
14768+
} else {
14769+
arg2 = jit_ZVAL_ADDR(jit, val_addr);
14770+
}
1466814771
ir_CALL_3(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_op_to_typed_ref),
1466914772
reference,
14670-
jit_ZVAL_ADDR(jit, val_addr),
14773+
arg2,
1467114774
ir_CONST_FC_FUNC(binary_op));
1467214775

1467314776
ir_END_list(end_inputs);
@@ -14760,16 +14863,27 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit,
1476014863
}
1476114864

1476214865
if (slow_inputs) {
14866+
ir_ref arg3;
14867+
1476314868
ir_MERGE_list(slow_inputs);
1476414869

1476514870
may_throw = 1;
1476614871

14872+
if (Z_MODE(val_addr) == IS_REG) {
14873+
zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline+1)->op1.var);
14874+
if (!zend_jit_spill_store_inv(jit, val_addr, real_addr, val_info)) {
14875+
return 0;
14876+
}
14877+
arg3 = jit_ZVAL_ADDR(jit, real_addr);
14878+
} else {
14879+
arg3 = jit_ZVAL_ADDR(jit, val_addr);
14880+
}
1476714881
jit_SET_EX_OPLINE(jit, opline);
1476814882
ir_ref run_time_cache = ir_LOAD_A(jit_EX(run_time_cache));
1476914883
ir_CALL_5(IR_VOID, ir_CONST_FC_FUNC(zend_jit_assign_obj_op_helper),
1477014884
obj_ref,
1477114885
ir_CONST_ADDR(name),
14772-
jit_ZVAL_ADDR(jit, val_addr),
14886+
arg3,
1477314887
ir_ADD_OFFSET(run_time_cache, (opline+1)->extended_value & ~ZEND_FETCH_OBJ_FLAGS),
1477414888
ir_CONST_FC_FUNC(binary_op));
1477514889

@@ -16692,7 +16806,16 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1669216806
return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
1669316807
(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
1669416808
((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
16809+
case ZEND_ASSIGN_OBJ_OP:
16810+
if (opline->result_type != IS_UNUSED) {
16811+
return 0;
16812+
}
16813+
if (!zend_jit_supported_binary_op(opline->extended_value, MAY_BE_ANY, OP1_DATA_INFO())) {
16814+
return 0;
16815+
}
16816+
ZEND_FALLTHROUGH;
1669516817
case ZEND_FETCH_OBJ_R:
16818+
case ZEND_ASSIGN_OBJ:
1669616819
if (opline->op2_type != IS_CONST
1669716820
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
1669816821
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {

ext/opcache/jit/zend_jit_trace.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,7 +1843,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
18431843
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
18441844
break;
18451845
}
1846-
if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1846+
if (opline->opcode == ZEND_ASSIGN_OBJ
1847+
|| opline->opcode == ZEND_ASSIGN_OBJ_OP) {
18471848
if (opline->op1_type == IS_CV
18481849
&& (opline+1)->op1_type == IS_CV
18491850
&& (opline+1)->op1.var == opline->op1.var) {
@@ -4851,7 +4852,7 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
48514852
op1_data_info = OP1_DATA_INFO();
48524853
CHECK_OP1_DATA_TRACE_TYPE();
48534854
if (!zend_jit_assign_obj_op(&ctx, opline, op_array, ssa, ssa_op,
4854-
op1_info, op1_addr, op1_data_info, OP1_DATA_RANGE(),
4855+
op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_RANGE(),
48554856
op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
48564857
val_type)) {
48574858
goto jit_failure;
@@ -4934,7 +4935,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
49344935
op1_data_info = OP1_DATA_INFO();
49354936
CHECK_OP1_DATA_TRACE_TYPE();
49364937
if (!zend_jit_assign_obj(&ctx, opline, op_array, ssa, ssa_op,
4937-
op1_info, op1_addr, op1_data_info,
4938+
op1_info, op1_addr, op1_data_info, OP1_DATA_REG_ADDR(), OP1_DATA_DEF_REG_ADDR(),
4939+
(opline->result_type != IS_UNUSED) ? RES_REG_ADDR() : 0,
49384940
op1_indirect, ce, ce_is_instanceof, on_this, delayed_fetch_this, op1_ce,
49394941
val_type,
49404942
zend_may_throw(opline, ssa_op, op_array, ssa))) {

0 commit comments

Comments
 (0)