From: Nikita Popov Date: Tue, 7 Jun 2016 19:52:47 +0000 (+0200) Subject: Add support for "instanceof" pi nodes X-Git-Tag: php-7.1.0alpha3~42^2~15^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=046889518d1e25a6aff858b28fddf05246bfd99f;p=php Add support for "instanceof" pi nodes --- diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 1b3de7e2b6..f89094edec 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -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; } diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 17f5437c95..a2eeb886ee 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -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) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 865fb9c338..d9e1d7f4f2 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -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; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 9e585f4536..6f1fff961c 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -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 { diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h index 02b1183930..653a61fc10 100644 --- a/ext/opcache/Optimizer/zend_ssa.h +++ b/ext/opcache/Optimizer/zend_ssa.h @@ -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);