Better specialization for packed/hash arrays

- improved packed/hash inference.
- added hash guards for ASSIGN_DIM, ASSIGN_DIM_OP, FETCH_DIM_W* instructions
- more accurate invariant type guards motion
- invariant packed/hash guards motion
- rename MAY_BE_ARRAY_HASH into MAY_BE_ARRAY_NUMERIC_HASH and add MAY_BE_ARRAY_STRING_HASH
- cleanup
This commit is contained in:
Dmitry Stogov 2021-08-13 14:30:41 +03:00
parent eb6c9eb936
commit 1ffbb7372a
7 changed files with 149 additions and 51 deletions

View file

@ -239,6 +239,19 @@ static void zend_dump_type_info(uint32_t info, zend_class_entry *ce, int is_inst
} }
if (info & MAY_BE_ARRAY) { if (info & MAY_BE_ARRAY) {
if (first) first = 0; else fprintf(stderr, ", "); if (first) first = 0; else fprintf(stderr, ", ");
if (!(info & MAY_BE_ARRAY_KEY_STRING) || (info & MAY_BE_PACKED_GUARD)) {
if (MAY_BE_PACKED_ONLY(info)) {
if (info & MAY_BE_PACKED_GUARD) {
fprintf(stderr, "!");
}
fprintf(stderr, "packed ");
} else if (MAY_BE_HASH_ONLY(info)) {
if (info & MAY_BE_PACKED_GUARD) {
fprintf(stderr, "!");
}
fprintf(stderr, "hash ");
}
}
fprintf(stderr, "array"); fprintf(stderr, "array");
if ((info & MAY_BE_ARRAY_KEY_ANY) != 0 && if ((info & MAY_BE_ARRAY_KEY_ANY) != 0 &&
((info & MAY_BE_ARRAY_KEY_LONG) == 0 || ((info & MAY_BE_ARRAY_KEY_LONG) == 0 ||

View file

@ -2107,16 +2107,16 @@ static uint32_t assign_dim_result_type(
tmp |= MAY_BE_ARRAY_OF_NULL; tmp |= MAY_BE_ARRAY_OF_NULL;
} }
if (dim_op_type == IS_UNUSED) { if (dim_op_type == IS_UNUSED) {
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} else { } else {
if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) { if (dim_type & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
if (dim_type & MAY_BE_STRING) { if (dim_type & MAY_BE_STRING) {
tmp |= MAY_BE_ARRAY_KEY_STRING; tmp |= MAY_BE_ARRAY_KEY_STRING;
if (dim_op_type != IS_CONST) { if (dim_op_type != IS_CONST) {
// FIXME: numeric string // FIXME: numeric string
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
} }
if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) { if (dim_type & (MAY_BE_UNDEF|MAY_BE_NULL)) {
@ -3179,6 +3179,13 @@ static zend_always_inline int _zend_update_type_info(
UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); UPDATE_SSA_TYPE(tmp, ssa_op->op1_def);
} }
if (ssa_op->result_def >= 0) { if (ssa_op->result_def >= 0) {
uint32_t arr_type;
if (opline->opcode == ZEND_INIT_ARRAY) {
arr_type = 0;
} else {
arr_type = RES_USE_INFO();
}
tmp = MAY_BE_RC1|MAY_BE_ARRAY; tmp = MAY_BE_RC1|MAY_BE_ARRAY;
if (ssa_op->result_use >= 0) { if (ssa_op->result_use >= 0) {
tmp |= ssa_var_info[ssa_op->result_use].type; tmp |= ssa_var_info[ssa_op->result_use].type;
@ -3192,16 +3199,16 @@ static zend_always_inline int _zend_update_type_info(
tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; tmp |= MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF;
} }
if (opline->op2_type == IS_UNUSED) { if (opline->op2_type == IS_UNUSED) {
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} else { } else {
if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) { if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_DOUBLE|MAY_BE_RESOURCE)) {
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
if (t2 & (MAY_BE_STRING)) { if (t2 & (MAY_BE_STRING)) {
tmp |= MAY_BE_ARRAY_KEY_STRING; tmp |= MAY_BE_ARRAY_KEY_STRING;
if (opline->op2_type != IS_CONST) { if (opline->op2_type != IS_CONST) {
// FIXME: numeric string // FIXME: numeric string
tmp |= MAY_BE_ARRAY_KEY_LONG; tmp |= MAY_BE_HASH_ONLY(arr_type) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
} }
if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {
@ -3343,16 +3350,16 @@ static zend_always_inline int _zend_update_type_info(
tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN); tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN);
} }
if (opline->op2_type == IS_UNUSED) { if (opline->op2_type == IS_UNUSED) {
key_type |= MAY_BE_ARRAY_KEY_LONG; key_type |= MAY_BE_HASH_ONLY(t1) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} else { } else {
if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) { if (t2 & (MAY_BE_LONG|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_RESOURCE|MAY_BE_DOUBLE)) {
key_type |= MAY_BE_ARRAY_KEY_LONG; key_type |= MAY_BE_HASH_ONLY(t1) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
if (t2 & MAY_BE_STRING) { if (t2 & MAY_BE_STRING) {
key_type |= MAY_BE_ARRAY_KEY_STRING; key_type |= MAY_BE_ARRAY_KEY_STRING;
if (opline->op2_type != IS_CONST) { if (opline->op2_type != IS_CONST) {
// FIXME: numeric string // FIXME: numeric string
key_type |= MAY_BE_ARRAY_KEY_LONG; key_type |= MAY_BE_HASH_ONLY(t1) ? MAY_BE_ARRAY_NUMERIC_HASH : MAY_BE_ARRAY_KEY_LONG;
} }
} }
if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) { if (t2 & (MAY_BE_UNDEF | MAY_BE_NULL)) {

View file

@ -176,7 +176,7 @@ static zend_always_inline uint32_t _const_op_type(const zval *zv) {
tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT); tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
if (HT_IS_PACKED(ht)) { if (HT_IS_PACKED(ht)) {
tmp &= ~MAY_BE_ARRAY_HASH; tmp &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
} }
return tmp; return tmp;
} else { } else {

View file

@ -58,12 +58,18 @@
#define MAY_BE_ARRAY_OF_REF (MAY_BE_REF << MAY_BE_ARRAY_SHIFT) #define MAY_BE_ARRAY_OF_REF (MAY_BE_REF << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_PACKED (1<<21) #define MAY_BE_ARRAY_PACKED (1<<21)
#define MAY_BE_ARRAY_HASH (1<<22) /* hash with numeric keys */ #define MAY_BE_ARRAY_NUMERIC_HASH (1<<22) /* hash with numeric keys */
#define MAY_BE_ARRAY_STRING_HASH (1<<23) /* hash with string keys */
#define MAY_BE_ARRAY_KEY_LONG (MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_HASH) #define MAY_BE_ARRAY_KEY_LONG (MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_NUMERIC_HASH)
#define MAY_BE_ARRAY_KEY_STRING (1<<23) #define MAY_BE_ARRAY_KEY_STRING MAY_BE_ARRAY_STRING_HASH
#define MAY_BE_ARRAY_KEY_ANY (MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_KEY_STRING) #define MAY_BE_ARRAY_KEY_ANY (MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_KEY_STRING)
#define MAY_BE_PACKED(t) ((t) & MAY_BE_ARRAY_PACKED)
#define MAY_BE_HASH(t) ((t) & (MAY_BE_ARRAY_NUMERIC_HASH | MAY_BE_ARRAY_KEY_STRING))
#define MAY_BE_PACKED_ONLY(t) (MAY_BE_PACKED(t) && !MAY_BE_HASH(t))
#define MAY_BE_HASH_ONLY(t) (MAY_BE_HASH(t) && !MAY_BE_PACKED(t))
#define MAY_BE_CLASS (1<<24) #define MAY_BE_CLASS (1<<24)
#define MAY_BE_INDIRECT (1<<25) #define MAY_BE_INDIRECT (1<<25)

View file

@ -4923,7 +4923,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
} }
if (packed_loaded) { if (packed_loaded) {
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef); | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
| ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)]
| TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w
| beq >4 // HASH_FIND | beq >4 // HASH_FIND
@ -4968,7 +4968,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
} }
switch (type) { switch (type) {
case BP_JIT_IS: case BP_JIT_IS:
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
if (packed_loaded) { if (packed_loaded) {
| b >5 | b >5
} }
@ -5001,11 +5001,11 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
case BP_VAR_IS: case BP_VAR_IS:
case BP_VAR_UNSET: case BP_VAR_UNSET:
if (packed_loaded) { if (packed_loaded) {
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
| IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w
} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
/* perform IS_UNDEF check only after result type guard (during deoptimization) */ /* perform IS_UNDEF check only after result type guard (during deoptimization) */
if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_HASH)) { if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
| IF_Z_TYPE REG0, IS_UNDEF, &exit_addr, TMP1w | IF_Z_TYPE REG0, IS_UNDEF, &exit_addr, TMP1w
} }
} else if (type == BP_VAR_IS && not_found_exit_addr) { } else if (type == BP_VAR_IS && not_found_exit_addr) {
@ -5016,7 +5016,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
| IF_Z_TYPE REG0, IS_UNDEF, >2, TMP1w // NOT_FOUND | IF_Z_TYPE REG0, IS_UNDEF, >2, TMP1w // NOT_FOUND
} }
} }
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_HASH))) { if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_NUMERIC_HASH))) {
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
| b &exit_addr | b &exit_addr
} else if (type == BP_VAR_IS && not_found_exit_addr) { } else if (type == BP_VAR_IS && not_found_exit_addr) {
@ -5027,7 +5027,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
| b >2 // NOT_FOUND | b >2 // NOT_FOUND
} }
} }
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
|4: |4:
if (!op2_loaded) { if (!op2_loaded) {
| // hval = Z_LVAL_P(dim); | // hval = Z_LVAL_P(dim);
@ -5088,7 +5088,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
if (packed_loaded) { if (packed_loaded) {
| IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w
} }
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_HASH) || packed_loaded) { if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded) {
|2: |2:
|4: |4:
if (!op2_loaded) { if (!op2_loaded) {

View file

@ -1587,6 +1587,20 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
} }
ADD_OP2_TRACE_GUARD(); ADD_OP2_TRACE_GUARD();
} }
if (op1_type == IS_ARRAY
&& !(orig_op1_type & IS_TRACE_PACKED)
&& ((opline->op2_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
|| (opline->op2_type != IS_CONST
&& op2_type == IS_LONG))) {
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
info->type |= MAY_BE_PACKED_GUARD;
info->type &= ~MAY_BE_ARRAY_PACKED;
}
}
break; break;
case ZEND_ASSIGN_OBJ_OP: case ZEND_ASSIGN_OBJ_OP:
if (opline->extended_value == ZEND_POW if (opline->extended_value == ZEND_POW
@ -1734,8 +1748,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
ADD_OP1_TRACE_GUARD(); ADD_OP1_TRACE_GUARD();
ADD_OP2_TRACE_GUARD(); ADD_OP2_TRACE_GUARD();
if (opline->op1_type != IS_CONST if (op1_type == IS_ARRAY
&& op1_type == IS_ARRAY && opline->op1_type != IS_CONST
&& ((opline->op2_type == IS_CONST && ((opline->op2_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG) && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
|| (opline->op2_type != IS_CONST || (opline->op2_type != IS_CONST
@ -1743,13 +1757,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if ((info->type & MAY_BE_ARRAY_PACKED) if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
&& (info->type & MAY_BE_ARRAY_HASH)
&& orig_op1_type != IS_UNKNOWN
&& !(orig_op1_type & IS_TRACE_REFERENCE)) {
info->type |= MAY_BE_PACKED_GUARD; info->type |= MAY_BE_PACKED_GUARD;
if (orig_op1_type & IS_TRACE_PACKED) { if (orig_op1_type & IS_TRACE_PACKED) {
info->type &= ~MAY_BE_ARRAY_HASH; info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
} else { } else {
info->type &= ~MAY_BE_ARRAY_PACKED; info->type &= ~MAY_BE_ARRAY_PACKED;
} }
@ -1767,6 +1778,20 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin
} }
ADD_OP1_TRACE_GUARD(); ADD_OP1_TRACE_GUARD();
ADD_OP2_TRACE_GUARD(); ADD_OP2_TRACE_GUARD();
if (op1_type == IS_ARRAY
&& !(orig_op1_type & IS_TRACE_PACKED)
&& ((opline->op2_type == IS_CONST
&& Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG)
|| (opline->op2_type != IS_CONST
&& op2_type == IS_LONG))) {
zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use];
if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) {
info->type |= MAY_BE_PACKED_GUARD;
info->type &= ~MAY_BE_ARRAY_PACKED;
}
}
break; break;
case ZEND_SEND_VAL_EX: case ZEND_SEND_VAL_EX:
case ZEND_SEND_VAR_EX: case ZEND_SEND_VAR_EX:
@ -2294,13 +2319,12 @@ propagate_arg:
while (phi) { while (phi) {
uint32_t t = ssa_var_info[phi->ssa_var].type; uint32_t t = ssa_var_info[phi->ssa_var].type;
if ((t & MAY_BE_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
uint32_t t0 = ssa_var_info[phi->sources[0]].type; uint32_t t0 = ssa_var_info[phi->sources[0]].type;
uint32_t t1 = ssa_var_info[phi->sources[1]].type; uint32_t t1 = ssa_var_info[phi->sources[1]].type;
if (t & MAY_BE_GUARD) { if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
if (tssa->vars[phi->ssa_var].alias != NO_ALIAS) {
/* pass */
} else if (((t0 | t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
if (!((t0 | t1) & MAY_BE_GUARD)) { if (!((t0 | t1) & MAY_BE_GUARD)) {
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD; ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
} }
@ -2308,20 +2332,66 @@ propagate_arg:
if (!(t1 & MAY_BE_GUARD) if (!(t1 & MAY_BE_GUARD)
|| is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) { || is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD; ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
ssa_var_info[phi->sources[0]].type = t | MAY_BE_GUARD; t0 = (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
(t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
MAY_BE_GUARD;
if (!(t0 & MAY_BE_ARRAY)) {
t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
}
if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
}
ssa_var_info[phi->sources[0]].type = t0;
ssa_var_info[phi->sources[0]].type = t0;
} }
} else { } else {
if ((t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) { if ((t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
ssa_var_info[phi->sources[0]].type = MAY_BE_GUARD | (t & t0); t0 = (t & t0 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
(t0 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
MAY_BE_GUARD;
if (!(t0 & MAY_BE_ARRAY)) {
t0 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
}
if (!(t0 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
t0 &= ~(MAY_BE_RC1|MAY_BE_RCN);
}
ssa_var_info[phi->sources[0]].type = t0;
} }
if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) { if ((t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) {
if (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0 if (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0
&& is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) { && is_checked_guard(tssa, ssa_opcodes, phi->sources[1], phi->ssa_var)) {
ssa_var_info[phi->sources[1]].type = MAY_BE_GUARD | (t & t1); t1 = (t & t1 & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
(t1 & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) |
MAY_BE_GUARD;
if (!(t1 & MAY_BE_ARRAY)) {
t1 &= ~(MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY);
}
if (!(t1 & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) {
t1 &= ~(MAY_BE_RC1|MAY_BE_RCN);
}
ssa_var_info[phi->sources[1]].type = t1;
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD; ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_GUARD;
} }
} }
} }
t = ssa_var_info[phi->ssa_var].type;
}
if ((t & MAY_BE_PACKED_GUARD) && tssa->vars[phi->ssa_var].alias == NO_ALIAS) {
uint32_t t0 = ssa_var_info[phi->sources[0]].type;
uint32_t t1 = ssa_var_info[phi->sources[1]].type;
if (((t0 | t1) & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
if (!((t0 | t1) & MAY_BE_PACKED_GUARD)) {
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
}
} else if ((t1 & MAY_BE_ARRAY_KEY_ANY) == (t & MAY_BE_ARRAY_KEY_ANY)) {
if (!(t1 & MAY_BE_PACKED_GUARD)) {
ssa_var_info[phi->ssa_var].type = t & ~MAY_BE_PACKED_GUARD;
ssa_var_info[phi->sources[0]].type =
(t0 & ~MAY_BE_ARRAY_KEY_ANY) | (t & MAY_BE_ARRAY_KEY_ANY) | MAY_BE_PACKED_GUARD;
}
}
} }
phi = phi->next; phi = phi->next;
} }
@ -3825,7 +3895,9 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
&& (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL
|| trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET)
&& ssa->vars[i].use_chain != -1) { && (ssa->vars[i].use_chain != -1
|| (ssa->vars[i].phi_use_chain
&& !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) {
if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) { if (!zend_jit_packed_guard(&dasm_state, opline, EX_NUM_TO_VAR(i), info)) {
goto jit_failure; goto jit_failure;
} }
@ -5170,12 +5242,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD; ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
} else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
&& (op1_info & MAY_BE_ARRAY_PACKED) && MAY_BE_PACKED(op1_info)
&& (op1_info & MAY_BE_ARRAY_HASH) && MAY_BE_HASH(op1_info)
&& orig_op1_type != IS_UNKNOWN) { && orig_op1_type != IS_UNKNOWN) {
op1_info |= MAY_BE_PACKED_GUARD; op1_info |= MAY_BE_PACKED_GUARD;
if (orig_op1_type & IS_TRACE_PACKED) { if (orig_op1_type & IS_TRACE_PACKED) {
op1_info &= ~MAY_BE_ARRAY_HASH; op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
} else { } else {
op1_info &= ~MAY_BE_ARRAY_PACKED; op1_info &= ~MAY_BE_ARRAY_PACKED;
} }
@ -5313,12 +5385,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par
ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD; ssa->var_info[ssa_op->op1_use].type &= ~MAY_BE_PACKED_GUARD;
} else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG } else if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG
&& (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY
&& (op1_info & MAY_BE_ARRAY_PACKED) && MAY_BE_PACKED(op1_info)
&& (op1_info & MAY_BE_ARRAY_HASH) && MAY_BE_HASH(op1_info)
&& orig_op1_type != IS_UNKNOWN) { && orig_op1_type != IS_UNKNOWN) {
op1_info |= MAY_BE_PACKED_GUARD; op1_info |= MAY_BE_PACKED_GUARD;
if (orig_op1_type & IS_TRACE_PACKED) { if (orig_op1_type & IS_TRACE_PACKED) {
op1_info &= ~MAY_BE_ARRAY_HASH; op1_info &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
} else { } else {
op1_info &= ~MAY_BE_ARRAY_PACKED; op1_info &= ~MAY_BE_ARRAY_PACKED;
} }

View file

@ -5381,7 +5381,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
} }
if (packed_loaded) { if (packed_loaded) {
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef); | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
| test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
| jz >4 // HASH_FIND | jz >4 // HASH_FIND
} }
@ -5436,7 +5436,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
} }
switch (type) { switch (type) {
case BP_JIT_IS: case BP_JIT_IS:
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
if (packed_loaded) { if (packed_loaded) {
| jmp >5 | jmp >5
} }
@ -5469,11 +5469,11 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
case BP_VAR_IS: case BP_VAR_IS:
case BP_VAR_UNSET: case BP_VAR_UNSET:
if (packed_loaded) { if (packed_loaded) {
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8 | IF_NOT_Z_TYPE r0, IS_UNDEF, >8
} else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
/* perform IS_UNDEF check only after result type guard (during deoptimization) */ /* perform IS_UNDEF check only after result type guard (during deoptimization) */
if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_HASH)) { if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) {
| IF_Z_TYPE r0, IS_UNDEF, &exit_addr | IF_Z_TYPE r0, IS_UNDEF, &exit_addr
} }
} else if (type == BP_VAR_IS && not_found_exit_addr) { } else if (type == BP_VAR_IS && not_found_exit_addr) {
@ -5484,7 +5484,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
| IF_Z_TYPE r0, IS_UNDEF, >2 // NOT_FOUND | IF_Z_TYPE r0, IS_UNDEF, >2 // NOT_FOUND
} }
} }
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_HASH))) { if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_NUMERIC_HASH))) {
if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
| jmp &exit_addr | jmp &exit_addr
} else if (type == BP_VAR_IS && not_found_exit_addr) { } else if (type == BP_VAR_IS && not_found_exit_addr) {
@ -5495,7 +5495,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
| jmp >2 // NOT_FOUND | jmp >2 // NOT_FOUND
} }
} }
if (op1_info & MAY_BE_ARRAY_HASH) { if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) {
|4: |4:
if (!op2_loaded) { if (!op2_loaded) {
| // hval = Z_LVAL_P(dim); | // hval = Z_LVAL_P(dim);
@ -5556,7 +5556,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
if (packed_loaded) { if (packed_loaded) {
| IF_NOT_Z_TYPE r0, IS_UNDEF, >8 | IF_NOT_Z_TYPE r0, IS_UNDEF, >8
} }
if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_HASH) || packed_loaded) { if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded) {
|2: |2:
|4: |4:
if (!op2_loaded) { if (!op2_loaded) {