summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_type_info.h15
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c4
-rw-r--r--ext/opcache/Optimizer/zend_inference.c4
-rw-r--r--ext/opcache/Optimizer/zend_inference.h3
-rw-r--r--ext/opcache/jit/zend_jit_x86.dasc104
5 files changed, 75 insertions, 55 deletions
diff --git a/Zend/zend_type_info.h b/Zend/zend_type_info.h
index 9dc90d142b..a0fc698ebe 100644
--- a/Zend/zend_type_info.h
+++ b/Zend/zend_type_info.h
@@ -56,11 +56,18 @@
#define MAY_BE_ARRAY_OF_ANY (MAY_BE_ANY << MAY_BE_ARRAY_SHIFT)
#define MAY_BE_ARRAY_OF_REF (MAY_BE_REF << MAY_BE_ARRAY_SHIFT)
-#define MAY_BE_ARRAY_KEY_LONG (1<<21)
-#define MAY_BE_ARRAY_KEY_STRING (1<<22)
+#define MAY_BE_ARRAY_PACKED (1<<21)
+#define MAY_BE_ARRAY_HASH (1<<22) /* hash with numeric 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_ANY (MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_KEY_STRING)
-#define MAY_BE_CLASS (1<<23)
-#define MAY_BE_INDIRECT (1<<24)
+#define MAY_BE_CLASS (1<<24)
+#define MAY_BE_INDIRECT (1<<25)
+
+
+#define MAY_BE_ANY_ARRAY \
+ (MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)
#endif /* ZEND_TYPE_INFO_H */
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index 47c4af5115..a387942919 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -64,7 +64,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
uint32_t t2 = _ssa_op1_info(op_array, ssa, call_info->arg_info[1].opline,
&ssa->ops[call_info->arg_info[1].opline - op_array->opcodes]);
uint32_t t3 = 0;
- uint32_t tmp = MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG;
+ uint32_t tmp = MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED;
if (call_info->num_args == 3) {
t3 = _ssa_op1_info(op_array, ssa, call_info->arg_info[2].opline,
@@ -86,7 +86,7 @@ static uint32_t zend_range_info(const zend_call_info *call_info, const zend_ssa
return tmp;
} else {
/* May throw */
- return MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
+ return MAY_BE_RC1 | MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_OF_LONG | MAY_BE_ARRAY_OF_DOUBLE | MAY_BE_ARRAY_OF_STRING;
}
}
diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c
index ab8b751acc..9a66c91d64 100644
--- a/ext/opcache/Optimizer/zend_inference.c
+++ b/ext/opcache/Optimizer/zend_inference.c
@@ -2454,7 +2454,7 @@ static zend_always_inline int _zend_update_type_info(
if (t1 & MAY_BE_OBJECT) {
tmp |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
} else {
- tmp |= ((t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT) | ((t1 & MAY_BE_ANY)? MAY_BE_ARRAY_KEY_LONG : 0);
+ tmp |= ((t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT) | ((t1 & MAY_BE_ANY) ? MAY_BE_ARRAY_PACKED : 0);
}
}
UPDATE_SSA_TYPE(tmp, ssa_op->result_def);
@@ -3474,7 +3474,7 @@ static zend_always_inline int _zend_update_type_info(
UPDATE_SSA_TYPE(MAY_BE_LONG, ssa_op->result_def);
break;
case ZEND_FUNC_GET_ARGS:
- UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN| MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
+ UPDATE_SSA_TYPE(MAY_BE_RC1|MAY_BE_RCN| MAY_BE_ARRAY | MAY_BE_ARRAY_PACKED | MAY_BE_ARRAY_OF_ANY, ssa_op->result_def);
break;
case ZEND_GET_CLASS:
case ZEND_GET_CALLED_CLASS:
diff --git a/ext/opcache/Optimizer/zend_inference.h b/ext/opcache/Optimizer/zend_inference.h
index 0708d5df94..e4c8598ce4 100644
--- a/ext/opcache/Optimizer/zend_inference.h
+++ b/ext/opcache/Optimizer/zend_inference.h
@@ -178,6 +178,9 @@ 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;
+ }
return tmp;
} else {
uint32_t tmp = (1 << Z_TYPE_P(zv));
diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc
index f655c1616d..f761c851bf 100644
--- a/ext/opcache/jit/zend_jit_x86.dasc
+++ b/ext/opcache/jit/zend_jit_x86.dasc
@@ -4947,21 +4947,26 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
}
if (op2_info & MAY_BE_LONG) {
+ zend_bool op2_loaded = 0;
+
if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) {
| // if (EXPECTED(Z_TYPE_P(dim) == IS_LONG))
| IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3
}
- if (type == BP_VAR_W || type == BP_VAR_RW) {
+ if (type == BP_VAR_W) {
| // hval = Z_LVAL_P(dim);
| GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ op2_loaded = 1;
}
- if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
+ if ((op1_info & MAY_BE_ARRAY_KEY_LONG) && (op1_info & MAY_BE_ARRAY_PACKED)) {
if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
zend_long val = Z_LVAL_P(Z_ZV(op2_addr));
if (val >= 0 && val < HT_MAX_SIZE) {
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
- | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
- | jz >4 // HASH_FIND
+ if (op1_info & MAY_BE_ARRAY_HASH) {
+ | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
+ | jz >4 // HASH_FIND
+ }
| // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
|.if X64
| movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
@@ -4998,13 +5003,16 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
}
}
} else {
- if (type != BP_VAR_W && type != BP_VAR_RW) {
+ if (!op2_loaded) {
| // hval = Z_LVAL_P(dim);
| GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ op2_loaded = 1;
}
| // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef);
- | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
- | jz >4 // HASH_FIND
+ if (op1_info & MAY_BE_ARRAY_HASH) {
+ | test dword [FCARG1a + offsetof(zend_array, u.flags)], HASH_FLAG_PACKED
+ | jz >4 // HASH_FIND
+ }
| // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed))
|.if X64
| movsxd r0, dword [FCARG1a + offsetof(zend_array, nNumUsed)]
@@ -5042,60 +5050,58 @@ 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_KEY_LONG) {
+ if ((op1_info & MAY_BE_ARRAY_KEY_LONG) && (op1_info & MAY_BE_ARRAY_HASH)) {
|4:
- }
- if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
- | // hval = Z_LVAL_P(dim);
- | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
- }
- | EXT_CALL _zend_hash_index_find, r0
- | test r0, r0
- if (not_found_exit_addr) {
- | jz &not_found_exit_addr
+ if (!op2_loaded) {
+ | // hval = Z_LVAL_P(dim);
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ }
+ | EXT_CALL _zend_hash_index_find, r0
+ | test r0, r0
+ if (not_found_exit_addr) {
+ | jz &not_found_exit_addr
+ } else {
+ | jz >9 // NOT_FOUND
+ }
+ if (op2_info & MAY_BE_STRING) {
+ | jmp >5
+ }
+ } else if (not_found_exit_addr) {
+ | jmp &not_found_exit_addr
} else {
- | jz >9 // NOT_FOUND
- }
- if (op2_info & MAY_BE_STRING) {
- | jmp >5
+ | jmp >9 // NOT_FOUND
}
break;
case BP_VAR_R:
case BP_VAR_IS:
case BP_VAR_UNSET:
- if (op1_info & MAY_BE_ARRAY_KEY_LONG) {
- if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
- zend_long val = Z_LVAL_P(Z_ZV(op2_addr));
- if (val >= 0 && val < HT_MAX_SIZE) {
- 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) {
- | jmp &not_found_exit_addr
- } else {
- | jmp >2 // NOT_FOUND
- }
- }
- } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
+ if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) ||
+ !(op1_info & MAY_BE_ARRAY_HASH) ||
+ Z_MODE(op2_addr) != IS_CONST_ZVAL ||
+ (Z_LVAL_P(Z_ZV(op2_addr)) >= 0 && Z_LVAL_P(Z_ZV(op2_addr)) < HT_MAX_SIZE)) {
+ 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) {
| jmp &not_found_exit_addr
} else {
| jmp >2 // NOT_FOUND
}
- |4:
}
- if (Z_MODE(op2_addr) == IS_CONST_ZVAL) {
- | // hval = Z_LVAL_P(dim);
- | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
- }
- | EXT_CALL _zend_hash_index_find, r0
- | test r0, r0
- if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
- | jz &exit_addr
- } else if (type == BP_VAR_IS && not_found_exit_addr) {
- | jz &not_found_exit_addr
- } else {
- | jz >2 // NOT_FOUND
+ if ((op1_info & MAY_BE_ARRAY_KEY_LONG) && (op1_info & MAY_BE_ARRAY_HASH)) {
+ |4:
+ if (!op2_loaded) {
+ | // hval = Z_LVAL_P(dim);
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ }
+ | EXT_CALL _zend_hash_index_find, r0
+ | test r0, r0
+ if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) {
+ | jz &exit_addr
+ } else if (type == BP_VAR_IS && not_found_exit_addr) {
+ | jz &not_found_exit_addr
+ } else {
+ | jz >2 // NOT_FOUND
+ }
}
|.cold_code
|2:
@@ -5124,6 +5130,10 @@ static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_o
case BP_VAR_RW:
|2:
|4:
+ if (!op2_loaded) {
+ | // hval = Z_LVAL_P(dim);
+ | GET_ZVAL_LVAL ZREG_FCARG2a, op2_addr
+ }
| SAVE_VALID_OPLINE opline, r0
| EXT_CALL zend_jit_hash_index_lookup_rw, r0
| test r0, r0