]> granicus.if.org Git - php/commitdiff
Add support for "instanceof" pi nodes
authorNikita Popov <nikic@php.net>
Tue, 7 Jun 2016 19:52:47 +0000 (21:52 +0200)
committerNikita Popov <nikic@php.net>
Mon, 13 Jun 2016 17:03:59 +0000 (19:03 +0200)
ext/opcache/Optimizer/dfa_pass.c
ext/opcache/Optimizer/zend_dump.c
ext/opcache/Optimizer/zend_inference.c
ext/opcache/Optimizer/zend_ssa.c
ext/opcache/Optimizer/zend_ssa.h

index 1b3de7e2b637a1796578324f2b19fc1708c3f89f..f89094edec50f40978e38abde9e63d8bdad5463c 100644 (file)
@@ -82,7 +82,7 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,
        if (ctx->debug_level & ZEND_DUMP_DFA_PHI) {
                build_flags |= ZEND_SSA_DEBUG_PHI_PLACEMENT;
        }
-       if (zend_build_ssa(&ctx->arena, op_array, build_flags, ssa, flags) != SUCCESS) {
+       if (zend_build_ssa(&ctx->arena, ctx->script, op_array, build_flags, ssa, flags) != SUCCESS) {
                return FAILURE;
        }
 
index 17f5437c9592e78c6d468066f23afc87963b5ebc..a2eeb886ee824667787362947256e696804d13bb 100644 (file)
@@ -335,7 +335,7 @@ static void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa
 static void zend_dump_type_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_type_constraint *constraint, uint32_t dump_flags)
 {
        fprintf(stderr, " TYPE");
-       zend_dump_type_info(constraint->type_mask, NULL, 0, dump_flags);
+       zend_dump_type_info(constraint->type_mask, constraint->ce, 1, dump_flags);
 }
 
 static void zend_dump_range_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_range_constraint *r, uint32_t dump_flags)
index 865fb9c3382a676a65c98a72f0a739dcbecd7e73..d9e1d7f4f2417ed8e3184443f8076707bb98b9ce 100644 (file)
@@ -3427,14 +3427,28 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script
                if (ssa_vars[j].definition_phi) {
                        zend_ssa_phi *p = ssa_vars[j].definition_phi;
                        if (p->pi >= 0) {
+                               zend_class_entry *ce = ssa_var_info[p->sources[0]].ce;
+                               int is_instanceof = ssa_var_info[p->sources[0]].is_instanceof;
                                tmp = get_ssa_var_info(ssa, p->sources[0]);
+
                                if (!p->has_range_constraint) {
-                                       tmp &= p->constraint.type.type_mask;
+                                       zend_ssa_type_constraint *constraint = &p->constraint.type;
+                                       tmp &= constraint->type_mask;
+                                       if ((tmp & MAY_BE_OBJECT) && constraint->ce && ce != constraint->ce) {
+                                               if (!ce) {
+                                                       ce = constraint->ce;
+                                                       is_instanceof = 1;
+                                               } else if (is_instanceof && instanceof_function(constraint->ce, ce)) {
+                                                       ce = constraint->ce;
+                                               } else {
+                                                       /* Ignore the constraint (either ce instanceof constraint->ce or
+                                                        * they are unrelated, as far as we can statically determine) */
+                                               }
+                                       }
                                }
+
                                UPDATE_SSA_TYPE(tmp, j);
-                               if (ssa_var_info[p->sources[0]].ce) {
-                                       UPDATE_SSA_OBJ_TYPE(ssa_var_info[p->sources[0]].ce, ssa_var_info[p->sources[0]].is_instanceof, j);
-                               }
+                               UPDATE_SSA_OBJ_TYPE(ce, is_instanceof, j);
                        } else {
                                int first = 1;
                                int is_instanceof = 0;
index 9e585f4536781283c190e89ecad37e771f030d48..6f1fff961cacc482b6191bb5e5b084d666f7c828 100644 (file)
@@ -139,6 +139,7 @@ static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) {
 
 static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) {
        phi->has_range_constraint = 0;
+       phi->constraint.type.ce = NULL;
        phi->constraint.type.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN;
        phi->constraint.type.type_mask |= type_mask;
        if (type_mask & MAY_BE_NULL) {
@@ -222,8 +223,8 @@ static inline zend_bool sub_will_overflow(zend_long a, zend_long b) {
  * Order of Phis is importent, Pis must be placed before Phis
  */
 static void place_essa_pis(
-               zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa,
-               zend_dfg *dfg) /* {{{ */ {
+               zend_arena **arena, const zend_script *script, const zend_op_array *op_array,
+               uint32_t build_flags, zend_ssa *ssa, zend_dfg *dfg) /* {{{ */ {
        zend_basic_block *blocks = ssa->cfg.blocks;
        int j, blocks_count = ssa->cfg.blocks_count;
        for (j = 0; j < blocks_count; j++) {
@@ -485,6 +486,23 @@ static void place_essa_pis(
                                        pi_not_type_mask(pi, type_mask);
                                }
                        }
+               } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_INSTANCEOF &&
+                                  opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV &&
+                                  (opline-1)->op2_type == IS_CONST) {
+                       int var = EX_VAR_TO_NUM((opline-1)->op1.var);
+                       zend_string *lcname = Z_STR_P(CRT_CONSTANT((opline-1)->op2) + 1);
+                       zend_class_entry *ce = zend_hash_find_ptr(&script->class_table, lcname);
+                       if (!ce) {
+                               ce = zend_hash_find_ptr(CG(class_table), lcname);
+                               if (!ce || ce->type != ZEND_INTERNAL_CLASS) {
+                                       continue;
+                               }
+                       }
+
+                       if ((pi = add_pi(arena, op_array, dfg, ssa, j, bt, var))) {
+                               pi_type_mask(pi, MAY_BE_OBJECT);
+                               pi->constraint.type.ce = ce;
+                       }
                }
        }
 }
@@ -806,7 +824,7 @@ static int zend_ssa_rename(const zend_op_array *op_array, uint32_t build_flags,
 }
 /* }}} */
 
-int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags) /* {{{ */
+int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags) /* {{{ */
 {
        zend_basic_block *blocks = ssa->cfg.blocks;
        zend_ssa_block *ssa_blocks;
@@ -854,7 +872,7 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b
 
        /* Place e-SSA pis. This will add additional "def" points, so it must
         * happen before def propagation. */
-       place_essa_pis(arena, op_array, build_flags, ssa, &dfg);
+       place_essa_pis(arena, script, op_array, build_flags, ssa, &dfg);
 
        /* SSA construction, Step 1: Propagate "def" sets in merge points */
        do {
index 02b1183930d679e1961da04dd3943ac8bb6a495c..653a61fc101f813163e699e638d4aee032f48d5c 100644 (file)
@@ -19,6 +19,7 @@
 #ifndef ZEND_SSA_H
 #define ZEND_SSA_H
 
+#include "zend_optimizer.h"
 #include "zend_cfg.h"
 
 typedef struct _zend_ssa_range {
@@ -48,7 +49,8 @@ typedef struct _zend_ssa_range_constraint {
 } zend_ssa_range_constraint;
 
 typedef struct _zend_ssa_type_constraint {
-       uint32_t               type_mask;       /* If -1 this is a range constraint */
+       uint32_t               type_mask;   /* Type mask to intersect with */
+       zend_class_entry      *ce;          /* Class entry for instanceof constraints */
 } zend_ssa_type_constraint;
 
 typedef union _zend_ssa_pi_constraint {
@@ -125,7 +127,7 @@ typedef struct _zend_ssa {
 
 BEGIN_EXTERN_C()
 
-int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags);
+int zend_build_ssa(zend_arena **arena, const zend_script *script, const zend_op_array *op_array, uint32_t build_flags, zend_ssa *ssa, uint32_t *func_flags);
 int zend_ssa_compute_use_def_chains(zend_arena **arena, const zend_op_array *op_array, zend_ssa *ssa);
 int zend_ssa_unlink_use_chain(zend_ssa *ssa, int op, int var);