]> granicus.if.org Git - php/commitdiff
Infer information about packed/hash arrays and use it for JIT
authorDmitry Stogov <dmitry@zend.com>
Tue, 25 Aug 2020 15:28:23 +0000 (18:28 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 25 Aug 2020 15:28:23 +0000 (18:28 +0300)
Zend/zend_type_info.h
ext/opcache/Optimizer/zend_func_info.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_inference.h
ext/opcache/jit/zend_jit_x86.dasc

index 9dc90d142b4ed80ee1833e6124f6b74197a4a708..a0fc698ebe5ee9d1bc49b0ec44e1af00fa5ffe40 100644 (file)
 #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 */
index 47c4af5115c45b0d02e06535bd0fbf61c7a12588..a387942919cb6dbc2ac3de6a20d1b773444370cd 100644 (file)
@@ -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;
        }
 }
 
index ab8b751acc461af189c3e59e2c324d489ca377b3..9a66c91d64cb9d8e7864fc9d66bccc350ded9bc7 100644 (file)
@@ -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:
index 0708d5df94516e39c83c2df7653778e56f56ee79..e4c8598ce41ea82b157fb0a6136edae0257f5302 100644 (file)
@@ -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));
index f655c1616d423903a46a6c8e84e0b2f3f14caffb..f761c851bf6a389655860611a1044bfbb5cb9fcb 100644 (file)
@@ -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