Commit:    cf102333a2d150d029ddea8fb6bf4939d075ee91
Author:    Dmitry Stogov <dmi...@zend.com>         Mon, 25 Feb 2013 14:18:07 
+0400
Parents:   ce69b869279d11e176ad19f361bf1dccfcdad5af
Branches:  PHP-5.5 master

Link:       
http://git.php.net/?p=php-src.git;a=commitdiff;h=cf102333a2d150d029ddea8fb6bf4939d075ee91

Log:
op_array->brk_count_array has to be kept even if op_array doesn't have 
BRK/CONT/GOTO opcodes.
It might be used to unlock "loop" or "switch" variable in case of exception.

Changed paths:
  M  Optimizer/block_pass.c
  M  Optimizer/zend_optimizer_internal.h

diff --git a/Optimizer/block_pass.c b/Optimizer/block_pass.c
index acd149e..7c37da4 100644
--- a/Optimizer/block_pass.c
+++ b/Optimizer/block_pass.c
@@ -80,30 +80,18 @@ static inline void print_block(zend_code_block *block, 
zend_op *opcodes, char *t
 /* find code blocks in op_array
    code block is a set of opcodes with single flow of control, i.e. without 
jmps,
    branches, etc. */
-static zend_code_block *find_code_blocks(zend_op_array *op_array)
+static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg)
 {
        zend_op *opline;
        zend_op *end = op_array->opcodes + op_array->last;
-       zend_code_block *blocks = ecalloc(op_array->last + 2, 
sizeof(zend_code_block));
-       zend_code_block *cur_block;
+       zend_code_block *blocks, *cur_block;
        zend_uint opno = 0;
 
+       memset(cfg, 0, sizeof(zend_cfg));
+       blocks = cfg->blocks = ecalloc(op_array->last + 2, 
sizeof(zend_code_block));
        opline = op_array->opcodes;
        blocks[0].start_opline = opline;
        blocks[0].start_opline_no = 0;
-       /* first find block start points */
-       if (op_array->last_try_catch) {
-               int i = 0;
-               blocks->try = ecalloc(op_array->last_try_catch, 
sizeof(zend_code_block *));
-               blocks->catch = ecalloc(op_array->last_try_catch, 
sizeof(zend_code_block *));
-               for (; i< op_array->last_try_catch; i++) {
-                       blocks->try[i] = 
&blocks[op_array->try_catch_array[i].try_op];
-                       blocks->catch[i] = 
&blocks[op_array->try_catch_array[i].catch_op];
-                       START_BLOCK_OP(op_array->try_catch_array[i].try_op);
-                       START_BLOCK_OP(op_array->try_catch_array[i].catch_op);
-                       blocks[op_array->try_catch_array[i].try_op].is_try = 1;
-               }
-       }
        while (opline < end) {
                switch((unsigned)opline->opcode) {
                        case ZEND_BRK:
@@ -114,12 +102,8 @@ static zend_code_block *find_code_blocks(zend_op_array 
*op_array)
                                /* would not optimize non-optimized BRK/CONTs - 
we cannot
                                 really know where it jumps, so these 
optimizations are
                                too dangerous */
-                               if (op_array->last_try_catch) {
-                                       efree(blocks->try);
-                                       efree(blocks->catch);
-                               }
                                efree(blocks);
-                               return NULL;
+                               return 0;
 #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
                        case ZEND_FAST_CALL:
                                START_BLOCK_OP(ZEND_OP1(opline).opline_num);
@@ -170,6 +154,71 @@ static zend_code_block *find_code_blocks(zend_op_array 
*op_array)
                opline++;
        }
 
+       /* first find block start points */
+       if (op_array->last_try_catch) {
+               int i;
+               cfg->try = ecalloc(op_array->last_try_catch, 
sizeof(zend_code_block *));
+               cfg->catch = ecalloc(op_array->last_try_catch, 
sizeof(zend_code_block *));
+               for (i = 0; i< op_array->last_try_catch; i++) {
+                       cfg->try[i] = 
&blocks[op_array->try_catch_array[i].try_op];
+                       cfg->catch[i] = 
&blocks[op_array->try_catch_array[i].catch_op];
+                       START_BLOCK_OP(op_array->try_catch_array[i].try_op);
+                       START_BLOCK_OP(op_array->try_catch_array[i].catch_op);
+                       blocks[op_array->try_catch_array[i].try_op].protected = 
1;
+               }
+       }
+       /* Currentrly, we don't optimize op_arrays with BRK/CONT/GOTO opcodes,
+        * but, we have to keep brk_cont_array to avoid memory leaks during
+        * exception handling */
+       if (op_array->last_brk_cont) {
+               int i, j;
+               cfg->loop_start = ecalloc(op_array->last_brk_cont, 
sizeof(zend_code_block *));
+               cfg->loop_cont  = ecalloc(op_array->last_brk_cont, 
sizeof(zend_code_block *));
+               cfg->loop_brk   = ecalloc(op_array->last_brk_cont, 
sizeof(zend_code_block *));
+               j = 0;
+               for (i = 0; i< op_array->last_brk_cont; i++) {
+                       if (op_array->brk_cont_array[i].start >= 0) {
+                               int parent = op_array->brk_cont_array[i].parent;
+
+                               while (parent >= 0 && 
op_array->brk_cont_array[parent].start < 0) {
+                                       parent = 
op_array->brk_cont_array[parent].parent;
+                               }
+                               op_array->brk_cont_array[i].parent = parent;
+                               j++;
+                       }
+               }
+               if (j) {
+                       j = 0;
+                       for (i = 0; i< op_array->last_brk_cont; i++) {
+                               if (op_array->brk_cont_array[i].start >= 0) {
+                                       if (i != j) {
+                                               op_array->brk_cont_array[j] = 
op_array->brk_cont_array[i];
+                                       }
+                                       cfg->loop_start[j] = 
&blocks[op_array->brk_cont_array[j].start];
+                                       cfg->loop_cont[j]  = 
&blocks[op_array->brk_cont_array[j].cont];
+                                       cfg->loop_brk[j]   = 
&blocks[op_array->brk_cont_array[j].brk];
+                                       
START_BLOCK_OP(op_array->brk_cont_array[j].start);
+                                       
START_BLOCK_OP(op_array->brk_cont_array[j].cont);
+                                       
START_BLOCK_OP(op_array->brk_cont_array[j].brk);
+                                       
blocks[op_array->brk_cont_array[j].start].protected = 1;
+                                       
blocks[op_array->brk_cont_array[j].brk].protected = 1;
+                                       j++;
+                               }
+                       }
+                       op_array->last_brk_cont = j;
+               } else {
+                       efree(cfg->loop_start);
+                       efree(cfg->loop_cont);
+                       efree(cfg->loop_brk);
+                       efree(op_array->brk_cont_array);
+                       cfg->loop_start = NULL;
+                       cfg->loop_cont = NULL;
+                       cfg->loop_brk = NULL;
+                       op_array->brk_cont_array = NULL;
+                       op_array->last_brk_cont = 0;
+               }
+       }
+
        /* Build CFG (Control Flow Graph) */
        cur_block = blocks;
        for (opno = 1; opno < op_array->last; opno++) {
@@ -232,14 +281,7 @@ static zend_code_block *find_code_blocks(zend_op_array 
*op_array)
        cur_block->next = &blocks[op_array->last+1];
        print_block(cur_block, op_array->opcodes, "");
 
-       /* The op_array doesn't have BRK, CONT, GOTO opcodes anyway */
-       if (op_array->brk_cont_array) {
-               efree(op_array->brk_cont_array);
-       }
-       op_array->brk_cont_array = NULL;
-       op_array->last_brk_cont = 0;
-
-       return blocks;
+       return 1;
 }
 
 /* CFG back references management */
@@ -409,8 +451,9 @@ static void zend_access_path(zend_code_block *block)
 }
 
 /* Traverse CFG, mark reachable basic blocks and build back references */
-static void zend_rebuild_access_path(zend_code_block *blocks, zend_op_array 
*op_array, int find_start)
+static void zend_rebuild_access_path(zend_cfg *cfg, zend_op_array *op_array, 
int find_start)
 {
+       zend_code_block *blocks = cfg->blocks;
        zend_code_block *start = find_start? NULL : blocks;
        zend_code_block *b;
 
@@ -439,8 +482,8 @@ static void zend_rebuild_access_path(zend_code_block 
*blocks, zend_op_array *op_
        if (op_array->last_try_catch) {
                int i;
                for (i=0; i< op_array->last_try_catch; i++) {
-                       if (!blocks->catch[i]->access) {
-                               zend_access_path(blocks->catch[i]);
+                       if (!cfg->catch[i]->access) {
+                               zend_access_path(cfg->catch[i]);
                        }
                }
        }
@@ -1085,8 +1128,9 @@ static void zend_optimize_block(zend_code_block *block, 
zend_op_array *op_array,
 }
 
 /* Rebuild plain (optimized) op_array from CFG */
-static void assemble_code_blocks(zend_code_block *blocks, zend_op_array 
*op_array)
+static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array)
 {
+       zend_code_block *blocks = cfg->blocks;
        zend_op *new_opcodes = emalloc(op_array->last*sizeof(zend_op));
        zend_op *opline = new_opcodes;
        zend_code_block *cur_block = blocks;
@@ -1146,12 +1190,25 @@ static void assemble_code_blocks(zend_code_block 
*blocks, zend_op_array *op_arra
        /* adjust exception jump targets */
        if (op_array->last_try_catch) {
                int i;
-               for (i=0; i< op_array->last_try_catch; i++) {
-                       op_array->try_catch_array[i].try_op = 
blocks->try[i]->start_opline - new_opcodes;
-                       op_array->try_catch_array[i].catch_op = 
blocks->catch[i]->start_opline - new_opcodes;
+               for (i = 0; i< op_array->last_try_catch; i++) {
+                       op_array->try_catch_array[i].try_op = 
cfg->try[i]->start_opline - new_opcodes;
+                       op_array->try_catch_array[i].catch_op = 
cfg->catch[i]->start_opline - new_opcodes;
                }
-               efree(blocks->try);
-               efree(blocks->catch);
+               efree(cfg->try);
+               efree(cfg->catch);
+       }
+
+       /* adjust loop jump targets */
+       if (op_array->last_brk_cont) {
+               int i;
+               for (i = 0; i< op_array->last_brk_cont; i++) {
+                       op_array->brk_cont_array[i].start = 
cfg->loop_start[i]->start_opline - new_opcodes;
+                       op_array->brk_cont_array[i].cont = 
cfg->loop_cont[i]->start_opline - new_opcodes;
+                       op_array->brk_cont_array[i].brk = 
cfg->loop_brk[i]->start_opline - new_opcodes;
+               }
+               efree(cfg->loop_start);
+               efree(cfg->loop_cont);
+               efree(cfg->loop_brk);
        }
 
     /* adjust jump targets */
@@ -1225,7 +1282,7 @@ static void zend_jmp_optimization(zend_code_block *block, 
zend_op_array *op_arra
                                if (((target->opcode == ZEND_JMP &&
                                        block->op1_to != block->op1_to->op1_to) 
||
                                        target->opcode == ZEND_JMPZNZ) &&
-                                       !block->op1_to->is_try) {
+                                       !block->op1_to->protected) {
                                        /* JMP L, L: JMP L1 -> JMP L1 */
                                        /* JMP L, L: JMPZNZ L1,L2 -> JMPZNZ 
L1,L2 */
                                        *last_op = *target;
@@ -1371,7 +1428,7 @@ next_target:
                                   same_type == ZEND_OP1_TYPE(target) &&
                                   same_var == VAR_NUM_EX(target->op1) &&
                                   target_block->follow_to &&
-                                  !target_block->is_try
+                                  !target_block->protected
                                   ) {
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->follow_to;
@@ -1381,7 +1438,7 @@ next_target:
                                                same_type == 
ZEND_OP1_TYPE(target) &&
                                                same_var == 
VAR_NUM_EX(target->op1) &&
                                                        target_block->follow_to 
&&
-                                                       !target_block->is_try) {
+                                                       
!target_block->protected) {
                                        /* JMPZ(X, L), L: X = JMPNZ_EX(X, L2) 
-> JMPZ(X, L+1) */
                                        last_op->opcode += 3;
                                        last_op->result = target->result;
@@ -1393,14 +1450,14 @@ next_target:
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   same_type == 
ZEND_OP1_TYPE(target) &&
                                                   same_var == 
VAR_NUM_EX(target->op1) &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* JMPZ(X, L), L: JMPZ(X, L2) -> 
JMPZ(X, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op2_to;
                                        ADD_SOURCE(block, block->op2_to);
                                } else if (target_block->op1_to &&
                                                        target->opcode == 
ZEND_JMP &&
-                                                       !target_block->is_try) {
+                                                       
!target_block->protected) {
                                        /* JMPZ(X, L), L: JMP(L2) -> JMPZ(X, 
L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op1_to;
@@ -1411,7 +1468,7 @@ next_target:
                                                        (ZEND_OP1_TYPE(target) 
& (IS_TMP_VAR|IS_CV)) &&
                                                same_type == 
ZEND_OP1_TYPE(target) &&
                                                same_var == 
VAR_NUM_EX(target->op1) &&
-                                                       !target_block->is_try) {
+                                                       
!target_block->protected) {
                                        /* JMPZ(X, L), L: JMPZNZ(X, L2, L3) -> 
JMPZ(X, L2) */
                                        del_source(block, block->op2_to);
                                        if (last_op->opcode == ZEND_JMPZ) {
@@ -1447,7 +1504,7 @@ next_target:
                                /* JMPZ(X,L1), JMP(L2) -> JMPZNZ(X,L1,L2) */
                                if (target->opcode == ZEND_JMP &&
                                        block->follow_to->op1_to &&
-                                       !block->follow_to->is_try) {
+                                       !block->follow_to->protected) {
                                        del_source(block, block->follow_to);
                                        if (last_op->opcode == ZEND_JMPZ) {
                                                block->ext_to = 
block->follow_to->op1_to;
@@ -1517,7 +1574,7 @@ next_target_ex:
                                                   target->opcode == 
last_op->opcode-3 &&
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   
(same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L1), L1: JMPZ({X|T}, 
L2) -> T = JMPZ_EX(X, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op2_to;
@@ -1526,7 +1583,7 @@ next_target_ex:
                                                   target->opcode == 
INV_EX_COND(last_op->opcode) &&
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   
(same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L1), L1: 
JMPNZ({X|T1}, L2) -> T = JMPZ_EX(X, L1+1) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->follow_to;
@@ -1536,7 +1593,7 @@ next_target_ex:
                                               (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   
(same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
                                                   
(same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L1), L1: T = 
JMPNZ_EX(T, L2) -> T = JMPZ_EX(X, L1+1) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->follow_to;
@@ -1546,14 +1603,14 @@ next_target_ex:
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   
(same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
                                                   
(same_t[VAR_NUM_EX(target->result)] & ZEND_RESULT_TYPE(target)) != 0 &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L1), L1: T = 
JMPZ({X|T}, L2) -> T = JMPZ_EX(X, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op2_to;
                                        ADD_SOURCE(block, block->op2_to);
                                } else if (target_block->op1_to &&
                                                   target->opcode == ZEND_JMP &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L), L: JMP(L2) -> T = 
JMPZ(X, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op1_to;
@@ -1563,7 +1620,7 @@ next_target_ex:
                                                   target->opcode == 
ZEND_JMPZNZ &&
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   
(same_t[VAR_NUM_EX(target->op1)] & ZEND_OP1_TYPE(target)) != 0 &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                        /* T = JMPZ_EX(X, L), L: JMPZNZ({X|T}, 
L2, L3) -> T = JMPZ_EX(X, L2) */
                                        del_source(block, block->op2_to);
                                        if (last_op->opcode == ZEND_JMPZ_EX) {
@@ -1663,7 +1720,7 @@ next_target_znz:
                                                   (ZEND_OP1_TYPE(target) & 
(IS_TMP_VAR|IS_CV)) &&
                                                   same_type == 
ZEND_OP1_TYPE(target) &&
                                                   same_var == 
VAR_NUM_EX(target->op1) &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                                    /* JMPZNZ(X, L1, L2), L1: JMPZ(X, L3) -> 
JMPZNZ(X, L3, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op2_to;
@@ -1673,14 +1730,14 @@ next_target_znz:
                                                   same_type == 
ZEND_OP1_TYPE(target) &&
                                                   same_var == 
VAR_NUM_EX(target->op1) &&
                                                   target_block->follow_to &&
-                                                  !target_block->is_try) {
+                                                  !target_block->protected) {
                     /* JMPZNZ(X, L1, L2), L1: X = JMPNZ(X, L3) -> JMPZNZ(X, 
L1+1, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->follow_to;
                                        ADD_SOURCE(block, block->op2_to);
                                } else if (target_block->op1_to &&
                                               target->opcode == ZEND_JMP &&
-                                              !target_block->is_try) {
+                                              !target_block->protected) {
                     /* JMPZNZ(X, L1, L2), L1: JMP(L3) -> JMPZNZ(X, L3, L2) */
                                        del_source(block, block->op2_to);
                                        block->op2_to = target_block->op1_to;
@@ -1882,7 +1939,8 @@ static void zend_t_usage(zend_code_block *block, 
zend_op_array *op_array, char *
 
 static void zend_block_optimization(zend_op_array *op_array TSRMLS_DC)
 {
-       zend_code_block *blocks, *cur_block;
+       zend_cfg cfg;
+       zend_code_block *cur_block;
        int pass;
        char *usage;
 
@@ -1898,21 +1956,20 @@ static void zend_block_optimization(zend_op_array 
*op_array TSRMLS_DC)
 #endif
 
     /* Build CFG */
-       blocks = find_code_blocks(op_array);
-       if (!blocks) {
+       if (!find_code_blocks(op_array, &cfg)) {
                return;
        }
 
-       zend_rebuild_access_path(blocks, op_array, 0);
+       zend_rebuild_access_path(&cfg, op_array, 0);
        /* full rebuild here to produce correct sources! */
        usage = emalloc(op_array->T);
        for (pass = 0; pass < PASSES; pass++) {
                /* Compute data dependencies */
                memset(usage, 0, op_array->T);
-               zend_t_usage(blocks, op_array, usage);
+               zend_t_usage(cfg.blocks, op_array, usage);
 
                /* optimize each basic block separately */
-               for (cur_block = blocks; cur_block; cur_block = 
cur_block->next) {
+               for (cur_block = cfg.blocks; cur_block; cur_block = 
cur_block->next) {
                        if (!cur_block->access) {
                                continue;
                        }
@@ -1920,22 +1977,22 @@ static void zend_block_optimization(zend_op_array 
*op_array TSRMLS_DC)
                }
 
                /* Jump optimization for each block */
-               for (cur_block = blocks; cur_block; cur_block = 
cur_block->next) {
+               for (cur_block = cfg.blocks; cur_block; cur_block = 
cur_block->next) {
                        if (!cur_block->access) {
                                continue;
                        }
-                       zend_jmp_optimization(cur_block, op_array, blocks);
+                       zend_jmp_optimization(cur_block, op_array, cfg.blocks);
                }
 
                /* Eliminate unreachable basic blocks */
-               zend_rebuild_access_path(blocks, op_array, 1);
+               zend_rebuild_access_path(&cfg, op_array, 1);
        }
 
-       assemble_code_blocks(blocks, op_array);
+       assemble_code_blocks(&cfg, op_array);
        efree(usage);
 
        /* Destroy CFG */
-       for (cur_block = blocks; cur_block; cur_block = cur_block->next) {
+       for (cur_block = cfg.blocks; cur_block; cur_block = cur_block->next) {
                zend_block_source *cs = cur_block->sources;
                while (cs) {
                        zend_block_source *n = cs->next;
@@ -1943,5 +2000,5 @@ static void zend_block_optimization(zend_op_array 
*op_array TSRMLS_DC)
                        cs = n;
                }
        }
-       efree(blocks);
+       efree(cfg.blocks);
 }
diff --git a/Optimizer/zend_optimizer_internal.h 
b/Optimizer/zend_optimizer_internal.h
index 198ec20..6f85364 100644
--- a/Optimizer/zend_optimizer_internal.h
+++ b/Optimizer/zend_optimizer_internal.h
@@ -63,10 +63,17 @@ struct _zend_code_block {
        zend_code_block    *follow_to;
        zend_code_block    *next;
        zend_block_source  *sources;
+       zend_bool           protected; /* don't merge this block with others */
+};
+
+typedef struct _zend_cfg {
+       zend_code_block    *blocks;
        zend_code_block   **try;
        zend_code_block   **catch;
-       zend_bool           is_try;
-};
+       zend_code_block   **loop_start;
+       zend_code_block   **loop_cont;
+       zend_code_block   **loop_brk;
+} zend_cfg;
 
 struct _zend_block_source {
        zend_code_block    *from;
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to