com php-src: Add support for "instanceof" pi nodes: ext/opcache/Optimizer/dfa_pass.c ext/opcache/Optimizer/ze nd_dump.c
ext/opcache/Optimizer/zend_inference.c ex t/opcache/Optimizer/zend_ssa.c ext/opcache/Optimizer/zend _ssa.h
| From: | Nikita Popov | Date: | Mon, 13 Jun 2016 17:03:59 +0000 |
| Subject: | com php-src: Add support for "instanceof" pi nodes: ext/opcache/Optimizer/dfa_pass.c ext/opcache/Optimizer/ze nd_dump.c ext/opcache/Optimizer/zend_inference.c ex t/opcache/Optimizer/zend_ssa.c ext/opcache/Optimizer/zend _ssa.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-92372@lists.php.net to get a copy of this message | ||
Commit: 046889518d1e25a6aff858b28fddf05246bfd99f
Author: Nikita Popov <nikic@php.net> Tue, 7 Jun 2016 21:52:47 +0200
Parents: 9877d8f019cc0c1070fc963419029f4faf00b34a
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=046889518d1e25a6aff858b28fddf05246bfd99f
Log:
Add support for "instanceof" pi nodes
Changed paths:
M ext/opcache/Optimizer/dfa_pass.c
M ext/opcache/Optimizer/zend_dump.c
M ext/opcache/Optimizer/zend_inference.c
M ext/opcache/Optimizer/zend_ssa.c
M ext/opcache/Optimizer/zend_ssa.h
Diff:
diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c
index 1b3de7e..f89094e 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 17f5437..a2eeb88 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 865fb9c..d9e1d7f 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 9e585f4..6f1fff9 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 02b1183..653a61f 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);