Skip to content

Commit 13d5c81

Browse files
authored
JIT: Add CPU registers support for FETCH_OBJ_R (#14253)
1 parent bc09cd2 commit 13d5c81

File tree

4 files changed

+192
-39
lines changed

4 files changed

+192
-39
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2338,7 +2338,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
23382338
}
23392339
if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
23402340
op1_info, op1_addr, 0, ce, ce_is_instanceof, on_this, 0, 0, NULL,
2341-
IS_UNKNOWN,
2341+
RES_REG_ADDR(), IS_UNKNOWN,
23422342
zend_may_throw(opline, ssa_op, op_array, ssa))) {
23432343
goto jit_failure;
23442344
}

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1956,6 +1956,110 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intpt
19561956
zend_jit_fetch_obj_is_slow(zobj);
19571957
}
19581958

1959+
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_slow_ex(zend_object *zobj)
1960+
{
1961+
zval *retval;
1962+
zend_execute_data *execute_data = EG(current_execute_data);
1963+
const zend_op *opline = EX(opline);
1964+
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1965+
zval *result = EX_VAR(opline->result.var);
1966+
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1967+
1968+
retval = zobj->handlers->read_property(zobj, name, BP_VAR_R, cache_slot, result);
1969+
if (retval == result && UNEXPECTED(Z_ISREF_P(retval))) {
1970+
zend_unwrap_reference(retval);
1971+
}
1972+
return retval;
1973+
}
1974+
1975+
static zval* ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
1976+
{
1977+
if (zobj->properties) {
1978+
zval *retval;
1979+
zend_execute_data *execute_data = EG(current_execute_data);
1980+
const zend_op *opline = EX(opline);
1981+
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
1982+
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
1983+
1984+
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
1985+
intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
1986+
1987+
if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
1988+
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
1989+
1990+
if (EXPECTED(p->key == name) ||
1991+
(EXPECTED(p->h == ZSTR_H(name)) &&
1992+
EXPECTED(p->key != NULL) &&
1993+
EXPECTED(zend_string_equal_content(p->key, name)))) {
1994+
return &p->val;
1995+
}
1996+
}
1997+
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
1998+
}
1999+
2000+
retval = zend_hash_find_known_hash(zobj->properties, name);
2001+
2002+
if (EXPECTED(retval)) {
2003+
intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2004+
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2005+
return retval;
2006+
}
2007+
}
2008+
return zend_jit_fetch_obj_r_slow_ex(zobj);
2009+
}
2010+
2011+
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_slow_ex(zend_object *zobj)
2012+
{
2013+
zval *retval;
2014+
zend_execute_data *execute_data = EG(current_execute_data);
2015+
const zend_op *opline = EX(opline);
2016+
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2017+
zval *result = EX_VAR(opline->result.var);
2018+
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2019+
2020+
retval = zobj->handlers->read_property(zobj, name, BP_VAR_IS, cache_slot, result);
2021+
if (retval == result && UNEXPECTED(Z_ISREF_P(retval))) {
2022+
zend_unwrap_reference(retval);
2023+
}
2024+
return retval;
2025+
}
2026+
2027+
static zval* ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic_ex(zend_object *zobj, intptr_t prop_offset)
2028+
{
2029+
if (zobj->properties) {
2030+
zval *retval;
2031+
zend_execute_data *execute_data = EG(current_execute_data);
2032+
const zend_op *opline = EX(opline);
2033+
zend_string *name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
2034+
void **cache_slot = CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS);
2035+
2036+
if (!IS_UNKNOWN_DYNAMIC_PROPERTY_OFFSET(prop_offset)) {
2037+
intptr_t idx = ZEND_DECODE_DYN_PROP_OFFSET(prop_offset);
2038+
2039+
if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) {
2040+
Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx);
2041+
2042+
if (EXPECTED(p->key == name) ||
2043+
(EXPECTED(p->h == ZSTR_H(name)) &&
2044+
EXPECTED(p->key != NULL) &&
2045+
EXPECTED(zend_string_equal_content(p->key, name)))) {
2046+
return &p->val;
2047+
}
2048+
}
2049+
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_DYNAMIC_PROPERTY_OFFSET);
2050+
}
2051+
2052+
retval = zend_hash_find_known_hash(zobj->properties, name);
2053+
2054+
if (EXPECTED(retval)) {
2055+
intptr_t idx = (char*)retval - (char*)zobj->properties->arData;
2056+
CACHE_PTR_EX(cache_slot + 1, (void*)ZEND_ENCODE_DYN_PROP_OFFSET(idx));
2057+
return retval;
2058+
}
2059+
}
2060+
return zend_jit_fetch_obj_is_slow_ex(zobj);
2061+
}
2062+
19592063
static zend_always_inline bool promotes_to_array(zval *val) {
19602064
return Z_TYPE_P(val) <= IS_FALSE
19612065
|| (Z_ISREF_P(val) && Z_TYPE_P(Z_REFVAL_P(val)) <= IS_FALSE);

ext/opcache/jit/zend_jit_ir.c

Lines changed: 84 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3039,9 +3039,13 @@ static void zend_jit_setup_disasm(void)
30393039
REGISTER_HELPER(zend_jit_assign_dim_op_helper);
30403040
REGISTER_HELPER(zend_jit_fetch_obj_w_slow);
30413041
REGISTER_HELPER(zend_jit_fetch_obj_r_slow);
3042+
REGISTER_HELPER(zend_jit_fetch_obj_r_slow_ex);
30423043
REGISTER_HELPER(zend_jit_fetch_obj_is_slow);
3044+
REGISTER_HELPER(zend_jit_fetch_obj_is_slow_ex);
30433045
REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic);
3046+
REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic_ex);
30443047
REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic);
3048+
REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic_ex);
30453049
REGISTER_HELPER(zend_jit_check_array_promotion);
30463050
REGISTER_HELPER(zend_jit_create_typed_ref);
30473051
REGISTER_HELPER(zend_jit_invalid_property_write);
@@ -13662,20 +13666,21 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
1366213666
bool delayed_fetch_this,
1366313667
bool op1_avoid_refcounting,
1366413668
zend_class_entry *trace_ce,
13669+
zend_jit_addr res_addr,
1366513670
uint8_t prop_type,
1366613671
int may_throw)
1366713672
{
1366813673
zval *member;
1366913674
zend_property_info *prop_info;
1367013675
bool may_be_dynamic = 1;
13671-
zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var);
1367213676
zend_jit_addr prop_addr;
1367313677
uint32_t res_info = RES_INFO();
1367413678
ir_ref prop_type_ref = IR_UNUSED;
1367513679
ir_ref obj_ref = IR_UNUSED;
1367613680
ir_ref prop_ref = IR_UNUSED;
1367713681
ir_ref end_inputs = IR_UNUSED;
1367813682
ir_ref slow_inputs = IR_UNUSED;
13683+
ir_ref end_values = IR_UNUSED;
1367913684

1368013685
ZEND_ASSERT(opline->op2_type == IS_CONST);
1368113686
ZEND_ASSERT(op1_info & MAY_BE_OBJECT);
@@ -13804,13 +13809,28 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
1380413809
jit_SET_EX_OPLINE(jit, opline);
1380513810

1380613811
if (opline->opcode != ZEND_FETCH_OBJ_IS) {
13807-
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
13808-
obj_ref, offset_ref);
13812+
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
13813+
|| Z_MODE(res_addr) == IS_REG) {
13814+
ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic_ex),
13815+
obj_ref, offset_ref);
13816+
ir_END_PHI_list(end_values, val_addr);
13817+
} else {
13818+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_dynamic),
13819+
obj_ref, offset_ref);
13820+
ir_END_list(end_inputs);
13821+
}
1380913822
} else {
13810-
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
13811-
obj_ref, offset_ref);
13823+
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
13824+
|| Z_MODE(res_addr) == IS_REG) {
13825+
ir_ref val_addr = ir_CALL_2(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic_ex),
13826+
obj_ref, offset_ref);
13827+
ir_END_PHI_list(end_values, val_addr);
13828+
} else {
13829+
ir_CALL_2(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_dynamic),
13830+
obj_ref, offset_ref);
13831+
ir_END_list(end_inputs);
13832+
}
1381213833
}
13813-
ir_END_list(end_inputs);
1381413834
}
1381513835
ir_IF_FALSE(if_dynamic);
1381613836
}
@@ -13996,12 +14016,56 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
1399614016
}
1399714017
ir_END_list(end_inputs);
1399814018
} else {
14019+
if (((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info)
14020+
|| Z_MODE(res_addr) == IS_REG) {
14021+
ir_END_PHI_list(end_values, jit_ZVAL_ADDR(jit, prop_addr));
14022+
} else {
14023+
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14024+
14025+
if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14026+
return 0;
14027+
}
14028+
ir_END_list(end_inputs);
14029+
}
14030+
}
14031+
14032+
if (op1_avoid_refcounting) {
14033+
SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14034+
}
14035+
14036+
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14037+
ir_MERGE_list(slow_inputs);
14038+
jit_SET_EX_OPLINE(jit, opline);
14039+
14040+
if (opline->opcode == ZEND_FETCH_OBJ_W) {
14041+
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14042+
ir_END_list(end_inputs);
14043+
} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14044+
if (Z_MODE(res_addr) == IS_REG) {
14045+
ir_ref val_ref = ir_CALL_1(IR_ADDR, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow_ex), obj_ref);
14046+
ir_END_PHI_list(end_values, val_ref);
14047+
} else {
14048+
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14049+
ir_END_list(end_inputs);
14050+
}
14051+
} else {
14052+
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14053+
ir_END_list(end_inputs);
14054+
}
14055+
}
14056+
14057+
if (end_values) {
14058+
ir_ref val_ref = ir_PHI_list(end_values);
14059+
zend_jit_addr val_addr = ZEND_ADDR_REF_ZVAL(val_ref);
1399914060
bool result_avoid_refcounting = 0;
1400014061

14001-
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) {
14062+
ZEND_ASSERT(opline->opcode == ZEND_FETCH_OBJ_R
14063+
|| opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG
14064+
|| opline->opcode == ZEND_FETCH_OBJ_IS);
14065+
ZEND_ASSERT(end_inputs == IR_UNUSED);
14066+
if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) {
1400214067
uint8_t type = concrete_type(res_info);
1400314068
uint32_t flags = 0;
14004-
zend_jit_addr val_addr = prop_addr;
1400514069

1400614070
if ((opline->op1_type & (IS_VAR|IS_TMP_VAR))
1400714071
&& !delayed_fetch_this
@@ -14026,39 +14090,14 @@ static int zend_jit_fetch_obj(zend_jit_ctx *jit,
1402614090

1402714091
res_info &= ~MAY_BE_GUARD;
1402814092
ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD;
14029-
14030-
// ZVAL_COPY
14031-
jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14032-
} else {
14033-
prop_type_ref = jit_Z_TYPE_INFO(jit, prop_addr);
14034-
14035-
if (!zend_jit_zval_copy_deref(jit, res_addr, prop_addr, prop_type_ref)) {
14036-
return 0;
14037-
}
1403814093
}
14039-
ir_END_list(end_inputs);
14040-
}
14041-
14042-
if (op1_avoid_refcounting) {
14043-
SET_STACK_REG(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE);
14044-
}
14045-
14046-
if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) {
14047-
ir_MERGE_list(slow_inputs);
14048-
jit_SET_EX_OPLINE(jit, opline);
1404914094

14050-
if (opline->opcode == ZEND_FETCH_OBJ_W) {
14051-
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_w_slow), obj_ref);
14052-
} else if (opline->opcode != ZEND_FETCH_OBJ_IS) {
14053-
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_r_slow), obj_ref);
14054-
} else {
14055-
ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_jit_fetch_obj_is_slow), obj_ref);
14056-
}
14057-
ir_END_list(end_inputs);
14095+
// ZVAL_COPY
14096+
jit_ZVAL_COPY(jit, res_addr, -1, val_addr, res_info, !result_avoid_refcounting);
14097+
} else {
14098+
ir_MERGE_list(end_inputs);
1405814099
}
1405914100

14060-
ir_MERGE_list(end_inputs);
14061-
1406214101
if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) {
1406314102
if (opline->op1_type == IS_VAR
1406414103
&& opline->opcode == ZEND_FETCH_OBJ_W
@@ -16662,6 +16701,14 @@ static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa
1666216701
return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) &&
1666316702
(((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) ||
1666416703
((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING));
16704+
case ZEND_FETCH_OBJ_R:
16705+
if (opline->op2_type != IS_CONST
16706+
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
16707+
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
16708+
return 0;
16709+
}
16710+
op1_info = OP1_INFO();
16711+
return opline->op1_type == IS_UNUSED || (op1_info & MAY_BE_OBJECT);
1666516712
}
1666616713
return 0;
1666716714
}

ext/opcache/jit/zend_jit_trace.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2963,6 +2963,7 @@ static zend_jit_reg_var* zend_jit_trace_allocate_registers(zend_jit_trace_rec *t
29632963
|| opline->opcode == ZEND_SUB
29642964
|| opline->opcode == ZEND_MUL
29652965
|| opline->opcode == ZEND_FETCH_DIM_R
2966+
|| opline->opcode == ZEND_FETCH_OBJ_R
29662967
|| opline->opcode == ZEND_FETCH_CONSTANT) {
29672968
if (!(ssa->var_info[ssa_op->result_def].type & MAY_BE_DOUBLE)
29682969
|| (opline->opcode != ZEND_PRE_INC && opline->opcode != ZEND_PRE_DEC)) {
@@ -6004,7 +6005,8 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
60046005
}
60056006
if (!zend_jit_fetch_obj(&ctx, opline, op_array, ssa, ssa_op,
60066007
op1_info, op1_addr, op1_indirect, ce, ce_is_instanceof,
6007-
on_this, delayed_fetch_this, avoid_refcounting, op1_ce, val_type,
6008+
on_this, delayed_fetch_this, avoid_refcounting, op1_ce,
6009+
RES_REG_ADDR(), val_type,
60086010
zend_may_throw_ex(opline, ssa_op, op_array, ssa, op1_info, MAY_BE_STRING))) {
60096011
goto jit_failure;
60106012
}

0 commit comments

Comments
 (0)