]> granicus.if.org Git - php/commitdiff
Avoid live range references in opcodes
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 16 Feb 2018 20:25:49 +0000 (21:25 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 16 Feb 2018 20:30:48 +0000 (21:30 +0100)
Don't store the live range of the freed variable for FREE_ON_RETURN
frees, instead look it up at runtime. As this is an extremely
unlikely codepath (in particular, it requires a loop variable with
a throwing destructor), saving the runtime lookup of the live range
is not worth the extra complexity this adds everywhere else.

Zend/zend_compile.c
Zend/zend_execute.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
Zend/zend_vm_gen.php
Zend/zend_vm_opcodes.c
Zend/zend_vm_opcodes.h
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/zend_dump.c
ext/opcache/Optimizer/zend_optimizer.c
sapi/phpdbg/phpdbg_opcode.c

index 9c8fe3f4d7e466afe6f0a1037f4ae46b40390c82..1190cef1b491dcf1f80402fd5849e0a20651c4bc 100644 (file)
@@ -629,7 +629,6 @@ static uint32_t zend_start_live_range_ex(zend_op_array *op_array, uint32_t start
                if (!zend_stack_is_empty(&CG(loop_var_stack))) {
                        zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack));
                        zend_loop_var *base = zend_stack_base(&CG(loop_var_stack));
-                       int check_opcodes = 0;
 
                        for (; loop_var >= base; loop_var--) {
                                if (loop_var->opcode == ZEND_RETURN) {
@@ -639,28 +638,11 @@ static uint32_t zend_start_live_range_ex(zend_op_array *op_array, uint32_t start
                                   loop_var->opcode == ZEND_FE_FREE) {
                                        if (loop_var->u.live_range_offset >= n) {
                                                loop_var->u.live_range_offset++;
-                                               check_opcodes = 1;
                                        } else {
                                                break;
                                        }
                                }
                        }
-
-                       /* update previously generated FREE/FE_FREE opcodes */
-                       if (check_opcodes) {
-                               zend_op *opline = op_array->opcodes + op_array->live_range[n+1].start;
-                               zend_op *end = op_array->opcodes + op_array->last;
-
-                               while (opline < end) {
-                                       if ((opline->opcode == ZEND_FREE ||
-                                            opline->opcode == ZEND_FE_FREE) &&
-                                           (opline->extended_value & ZEND_FREE_ON_RETURN) &&
-                                           opline->op2.num >= n) {
-                                               opline->op2.num++;
-                                       }
-                                       opline++;
-                               }
-                       }
                }
                return n;
        }
@@ -4463,7 +4445,6 @@ static int zend_handle_loops_and_finally_ex(zend_long depth, znode *return_value
                        opline->op1_type = loop_var->var_type;
                        opline->op1.var = loop_var->var_num;
                        SET_UNUSED(opline->op2);
-                       opline->op2.num = loop_var->u.live_range_offset;
                        opline->extended_value = ZEND_FREE_ON_RETURN;
                        depth--;
            }
index 80217b72f31ce6372a60f3c6b0952ba0cf66d012..63073f59577f31c27b1334b3e8255738fd79d4a6 100644 (file)
@@ -2576,6 +2576,20 @@ static void cleanup_unfinished_calls(zend_execute_data *execute_data, uint32_t o
 }
 /* }}} */
 
+static const zend_live_range *find_live_range(const zend_op_array *op_array, uint32_t op_num, uint32_t var_num) /* {{{ */
+{
+       int i;
+       for (i = 0; i < op_array->last_live_range; i++) {
+               const zend_live_range *range = &op_array->live_range[i];
+               if (op_num >= range->start && op_num < range->end
+                               && var_num == (range->var & ~ZEND_LIVE_MASK)) {
+                       return range;
+               }
+       }
+       return NULL;
+}
+/* }}} */
+
 static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */
 {
        int i;
index c1054505639e9666b5aabc3430674d63dbb05e0b..a838dd0668eab0528060c1478f39c3626ad4bbb9 100644 (file)
@@ -2730,7 +2730,7 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, JMP_ADDR)
        ZEND_VM_JMP(opline);
 }
 
-ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LIVE_RANGE)
+ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY)
 {
        USE_OPLINE
 
@@ -2739,7 +2739,7 @@ ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, LIVE_RANGE)
        ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
 }
 
-ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, LIVE_RANGE)
+ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY)
 {
        zval *var;
        USE_OPLINE
@@ -7129,16 +7129,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
        uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
        int i, current_try_catch_offset = -1;
 
-       {
-               const zend_op *exc_opline = EG(opline_before_exception);
-               if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
-                       && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
-                       /* exceptions thrown because of loop var destruction on return/break/...
-                        * are logically thrown at the end of the foreach loop, so adjust the
-                        * throw_op_num.
-                        */
-                       throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
-               }
+       if ((throw_op->opcode == ZEND_FREE || throw_op->opcode == ZEND_FE_FREE)
+               && throw_op->extended_value & ZEND_FREE_ON_RETURN) {
+               /* exceptions thrown because of loop var destruction on return/break/...
+                * are logically thrown at the end of the foreach loop, so adjust the
+                * throw_op_num.
+                */
+               const zend_live_range *range = find_live_range(
+                       &EX(func)->op_array, throw_op_num, throw_op->op1.var);
+               throw_op_num = range->end;
        }
 
        /* Find the innermost try/catch/finally the exception was thrown in */
index 7b2a15d28ac33c4f440aeb5143b9615e66d5c98d..1f6ab1b412ade7ee7d90dbc34ebc5bcdcc596081 100644 (file)
@@ -1726,16 +1726,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
        uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes;
        int i, current_try_catch_offset = -1;
 
-       {
-               const zend_op *exc_opline = EG(opline_before_exception);
-               if ((exc_opline->opcode == ZEND_FREE || exc_opline->opcode == ZEND_FE_FREE)
-                       && exc_opline->extended_value & ZEND_FREE_ON_RETURN) {
-                       /* exceptions thrown because of loop var destruction on return/break/...
-                        * are logically thrown at the end of the foreach loop, so adjust the
-                        * throw_op_num.
-                        */
-                       throw_op_num = EX(func)->op_array.live_range[exc_opline->op2.num].end;
-               }
+       if ((throw_op->opcode == ZEND_FREE || throw_op->opcode == ZEND_FE_FREE)
+               && throw_op->extended_value & ZEND_FREE_ON_RETURN) {
+               /* exceptions thrown because of loop var destruction on return/break/...
+                * are logically thrown at the end of the foreach loop, so adjust the
+                * throw_op_num.
+                */
+               const zend_live_range *range = find_live_range(
+                       &EX(func)->op_array, throw_op_num, throw_op->op1.var);
+               throw_op_num = range->end;
        }
 
        /* Find the innermost try/catch/finally the exception was thrown in */
index 37a660127f22f1ca20e3f8afbc5a78d00366ceb4..f9b2280d3135c7768d2119b1335d3bf0bdcd2fc4 100644 (file)
@@ -64,7 +64,7 @@ $vm_op_flags = array(
        "ZEND_VM_OP_NUM"          => 0x10,
        "ZEND_VM_OP_JMP_ADDR"     => 0x20,
        "ZEND_VM_OP_TRY_CATCH"    => 0x30,
-       "ZEND_VM_OP_LIVE_RANGE"   => 0x40,
+       // unused 0x40
        "ZEND_VM_OP_THIS"         => 0x50,
        "ZEND_VM_OP_NEXT"         => 0x60,
        "ZEND_VM_OP_CLASS_FETCH"  => 0x70,
@@ -110,7 +110,6 @@ $vm_op_decode = array(
        "NUM"                  => ZEND_VM_OP_NUM,
        "JMP_ADDR"             => ZEND_VM_OP_JMP_ADDR,
        "TRY_CATCH"            => ZEND_VM_OP_TRY_CATCH,
-       "LIVE_RANGE"           => ZEND_VM_OP_LIVE_RANGE,
        "THIS"                 => ZEND_VM_OP_THIS,
        "NEXT"                 => ZEND_VM_OP_NEXT,
        "CLASS_FETCH"          => ZEND_VM_OP_CLASS_FETCH,
index 52b7cb855c869bd34996fee5f6a4a40aee8c9562..f37b769da3cfca1f12030b1c4e815f109926727f 100644 (file)
@@ -295,7 +295,7 @@ static uint32_t zend_vm_opcodes_flags[199] = {
        0x00001001,
        0x0100a173,
        0x01040300,
-       0x00004005,
+       0x00000005,
        0x00186703,
        0x00106703,
        0x08000007,
@@ -352,7 +352,7 @@ static uint32_t zend_vm_opcodes_flags[199] = {
        0x0000a103,
        0x00002003,
        0x03000001,
-       0x00004005,
+       0x00000005,
        0x01000700,
        0x00000000,
        0x00000000,
index 6f9b323bb058b0f352b6132dbbe309ddd249584d..b5c0a483d83f897c512ce503dbba347598d14a4c 100644 (file)
@@ -42,7 +42,6 @@
 #define ZEND_VM_OP_NUM           0x00000010
 #define ZEND_VM_OP_JMP_ADDR      0x00000020
 #define ZEND_VM_OP_TRY_CATCH     0x00000030
-#define ZEND_VM_OP_LIVE_RANGE    0x00000040
 #define ZEND_VM_OP_THIS          0x00000050
 #define ZEND_VM_OP_NEXT          0x00000060
 #define ZEND_VM_OP_CLASS_FETCH   0x00000070
index 97e44fe0b2546304c38a4c370e032c91f906fe19..b402cce27602f314f4a09180fce4baf41ccb9d89 100644 (file)
@@ -347,10 +347,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
                                            src->opcode != ZEND_FETCH_DIM_R &&
                                            src->opcode != ZEND_FETCH_OBJ_R &&
                                            src->opcode != ZEND_NEW) {
-                                               if (opline->extended_value & ZEND_FREE_ON_RETURN) {
-                                                       /* mark as removed (empty live range) */
-                                                       op_array->live_range[opline->op2.num].var = (uint32_t)-1;
-                                               }
                                                src->result_type = IS_UNUSED;
                                                MAKE_NOP(opline);
                                        }
@@ -1040,10 +1036,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
        /* adjust loop jump targets & remove unused live range entries */
        if (op_array->last_live_range) {
                int i, j;
-               uint32_t *map;
-               ALLOCA_FLAG(use_heap);
-
-               map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_live_range, use_heap);
 
                for (i = 0, j = 0; i < op_array->last_live_range; i++) {
                        if (op_array->live_range[i].var == (uint32_t)-1) {
@@ -1062,7 +1054,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
                                }
                                op_array->live_range[i].start = start_op;
                                op_array->live_range[i].end = end_op;
-                               map[i] = j;
                                if (i != j) {
                                        op_array->live_range[j]  = op_array->live_range[i];
                                }
@@ -1071,23 +1062,12 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
                }
 
                if (i != j) {
-                       if ((op_array->last_live_range = j)) {
-                               zend_op *opline = new_opcodes;
-                               zend_op *end = opline + len;
-                               while (opline != end) {
-                                       if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) &&
-                                                       opline->extended_value == ZEND_FREE_ON_RETURN) {
-                                               ZEND_ASSERT(opline->op2.num < (uint32_t) i);
-                                               opline->op2.num = map[opline->op2.num];
-                                       }
-                                       opline++;
-                               }
-                       } else {
+                       op_array->last_live_range = j;
+                       if (j == 0) {
                                efree(op_array->live_range);
                                op_array->live_range = NULL;
                        }
                }
-               free_alloca(map, use_heap);
        }
 
        /* adjust early binding list */
index 7fb55355fd74b370f67d118e5531a05d6a390ffe..e4516b59ccb6e0a3dc863c55b216cef5ce33f779 100644 (file)
@@ -118,10 +118,6 @@ static void zend_dump_unused_op(const zend_op *opline, znode_op op, uint32_t fla
                if (op.num != (uint32_t)-1) {
                        fprintf(stderr, " try-catch(%u)", op.num);
                }
-       } else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
-               if (opline->extended_value & ZEND_FREE_ON_RETURN) {
-                       fprintf(stderr, " live-range(%u)", op.num);
-               }
        } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
                fprintf(stderr, " THIS");
        } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {
index 07860f39987316ec441906d2195110ce4b97bac6..ffc04854e27ef31bddc849771ff7825b0b624936 100644 (file)
@@ -566,14 +566,9 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var)
        if (op_array->last_live_range) {
                int i = 0;
                int j = 0;
-               uint32_t *map;
-               ALLOCA_FLAG(use_heap);
-
-               map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_live_range, use_heap);
 
                do {
                        if ((op_array->live_range[i].var & ~ZEND_LIVE_MASK) != var) {
-                               map[i] = j;
                                if (i != j) {
                                        op_array->live_range[j] = op_array->live_range[i];
                                }
@@ -582,23 +577,12 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var)
                        i++;
                } while (i < op_array->last_live_range);
                if (i != j) {
-                       if ((op_array->last_live_range = j)) {
-                               zend_op *opline = op_array->opcodes;
-                               zend_op *end = opline + op_array->last;
-
-                               while (opline != end) {
-                                       if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) &&
-                                                       opline->extended_value == ZEND_FREE_ON_RETURN) {
-                                               opline->op2.num = map[opline->op2.num];
-                                       }
-                                       opline++;
-                               }
-                       } else {
+                       op_array->last_live_range = j;
+                       if (j == 0) {
                                efree(op_array->live_range);
                                op_array->live_range = NULL;
                        }
                }
-               free_alloca(map, use_heap);
        }
 }
 
index d066674b901b7a9156e7dcabc912f915b0751419..b14a1c23e2c20f718fedb2fec935f624a7296251 100644 (file)
@@ -77,10 +77,6 @@ char *phpdbg_decode_input_op(
                if (op.num != (uint32_t)-1) {
                        spprintf(&result, 0, "try-catch(%" PRIu32 ")", op.num);
                }
-       } else if (ZEND_VM_OP_LIVE_RANGE == (flags & ZEND_VM_OP_MASK)) {
-               if (opline->extended_value & ZEND_FREE_ON_RETURN) {
-                       spprintf(&result, 0, "live-range(%" PRIu32 ")", op.num);
-               }
        } else if (ZEND_VM_OP_THIS == (flags & ZEND_VM_OP_MASK)) {
                result = estrdup("THIS");
        } else if (ZEND_VM_OP_NEXT == (flags & ZEND_VM_OP_MASK)) {