diff --git a/Zend/Optimizer/zend_dump.c b/Zend/Optimizer/zend_dump.c index f5a1baeb8c3..3c27d2786e8 100644 --- a/Zend/Optimizer/zend_dump.c +++ b/Zend/Optimizer/zend_dump.c @@ -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 (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"); if ((info & MAY_BE_ARRAY_KEY_ANY) != 0 && ((info & MAY_BE_ARRAY_KEY_LONG) == 0 || diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index e0d118bbf87..2505de8bd8b 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -2107,16 +2107,16 @@ static uint32_t assign_dim_result_type( tmp |= MAY_BE_ARRAY_OF_NULL; } 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 { 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) { tmp |= MAY_BE_ARRAY_KEY_STRING; if (dim_op_type != IS_CONST) { // 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)) { @@ -3179,6 +3179,13 @@ static zend_always_inline int _zend_update_type_info( UPDATE_SSA_TYPE(tmp, ssa_op->op1_def); } 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; if (ssa_op->result_use >= 0) { 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; } 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 { 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)) { tmp |= MAY_BE_ARRAY_KEY_STRING; if (opline->op2_type != IS_CONST) { // 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)) { @@ -3343,16 +3350,16 @@ static zend_always_inline int _zend_update_type_info( tmp |= t1 & (MAY_BE_RC1|MAY_BE_RCN); } 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 { 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) { key_type |= MAY_BE_ARRAY_KEY_STRING; if (opline->op2_type != IS_CONST) { // 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)) { diff --git a/Zend/Optimizer/zend_inference.h b/Zend/Optimizer/zend_inference.h index 1e1e471c328..54910a957ce 100644 --- a/Zend/Optimizer/zend_inference.h +++ b/Zend/Optimizer/zend_inference.h @@ -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); } ZEND_HASH_FOREACH_END(); if (HT_IS_PACKED(ht)) { - tmp &= ~MAY_BE_ARRAY_HASH; + tmp &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH); } return tmp; } else { diff --git a/Zend/zend_type_info.h b/Zend/zend_type_info.h index b61b09d296e..93048a777bd 100644 --- a/Zend/zend_type_info.h +++ b/Zend/zend_type_info.h @@ -58,12 +58,18 @@ #define MAY_BE_ARRAY_OF_REF (MAY_BE_REF << MAY_BE_ARRAY_SHIFT) #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_STRING (1<<23) +#define MAY_BE_ARRAY_KEY_LONG (MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_NUMERIC_HASH) +#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_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_INDIRECT (1<<25) diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index a6b4f1a75dd..f2e9bc4f6ca 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -4923,7 +4923,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } if (packed_loaded) { | // 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)] | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w | beq >4 // HASH_FIND @@ -4968,7 +4968,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } switch (type) { case BP_JIT_IS: - if (op1_info & MAY_BE_ARRAY_HASH) { + if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { if (packed_loaded) { | 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_UNSET: 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 } 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) */ - 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 } } 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 (!(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) { | b &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 } } - if (op1_info & MAY_BE_ARRAY_HASH) { + if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { |4: if (!op2_loaded) { | // 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_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: |4: if (!op2_loaded) { diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index e7778060c92..60db75ec79f 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1587,6 +1587,20 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin } 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; case ZEND_ASSIGN_OBJ_OP: 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_OP2_TRACE_GUARD(); - if (opline->op1_type != IS_CONST - && op1_type == IS_ARRAY + if (op1_type == IS_ARRAY + && opline->op1_type != IS_CONST && ((opline->op2_type == IS_CONST && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_LONG) || (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]; - if ((info->type & MAY_BE_ARRAY_PACKED) - && (info->type & MAY_BE_ARRAY_HASH) - && orig_op1_type != IS_UNKNOWN - && !(orig_op1_type & IS_TRACE_REFERENCE)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { info->type |= MAY_BE_PACKED_GUARD; 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 { 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_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; case ZEND_SEND_VAL_EX: case ZEND_SEND_VAR_EX: @@ -2293,14 +2318,13 @@ propagate_arg: ssa = &jit_extension->func_info.ssa; while (phi) { - uint32_t t = ssa_var_info[phi->ssa_var].type; - uint32_t t0 = ssa_var_info[phi->sources[0]].type; - uint32_t t1 = ssa_var_info[phi->sources[1]].type; + uint32_t t = ssa_var_info[phi->ssa_var].type; - if (t & MAY_BE_GUARD) { - 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 ((t & MAY_BE_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_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == (t & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF))) { if (!((t0 | t1) & 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) || 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->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 { 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 (((t & t1) & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != 0 && 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; } } } + 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; } @@ -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_RECURSIVE_CALL || 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)) { 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; } 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_ARRAY_PACKED) - && (op1_info & MAY_BE_ARRAY_HASH) + && MAY_BE_PACKED(op1_info) + && MAY_BE_HASH(op1_info) && orig_op1_type != IS_UNKNOWN) { op1_info |= MAY_BE_PACKED_GUARD; 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 { 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; } 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_ARRAY_PACKED) - && (op1_info & MAY_BE_ARRAY_HASH) + && MAY_BE_PACKED(op1_info) + && MAY_BE_HASH(op1_info) && orig_op1_type != IS_UNKNOWN) { op1_info |= MAY_BE_PACKED_GUARD; 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 { op1_info &= ~MAY_BE_ARRAY_PACKED; } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 27965c6bd94..c47dd55ad4f 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -5381,7 +5381,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } if (packed_loaded) { | // 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 | jz >4 // HASH_FIND } @@ -5436,7 +5436,7 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o } switch (type) { case BP_JIT_IS: - if (op1_info & MAY_BE_ARRAY_HASH) { + if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { if (packed_loaded) { | 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_UNSET: 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 } 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) */ - 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 } } 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 (!(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) { | jmp &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 } } - if (op1_info & MAY_BE_ARRAY_HASH) { + if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { |4: if (!op2_loaded) { | // 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_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: |4: if (!op2_loaded) {