Skip to content

Commit bf51564

Browse files
committed
JIT for ASSIGN_OBJ_OP
1 parent 950ea89 commit bf51564

File tree

5 files changed

+543
-5
lines changed

5 files changed

+543
-5
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2457,10 +2457,55 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
24572457
goto jit_failure;
24582458
}
24592459
goto done;
2460-
case ZEND_ASSIGN_OBJ:
2461-
if (opline->op1_type == IS_VAR) {
2460+
case ZEND_ASSIGN_OBJ_OP:
2461+
if (opline->extended_value == ZEND_POW
2462+
|| opline->extended_value == ZEND_DIV) {
2463+
// TODO: check for division by zero ???
2464+
break;
2465+
}
2466+
if (opline->result_type != IS_UNUSED) {
2467+
break;
2468+
}
2469+
if (opline->op2_type != IS_CONST
2470+
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
2471+
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
24622472
break;
24632473
}
2474+
if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
2475+
break;
2476+
}
2477+
ce = NULL;
2478+
ce_is_instanceof = 0;
2479+
if (opline->op1_type == IS_UNUSED) {
2480+
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
2481+
ce = op_array->scope;
2482+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
2483+
op1_addr = 0;
2484+
} else {
2485+
op1_info = OP1_INFO();
2486+
if (!(op1_info & MAY_BE_OBJECT)) {
2487+
break;
2488+
}
2489+
op1_addr = OP1_REG_ADDR();
2490+
if (ssa->var_info && ssa->ops) {
2491+
zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
2492+
if (ssa_op->op1_use >= 0) {
2493+
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
2494+
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
2495+
ce = op1_ssa->ce;
2496+
ce_is_instanceof = op1_ssa->is_instanceof;
2497+
}
2498+
}
2499+
}
2500+
}
2501+
if (!zend_jit_assign_obj_op(&dasm_state, opline, op_array, ssa, ssa_op,
2502+
op1_info, op1_addr, OP1_DATA_INFO(), OP1_DATA_RANGE(),
2503+
0, ce, ce_is_instanceof, 0, NULL,
2504+
zend_may_throw(opline, ssa_op, op_array, ssa))) {
2505+
goto jit_failure;
2506+
}
2507+
goto done;
2508+
case ZEND_ASSIGN_OBJ:
24642509
if (opline->op2_type != IS_CONST
24652510
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
24662511
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {

ext/opcache/jit/zend_jit_disasm_x86.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ static int zend_jit_disasm_init(void)
457457
REGISTER_HELPER(zend_jit_invalid_property_read);
458458
REGISTER_HELPER(zend_jit_invalid_property_write);
459459
REGISTER_HELPER(zend_jit_invalid_property_assign);
460+
REGISTER_HELPER(zend_jit_invalid_property_assign_op);
460461
REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
461462
REGISTER_HELPER(zend_jit_pre_inc);
462463
REGISTER_HELPER(zend_jit_pre_dec);
@@ -468,7 +469,9 @@ static int zend_jit_disasm_init(void)
468469
REGISTER_HELPER(zend_jit_zval_array_dup);
469470
REGISTER_HELPER(zend_jit_add_arrays_helper);
470471
REGISTER_HELPER(zend_jit_assign_obj_helper);
472+
REGISTER_HELPER(zend_jit_assign_obj_op_helper);
471473
REGISTER_HELPER(zend_jit_assign_to_typed_prop);
474+
REGISTER_HELPER(zend_jit_assign_op_to_typed_prop);
472475
#undef REGISTER_HELPER
473476

474477
#ifndef _WIN32

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,6 +1865,16 @@ static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, cons
18651865
property_name, zend_zval_type_name(container));
18661866
}
18671867

1868+
static void ZEND_FASTCALL zend_jit_invalid_property_assign_op(zval *container, const char *property_name)
1869+
{
1870+
if (Z_TYPE_P(container) == IS_UNDEF) {
1871+
const zend_execute_data *execute_data = EG(current_execute_data);
1872+
1873+
zend_jit_undefined_op_helper(EX(opline)->op1.var);
1874+
}
1875+
zend_jit_invalid_property_assign(container, property_name);
1876+
}
1877+
18681878
static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
18691879
zval *val = Z_REFVAL_P(ref);
18701880
if (Z_TYPE_P(val) <= IS_FALSE) {
@@ -1965,3 +1975,88 @@ static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend
19651975
ZVAL_COPY_DEREF(result, value);
19661976
}
19671977
}
1978+
1979+
static zend_never_inline void _zend_jit_assign_op_overloaded_property(zend_object *object, zend_string *name, void **cache_slot, zval *value, binary_op_type binary_op)
1980+
{
1981+
zval *z;
1982+
zval rv, res;
1983+
1984+
GC_ADDREF(object);
1985+
z = object->handlers->read_property(object, name, BP_VAR_R, cache_slot, &rv);
1986+
if (UNEXPECTED(EG(exception))) {
1987+
OBJ_RELEASE(object);
1988+
//??? if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1989+
//??? ZVAL_UNDEF(EX_VAR(opline->result.var));
1990+
//??? }
1991+
return;
1992+
}
1993+
if (binary_op(&res, z, value) == SUCCESS) {
1994+
object->handlers->write_property(object, name, &res, cache_slot);
1995+
}
1996+
//??? if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
1997+
//??? ZVAL_COPY(EX_VAR(opline->result.var), &res);
1998+
//??? }
1999+
zval_ptr_dtor(z);
2000+
zval_ptr_dtor(&res);
2001+
OBJ_RELEASE(object);
2002+
}
2003+
2004+
static void ZEND_FASTCALL zend_jit_assign_op_to_typed_prop(zval *zptr, zend_property_info *prop_info, zval *value, binary_op_type binary_op)
2005+
{
2006+
zend_execute_data *execute_data = EG(current_execute_data);
2007+
zval z_copy;
2008+
2009+
binary_op(&z_copy, zptr, value);
2010+
if (EXPECTED(zend_verify_property_type(prop_info, &z_copy, EX_USES_STRICT_TYPES()))) {
2011+
zval_ptr_dtor(zptr);
2012+
ZVAL_COPY_VALUE(zptr, &z_copy);
2013+
} else {
2014+
zval_ptr_dtor(&z_copy);
2015+
}
2016+
}
2017+
2018+
static void ZEND_FASTCALL zend_jit_assign_obj_op_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, binary_op_type binary_op)
2019+
{
2020+
zval *zptr;
2021+
zend_property_info *prop_info;
2022+
2023+
if (EXPECTED((zptr = zobj->handlers->get_property_ptr_ptr(zobj, name, BP_VAR_RW, cache_slot)) != NULL)) {
2024+
if (UNEXPECTED(Z_ISERROR_P(zptr))) {
2025+
//??? if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2026+
//??? ZVAL_NULL(EX_VAR(opline->result.var));
2027+
//??? }
2028+
} else {
2029+
//??? zval *orig_zptr = zptr;
2030+
zend_reference *ref;
2031+
2032+
do {
2033+
if (UNEXPECTED(Z_ISREF_P(zptr))) {
2034+
ref = Z_REF_P(zptr);
2035+
zptr = Z_REFVAL_P(zptr);
2036+
if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(ref))) {
2037+
zend_jit_assign_op_to_typed_ref(ref, value, binary_op);
2038+
break;
2039+
}
2040+
}
2041+
2042+
//??? if (OP2_TYPE == IS_CONST) {
2043+
prop_info = (zend_property_info*)CACHED_PTR_EX(cache_slot + 2);
2044+
//??? } else {
2045+
//??? prop_info = zend_object_fetch_property_type_info(Z_OBJ_P(object), orig_zptr);
2046+
//??? }
2047+
if (UNEXPECTED(prop_info)) {
2048+
/* special case for typed properties */
2049+
zend_jit_assign_op_to_typed_prop(zptr, prop_info, value, binary_op);
2050+
} else {
2051+
binary_op(zptr, zptr, value);
2052+
}
2053+
} while (0);
2054+
2055+
//??? if (UNEXPECTED(RETURN_VALUE_USED(opline))) {
2056+
//??? ZVAL_COPY(EX_VAR(opline->result.var), zptr);
2057+
//??? }
2058+
}
2059+
} else {
2060+
_zend_jit_assign_op_overloaded_property(zobj, name, cache_slot, value, binary_op);
2061+
}
2062+
}

ext/opcache/jit/zend_jit_trace.c

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,17 +1422,31 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
14221422
} else if (orig_op1_type != IS_UNKNOWN
14231423
&& (orig_op1_type & IS_TRACE_INDIRECT)
14241424
&& opline->result_type == IS_UNUSED) {
1425-
// ADD_OP1_DATA_TRACE_GUARD();
1425+
if (opline->opcode == ZEND_ASSIGN_DIM_OP) {
1426+
ADD_OP1_DATA_TRACE_GUARD();
1427+
}
14261428
ADD_OP2_TRACE_GUARD();
14271429
}
14281430
break;
1431+
case ZEND_ASSIGN_OBJ_OP:
1432+
if (opline->extended_value == ZEND_POW
1433+
|| opline->extended_value == ZEND_DIV) {
1434+
// TODO: check for division by zero ???
1435+
break;
1436+
}
1437+
if (opline->result_type != IS_UNUSED) {
1438+
break;
1439+
}
1440+
/* break missing intentionally */
14291441
case ZEND_ASSIGN_OBJ:
14301442
if (opline->op2_type != IS_CONST
14311443
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
14321444
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
14331445
break;
14341446
}
1435-
// ADD_OP1_DATA_TRACE_GUARD();
1447+
if (opline->opcode == ZEND_ASSIGN_OBJ_OP) {
1448+
ADD_OP1_DATA_TRACE_GUARD();
1449+
}
14361450
ADD_OP1_TRACE_GUARD();
14371451
break;
14381452
case ZEND_IS_EQUAL:
@@ -3718,6 +3732,80 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
37183732
goto jit_failure;
37193733
}
37203734
goto done;
3735+
case ZEND_ASSIGN_OBJ_OP:
3736+
if (opline->extended_value == ZEND_POW
3737+
|| opline->extended_value == ZEND_DIV) {
3738+
// TODO: check for division by zero ???
3739+
break;
3740+
}
3741+
if (opline->result_type != IS_UNUSED) {
3742+
break;
3743+
}
3744+
if (opline->op2_type != IS_CONST
3745+
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
3746+
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
3747+
break;
3748+
}
3749+
ce = NULL;
3750+
ce_is_instanceof = 0;
3751+
delayed_fetch_this = 0;
3752+
op1_indirect = 0;
3753+
if (opline->op1_type == IS_UNUSED) {
3754+
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
3755+
ce = op_array->scope;
3756+
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
3757+
op1_addr = 0;
3758+
} else {
3759+
if (ssa_op->op1_use >= 0) {
3760+
delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
3761+
}
3762+
op1_info = OP1_INFO();
3763+
if (!(op1_info & MAY_BE_OBJECT)) {
3764+
break;
3765+
}
3766+
op1_addr = OP1_REG_ADDR();
3767+
if (opline->op1_type == IS_VAR) {
3768+
if (orig_op1_type != IS_UNKNOWN
3769+
&& (orig_op1_type & IS_TRACE_INDIRECT)) {
3770+
op1_indirect = 1;
3771+
if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
3772+
&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
3773+
goto jit_failure;
3774+
}
3775+
}
3776+
}
3777+
if (orig_op1_type != IS_UNKNOWN
3778+
&& (orig_op1_type & IS_TRACE_REFERENCE)) {
3779+
if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
3780+
!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
3781+
goto jit_failure;
3782+
}
3783+
if (opline->op1_type == IS_CV
3784+
&& zend_jit_var_may_alias(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op1.var)) == NO_ALIAS) {
3785+
ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
3786+
}
3787+
} else {
3788+
CHECK_OP1_TRACE_TYPE();
3789+
}
3790+
if (ssa->var_info && ssa->ops) {
3791+
if (ssa_op->op1_use >= 0) {
3792+
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
3793+
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
3794+
ce = op1_ssa->ce;
3795+
ce_is_instanceof = op1_ssa->is_instanceof;
3796+
}
3797+
}
3798+
}
3799+
}
3800+
op1_data_info = OP1_DATA_INFO();
3801+
CHECK_OP1_DATA_TRACE_TYPE();
3802+
if (!zend_jit_assign_obj_op(&dasm_state, opline, op_array, ssa, ssa_op,
3803+
op1_info, op1_addr, op1_data_info, OP1_DATA_RANGE(),
3804+
op1_indirect, ce, ce_is_instanceof, delayed_fetch_this, op1_ce,
3805+
zend_may_throw(opline, ssa_op, op_array, ssa))) {
3806+
goto jit_failure;
3807+
}
3808+
goto done;
37213809
case ZEND_ASSIGN_OBJ:
37223810
if (opline->op2_type != IS_CONST
37233811
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING

0 commit comments

Comments
 (0)