Skip to content

Commit

Permalink
JIT for ASSIGN_OBJ
Browse files Browse the repository at this point in the history
  • Loading branch information
dstogov committed Sep 10, 2020
1 parent e9b47df commit 7b0a053
Show file tree
Hide file tree
Showing 7 changed files with 518 additions and 31 deletions.
2 changes: 1 addition & 1 deletion Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -919,7 +919,7 @@ static zend_always_inline zend_bool i_zend_verify_property_type(zend_property_in
return 0;
}

zend_bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict) {
ZEND_API zend_bool zend_never_inline zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict) {
return i_zend_verify_property_type(info, property, strict);
}

Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ ZEND_API int ZEND_FASTCALL zend_handle_undef_args(zend_execute_data *call);

#define ZEND_CLASS_HAS_TYPE_HINTS(ce) ((ce->ce_flags & ZEND_ACC_HAS_TYPE_HINTS) == ZEND_ACC_HAS_TYPE_HINTS)

zend_bool zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict);
ZEND_API zend_bool zend_verify_property_type(zend_property_info *info, zval *property, zend_bool strict);
ZEND_COLD void zend_verify_property_type_error(zend_property_info *info, zval *property);

#define ZEND_REF_ADD_TYPE_SOURCE(ref, source) \
Expand Down
43 changes: 43 additions & 0 deletions ext/opcache/jit/zend_jit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2457,6 +2457,49 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op
goto jit_failure;
}
goto done;
case ZEND_ASSIGN_OBJ:
if (opline->op1_type == IS_VAR) {
break;
}
if (opline->op2_type != IS_CONST
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
if (PROFITABILITY_CHECKS && (!ssa->ops || !ssa->var_info)) {
break;
}
ce = NULL;
ce_is_instanceof = 0;
if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
ce = op_array->scope;
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
op1_addr = 0;
} else {
op1_info = OP1_INFO();
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (ssa->var_info && ssa->ops) {
zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes];
if (ssa_op->op1_use >= 0) {
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
ce = op1_ssa->ce;
ce_is_instanceof = op1_ssa->is_instanceof;
}
}
}
}
if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, OP1_DATA_INFO(),
0, ce, ce_is_instanceof, 0, NULL,
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
}
goto done;
case ZEND_ASSIGN:
if (opline->op1_type != IS_CV) {
break;
Expand Down
3 changes: 3 additions & 0 deletions ext/opcache/jit/zend_jit_disasm_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,7 @@ static int zend_jit_disasm_init(void)
REGISTER_HELPER(zend_jit_invalid_array_access);
REGISTER_HELPER(zend_jit_invalid_property_read);
REGISTER_HELPER(zend_jit_invalid_property_write);
REGISTER_HELPER(zend_jit_invalid_property_assign);
REGISTER_HELPER(zend_jit_prepare_assign_dim_ref);
REGISTER_HELPER(zend_jit_pre_inc);
REGISTER_HELPER(zend_jit_pre_dec);
Expand All @@ -466,6 +467,8 @@ static int zend_jit_disasm_init(void)
REGISTER_HELPER(zend_jit_array_free);
REGISTER_HELPER(zend_jit_zval_array_dup);
REGISTER_HELPER(zend_jit_add_arrays_helper);
REGISTER_HELPER(zend_jit_assign_obj_helper);
REGISTER_HELPER(zend_jit_assign_to_typed_prop);
#undef REGISTER_HELPER

#ifndef _WIN32
Expand Down
38 changes: 38 additions & 0 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1858,6 +1858,13 @@ static void ZEND_FASTCALL zend_jit_invalid_property_write(zval *container, const
property_name, zend_zval_type_name(container));
}

static void ZEND_FASTCALL zend_jit_invalid_property_assign(zval *container, const char *property_name)
{
zend_throw_error(NULL,
"Attempt to assign property \"%s\" on %s",
property_name, zend_zval_type_name(container));
}

static zval * ZEND_FASTCALL zend_jit_prepare_assign_dim_ref(zval *ref) {
zval *val = Z_REFVAL_P(ref);
if (Z_TYPE_P(val) <= IS_FALSE) {
Expand Down Expand Up @@ -1927,3 +1934,34 @@ static zend_array *ZEND_FASTCALL zend_jit_add_arrays_helper(zend_array *op1, zen
zend_hash_merge(res, op2, zval_add_ref, 0);
return res;
}

static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_string *name, zval *value, void **cache_slot, zval *result)
{
ZVAL_DEREF(value);
value = zobj->handlers->write_property(zobj, name, value, cache_slot);
if (result) {
ZVAL_COPY_DEREF(result, value);
}
}

static void ZEND_FASTCALL zend_jit_assign_to_typed_prop(zval *property_val, zend_property_info *info, zval *value, zval *result)
{
zend_execute_data *execute_data = EG(current_execute_data);
zval tmp;

ZVAL_DEREF(value);
ZVAL_COPY(&tmp, value);

if (UNEXPECTED(!zend_verify_property_type(info, &tmp, EX_USES_STRICT_TYPES()))) {
zval_ptr_dtor(&tmp);
if (result) {
ZVAL_NULL(result);
}
return;
}

value = zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES());
if (result) {
ZVAL_COPY_DEREF(result, value);
}
}
78 changes: 77 additions & 1 deletion ext/opcache/jit/zend_jit_trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1426,6 +1426,15 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
ADD_OP2_TRACE_GUARD();
}
break;
case ZEND_ASSIGN_OBJ:
if (opline->op2_type != IS_CONST
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
// ADD_OP1_DATA_TRACE_GUARD();
ADD_OP1_TRACE_GUARD();
break;
case ZEND_IS_EQUAL:
case ZEND_IS_NOT_EQUAL:
case ZEND_IS_SMALLER:
Expand Down Expand Up @@ -2795,7 +2804,8 @@ static zend_bool zend_jit_may_delay_fetch_this(zend_ssa *ssa, const zend_op **ss
}
} else if (opline->opcode != ZEND_FETCH_OBJ_R
&& opline->opcode != ZEND_FETCH_OBJ_IS
&& opline->opcode != ZEND_FETCH_OBJ_W) {
&& opline->opcode != ZEND_FETCH_OBJ_W
&& opline->opcode != ZEND_ASSIGN_OBJ) {
return 0;
}

Expand Down Expand Up @@ -3708,6 +3718,72 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
goto jit_failure;
}
goto done;
case ZEND_ASSIGN_OBJ:
if (opline->op2_type != IS_CONST
|| Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) != IS_STRING
|| Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] == '\0') {
break;
}
ce = NULL;
ce_is_instanceof = 0;
delayed_fetch_this = 0;
op1_indirect = 0;
if (opline->op1_type == IS_UNUSED) {
op1_info = MAY_BE_OBJECT|MAY_BE_RC1|MAY_BE_RCN;
ce = op_array->scope;
ce_is_instanceof = (ce->ce_flags & ZEND_ACC_FINAL) != 0;
op1_addr = 0;
} else {
if (ssa_op->op1_use >= 0) {
delayed_fetch_this = ssa->var_info[ssa_op->op1_use].delayed_fetch_this;
}
op1_info = OP1_INFO();
if (!(op1_info & MAY_BE_OBJECT)) {
break;
}
op1_addr = OP1_REG_ADDR();
if (opline->op1_type == IS_VAR) {
if (orig_op1_type != IS_UNKNOWN
&& (orig_op1_type & IS_TRACE_INDIRECT)) {
op1_indirect = 1;
if (!zend_jit_fetch_indirect_var(&dasm_state, opline, orig_op1_type,
&op1_info, &op1_addr, !ssa->var_info[ssa_op->op1_use].indirect_reference)) {
goto jit_failure;
}
}
}
if (orig_op1_type != IS_UNKNOWN
&& (orig_op1_type & IS_TRACE_REFERENCE)) {
if (!zend_jit_fetch_reference(&dasm_state, opline, orig_op1_type, &op1_info, &op1_addr,
!ssa->var_info[ssa_op->op1_use].guarded_reference, 1)) {
goto jit_failure;
}
if (opline->op1_type == IS_CV
&& zend_jit_var_may_alias(op_array, op_array_ssa, EX_VAR_TO_NUM(opline->op1.var)) == NO_ALIAS) {
ssa->var_info[ssa_op->op1_use].guarded_reference = 1;
}
} else {
CHECK_OP1_TRACE_TYPE();
}
if (ssa->var_info && ssa->ops) {
if (ssa_op->op1_use >= 0) {
zend_ssa_var_info *op1_ssa = ssa->var_info + ssa_op->op1_use;
if (op1_ssa->ce && !op1_ssa->ce->create_object) {
ce = op1_ssa->ce;
ce_is_instanceof = op1_ssa->is_instanceof;
}
}
}
}
op1_data_info = OP1_DATA_INFO();
CHECK_OP1_DATA_TRACE_TYPE();
if (!zend_jit_assign_obj(&dasm_state, opline, op_array, ssa, ssa_op,
op1_info, op1_addr, op1_data_info,
op1_indirect, ce, ce_is_instanceof, delayed_fetch_this, op1_ce,
zend_may_throw(opline, ssa_op, op_array, ssa))) {
goto jit_failure;
}
goto done;
case ZEND_ASSIGN_DIM:
op1_info = OP1_INFO();
op1_addr = OP1_REG_ADDR();
Expand Down
Loading

3 comments on commit 7b0a053

@cmb69
Copy link
Member

@cmb69 cmb69 commented on 7b0a053 Sep 13, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dstogov, as of this commit, Zend/tests/bug63635.phpt, Zend/tests/bug77345_gc_1.phpt and Zend/tests/bug77345_gc_2.phpt are segfaulting on Windows (the latter two only for ZTS). backtrace

@dstogov
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be fixed by 0a03291
Please, verify and confirm.

@cmb69
Copy link
Member

@cmb69 cmb69 commented on 7b0a053 Sep 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tests are passing now. Thanks!

Please sign in to comment.