]> granicus.if.org Git - php/commitdiff
Allow optional ignorance of operator overlaoding. Optimizer takes into account possib...
authorDmitry Stogov <dmitry@zend.com>
Mon, 19 Feb 2018 09:21:43 +0000 (12:21 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 19 Feb 2018 09:21:43 +0000 (12:21 +0300)
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_inference.h
ext/opcache/Optimizer/zend_optimizer.h

index ae067c58eb3ef4135753d4d1b4864692c44f3e4c..1f62b9ec93817a5c83b5f1112d97096cf183eb43 100644 (file)
@@ -110,7 +110,7 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
                return FAILURE;
        }
 
-       if (zend_ssa_inference(&ctx->arena, op_array, ctx->script, ssa) != SUCCESS) {
+       if (zend_ssa_inference(&ctx->arena, op_array, ctx->script, ssa, ctx->optimization_level) != SUCCESS) {
                return FAILURE;
        }
 
index a0302132d2bf82910af69af34a9eef5b84d7118a..08ae51667e10cf74e7fb8c8f323aead68aa6e404 100644 (file)
@@ -2092,16 +2092,19 @@ static uint32_t assign_dim_result_type(
 
 /* For binary ops that have compound assignment operators */
 static uint32_t binary_op_result_type(
-               zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, uint32_t result_var) {
+               zend_ssa *ssa, zend_uchar opcode, uint32_t t1, uint32_t t2, uint32_t result_var,
+               zend_long optimization_level) {
        uint32_t tmp = 0;
        uint32_t t1_type = (t1 & MAY_BE_ANY) | (t1 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
        uint32_t t2_type = (t2 & MAY_BE_ANY) | (t2 & MAY_BE_UNDEF ? MAY_BE_NULL : 0);
 
-       /* Handle potentially overloaded operators.
-        * This could be made more precise by checking the class type, if known. */
-       if ((t1_type & MAY_BE_OBJECT) || (t2_type & MAY_BE_OBJECT)) {
-               /* This is somewhat GMP specific. */
-               tmp |= MAY_BE_OBJECT | MAY_BE_FALSE | MAY_BE_RC1;
+       if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
+               /* Handle potentially overloaded operators.
+                * This could be made more precise by checking the class type, if known. */
+               if ((t1_type & MAY_BE_OBJECT) || (t2_type & MAY_BE_OBJECT)) {
+                       /* This is somewhat GMP specific. */
+                       tmp |= MAY_BE_OBJECT | MAY_BE_FALSE | MAY_BE_RC1;
+               }
        }
 
        switch (opcode) {
@@ -2158,7 +2161,11 @@ static uint32_t binary_op_result_type(
                         * handling */
                        break;
                case ZEND_MOD:
-                       tmp |= MAY_BE_LONG;
+                       if (ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level) {
+                               tmp = MAY_BE_LONG;
+                       } else {
+                               tmp |= MAY_BE_LONG;
+                       }
                        /* Division by zero results in an exception, so it doesn't need any special handling */
                        break;
                case ZEND_BW_OR:
@@ -2173,7 +2180,11 @@ static uint32_t binary_op_result_type(
                        break;
                case ZEND_SL:
                case ZEND_SR:
-                       tmp |= MAY_BE_LONG;
+                       if (ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level) {
+                               tmp = MAY_BE_LONG;
+                       } else {
+                               tmp |= MAY_BE_LONG;
+                       }
                        break;
                case ZEND_CONCAT:
                case ZEND_FAST_CONCAT:
@@ -2240,7 +2251,8 @@ static int zend_update_type_info(const zend_op_array *op_array,
                                   zend_ssa            *ssa,
                                   const zend_script   *script,
                                   zend_bitset          worklist,
-                                  int                  i)
+                                  int                  i,
+                                  zend_long            optimization_level)
 {
        uint32_t t1, t2;
        uint32_t tmp, orig;
@@ -2290,7 +2302,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                case ZEND_SL:
                case ZEND_SR:
                case ZEND_CONCAT:
-                       tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_ops[i].result_def);
+                       tmp = binary_op_result_type(ssa, opline->opcode, t1, t2, ssa_ops[i].result_def, optimization_level);
                        UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
                        break;
                case ZEND_BW_NOT:
@@ -2301,9 +2313,11 @@ static int zend_update_type_info(const zend_op_array *op_array,
                        if (t1 & (MAY_BE_ANY-MAY_BE_STRING)) {
                                tmp |= MAY_BE_LONG;
                        }
-                       if (t1 & MAY_BE_OBJECT) {
-                               /* Potentially overloaded operator. */
-                               tmp |= MAY_BE_OBJECT | MAY_BE_RC1;
+                       if (!(ZEND_OPTIMIZER_IGNORE_OVERLOADING & optimization_level)) {
+                               if (t1 & MAY_BE_OBJECT) {
+                                       /* Potentially overloaded operator. */
+                                       tmp |= MAY_BE_OBJECT | MAY_BE_RC1;
+                               }
                        }
                        UPDATE_SSA_TYPE(tmp, ssa_ops[i].result_def);
                        break;
@@ -2445,7 +2459,7 @@ static int zend_update_type_info(const zend_op_array *op_array,
                        }
 
                        tmp |= binary_op_result_type(
-                               ssa, get_compound_assign_op(opline->opcode), t1, t2, ssa_ops[i].op1_def);
+                               ssa, get_compound_assign_op(opline->opcode), t1, t2, ssa_ops[i].op1_def, optimization_level);
                        if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) {
                                tmp |= MAY_BE_RC1;
                        }
@@ -3468,7 +3482,7 @@ static zend_class_entry *join_class_entries(
        return ce1;
 }
 
-int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist)
+int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level)
 {
        zend_basic_block *blocks = ssa->cfg.blocks;
        zend_ssa_var *ssa_vars = ssa->vars;
@@ -3535,7 +3549,7 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
                        }
                } else if (ssa_vars[j].definition >= 0) {
                        i = ssa_vars[j].definition;
-                       if (zend_update_type_info(op_array, ssa, script, worklist, i) == FAILURE) {
+                       if (zend_update_type_info(op_array, ssa, script, worklist, i, optimization_level) == FAILURE) {
                                return FAILURE;
                        }
                }
@@ -3707,7 +3721,7 @@ static zend_bool can_convert_to_double(
        return 1;
 }
 
-static int zend_type_narrowing(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa)
+static int zend_type_narrowing(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
 {
        uint32_t bitset_len = zend_bitset_len(ssa->vars_count);
        zend_bitset visited, worklist;
@@ -3751,7 +3765,7 @@ static int zend_type_narrowing(const zend_op_array *op_array, const zend_script
                return SUCCESS;
        }
 
-       if (zend_infer_types_ex(op_array, script, ssa, worklist) != SUCCESS) {
+       if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) != SUCCESS) {
                free_alloca(visited, use_heap);
                return FAILURE;
        }
@@ -4001,7 +4015,7 @@ void zend_func_return_info(const zend_op_array   *op_array,
        ret->has_range = tmp_has_range;
 }
 
-static int zend_infer_types(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa)
+static int zend_infer_types(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level)
 {
        zend_ssa_var_info *ssa_var_info = ssa->var_info;
        int ssa_vars_count = ssa->vars_count;
@@ -4018,13 +4032,13 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc
                ssa_var_info[j].type = 0;
        }
 
-       if (zend_infer_types_ex(op_array, script, ssa, worklist) != SUCCESS) {
+       if (zend_infer_types_ex(op_array, script, ssa, worklist, optimization_level) != SUCCESS) {
                free_alloca(worklist,  use_heap);
                return FAILURE;
        }
 
        /* Narrowing integer initialization to doubles */
-       zend_type_narrowing(op_array, script, ssa);
+       zend_type_narrowing(op_array, script, ssa, optimization_level);
 
        if (ZEND_FUNC_INFO(op_array)) {
                zend_func_return_info(op_array, script, 1, 0, &ZEND_FUNC_INFO(op_array)->return_info);
@@ -4034,7 +4048,7 @@ static int zend_infer_types(const zend_op_array *op_array, const zend_script *sc
        return SUCCESS;
 }
 
-int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa) /* {{{ */
+int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level) /* {{{ */
 {
        zend_ssa_var_info *ssa_var_info;
        int i;
@@ -4067,7 +4081,7 @@ int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const
                return FAILURE;
        }
 
-       if (zend_infer_types(op_array, script, ssa) != SUCCESS) {
+       if (zend_infer_types(op_array, script, ssa, optimization_level) != SUCCESS) {
                return FAILURE;
        }
 
index 7b058fe45daf62de61592ff27adbc7531bf6f286..e3d767da04d2e04773eaef40bccfd9b0a994a235 100644 (file)
@@ -243,7 +243,7 @@ BEGIN_EXTERN_C()
 
 int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa);
 int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
-int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa);
+int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level);
 
 uint32_t zend_array_element_type(uint32_t t1, int write, int insert);
 
@@ -253,7 +253,7 @@ int  zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *
 int  zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
 void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
 
-int  zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist);
+int  zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist, zend_long optimization_level);
 
 void zend_init_func_return_info(const zend_op_array   *op_array,
                                 const zend_script     *script,
index e1c96bec4591c4a5afc676dfc840146d155c3c15..3c6a0fe50eab44b89ea06ff0e011f90005bdd5dd 100644 (file)
 #define ZEND_OPTIMIZER_PASS_12         (1<<11)  /* Adjust used stack           */
 #define ZEND_OPTIMIZER_PASS_13         (1<<12)  /* Remove unused variables     */
 #define ZEND_OPTIMIZER_PASS_14         (1<<13)  /* DCE (dead code elimination) */
-#define ZEND_OPTIMIZER_PASS_15         (1<<14)  /* Collect constants */
+#define ZEND_OPTIMIZER_PASS_15         (1<<14)  /* (unsafe) Collect constants */
 #define ZEND_OPTIMIZER_PASS_16         (1<<15)  /* Inline functions */
 
+#define ZEND_OPTIMIZER_IGNORE_OVERLOADING      (1<<16)  /* (unsafe) Ignore possibility of operator overloading */
+
 #define ZEND_OPTIMIZER_ALL_PASSES      0x7FFFFFFF
 
-#define DEFAULT_OPTIMIZATION_LEVEL  "0x7FFFBFFF"
+#define DEFAULT_OPTIMIZATION_LEVEL  "0x7FFEBFFF"
 
 
 #define ZEND_DUMP_AFTER_PASS_1         ZEND_OPTIMIZER_PASS_1