diff options
| -rw-r--r-- | Zend/tests/entry_block_with_predecessors.phpt | 33 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/dfa_pass.c | 3 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_cfg.c | 45 | ||||
| -rw-r--r-- | ext/opcache/Optimizer/zend_cfg.h | 1 | 
4 files changed, 69 insertions, 13 deletions
| diff --git a/Zend/tests/entry_block_with_predecessors.phpt b/Zend/tests/entry_block_with_predecessors.phpt new file mode 100644 index 0000000000..ffc3147f1c --- /dev/null +++ b/Zend/tests/entry_block_with_predecessors.phpt @@ -0,0 +1,33 @@ +--TEST-- +For SSA form the entry block should have no predecessors +--FILE-- +<?php + +function test() { +    while (true) { +        var_dump($a + 1); +        $a = 1; +        if (@$i++) { +            break; +        } +    } +} + +function test2() { +    while (true) { +        $a = 42; +        if (@$i++ > 1) { +            break; +        } +        $a = new stdClass; +    } +} + +test(); +test2(); + +?> +--EXPECTF-- +Notice: Undefined variable: a in %s on line %d +int(1) +int(2) diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index f7cae772fb..3be638eb92 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -43,7 +43,8 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx,      /* Build SSA */  	memset(ssa, 0, sizeof(zend_ssa)); -	if (zend_build_cfg(&ctx->arena, op_array, 0, &ssa->cfg, flags) != SUCCESS) { +	if (zend_build_cfg(&ctx->arena, op_array, +			ZEND_CFG_NO_ENTRY_PREDECESSORS, &ssa->cfg, flags) != SUCCESS) {  		return FAILURE;  	} diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 2bf43fe9c5..9701f58606 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -240,9 +240,22 @@ static void record_successor(zend_basic_block *blocks, int pred, int n, int succ  	blocks[pred].successors[n] = succ;  } +static void initialize_block(zend_basic_block *block) { +	block->flags = 0; +	block->successors[0] = -1; +	block->successors[1] = -1; +	block->predecessors_count = 0; +	block->predecessor_offset = -1; +	block->idom = -1; +	block->loop_header = -1; +	block->level = -1; +	block->children = -1; +	block->next_child = -1; +} +  #define BB_START(i) do { \  		if (!block_map[i]) { blocks_count++;} \ -		block_map[i] = 1; \ +		block_map[i]++; \  	} while (0)  int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t build_flags, zend_cfg *cfg, uint32_t *func_flags) /* {{{ */ @@ -255,6 +268,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b  	int blocks_count = 0;  	zend_basic_block *blocks;  	zval *zv; +	zend_bool extra_entry_block = 0;  	cfg->split_at_live_ranges = (build_flags & ZEND_CFG_SPLIT_AT_LIVE_RANGES) != 0;  	cfg->map = block_map = zend_arena_calloc(arena, op_array->last, sizeof(uint32_t)); @@ -407,6 +421,12 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b  		}  	} +	/* If the entry block has predecessors, we may need to split it */ +	if ((build_flags & ZEND_CFG_NO_ENTRY_PREDECESSORS) +			&& op_array->last > 0 && block_map[0] > 1) { +		extra_entry_block = 1; +	} +  	if (cfg->split_at_live_ranges) {  		for (j = 0; j < op_array->last_live_range; j++) {  			BB_START(op_array->live_range[j].start); @@ -429,6 +449,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b  		}  	} +	blocks_count += extra_entry_block;  	cfg->blocks_count = blocks_count;  	/* Build CFG, Step 2: Build Array of Basic Blocks */ @@ -437,23 +458,23 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b  		return FAILURE;  	} -	for (i = 0, blocks_count = -1; i < op_array->last; i++) { +	blocks_count = -1; + +	if (extra_entry_block) { +		initialize_block(&blocks[0]); +		blocks[0].start = 0; +		blocks[0].len = 0; +		blocks_count++; +	} + +	for (i = 0; i < op_array->last; i++) {  		if (block_map[i]) {  			if (blocks_count >= 0) {  				blocks[blocks_count].len = i - blocks[blocks_count].start;  			}  			blocks_count++; -			blocks[blocks_count].flags = 0; +			initialize_block(&blocks[blocks_count]);  			blocks[blocks_count].start = i; -			blocks[blocks_count].successors[0] = -1; -			blocks[blocks_count].successors[1] = -1; -			blocks[blocks_count].predecessors_count = 0; -			blocks[blocks_count].predecessor_offset = -1; -			blocks[blocks_count].idom = -1; -			blocks[blocks_count].loop_header = -1; -			blocks[blocks_count].level = -1; -			blocks[blocks_count].children = -1; -			blocks[blocks_count].next_child = -1;  		}  		block_map[i] = blocks_count;  	} diff --git a/ext/opcache/Optimizer/zend_cfg.h b/ext/opcache/Optimizer/zend_cfg.h index 244a2ade97..da908fdbe3 100644 --- a/ext/opcache/Optimizer/zend_cfg.h +++ b/ext/opcache/Optimizer/zend_cfg.h @@ -96,6 +96,7 @@ typedef struct _zend_cfg {  #define ZEND_SSA_DEBUG_PHI_PLACEMENT   (1<<28)  #define ZEND_SSA_RC_INFERENCE          (1<<27)  #define ZEND_CFG_SPLIT_AT_LIVE_RANGES  (1<<26) +#define ZEND_CFG_NO_ENTRY_PREDECESSORS (1<<25)  #define CRT_CONSTANT_EX(op_array, node, rt_constants) \  	((rt_constants) ? \ | 
