root/ext/opcache/Optimizer/optimize_temp_vars_5.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. optimize_temporary_variables

   1 /*
   2    +----------------------------------------------------------------------+
   3    | Zend OPcache                                                         |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1998-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Andi Gutmans <andi@zend.com>                                |
  16    |          Zeev Suraski <zeev@zend.com>                                |
  17    |          Stanislav Malyshev <stas@zend.com>                          |
  18    |          Dmitry Stogov <dmitry@zend.com>                             |
  19    +----------------------------------------------------------------------+
  20 */
  21 
  22 #include "php.h"
  23 #include "Optimizer/zend_optimizer.h"
  24 #include "Optimizer/zend_optimizer_internal.h"
  25 #include "zend_API.h"
  26 #include "zend_constants.h"
  27 #include "zend_execute.h"
  28 #include "zend_vm.h"
  29 #include "zend_bitset.h"
  30 
  31 #define GET_AVAILABLE_T()                                       \
  32         for (i = 0; i < T; i++) {                               \
  33                 if (!zend_bitset_in(taken_T, i)) {      \
  34                         break;                                                  \
  35                 }                                                                       \
  36         }                                                                               \
  37         zend_bitset_incl(taken_T, i);                   \
  38         if (i > max) {                                                  \
  39                 max = i;                                                        \
  40         }
  41 
  42 void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *ctx)
  43 {
  44         int T = op_array->T;
  45         int offset = op_array->last_var;
  46         uint32_t bitset_len;
  47         zend_bitset taken_T;    /* T index in use */
  48         zend_op **start_of_T;   /* opline where T is first used */
  49         zend_bitset valid_T;    /* Is the map_T valid */
  50         int *map_T;                             /* Map's the T to its new index */
  51         zend_op *opline, *end;
  52         int currT;
  53         int i;
  54         int max = -1;
  55         int var_to_free = -1;
  56         void *checkpoint = zend_arena_checkpoint(ctx->arena);
  57 
  58         bitset_len = zend_bitset_len(T);
  59         taken_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
  60         start_of_T = (zend_op **) zend_arena_alloc(&ctx->arena, T * sizeof(zend_op *));
  61         valid_T = (zend_bitset) zend_arena_alloc(&ctx->arena, bitset_len * ZEND_BITSET_ELM_SIZE);
  62         map_T = (int *) zend_arena_alloc(&ctx->arena, T * sizeof(int));
  63 
  64     end = op_array->opcodes;
  65     opline = &op_array->opcodes[op_array->last - 1];
  66 
  67     /* Find T definition points */
  68     while (opline >= end) {
  69         if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
  70                         start_of_T[VAR_NUM(ZEND_RESULT(opline).var) - offset] = opline;
  71                 }
  72                 opline--;
  73         }
  74 
  75         zend_bitset_clear(valid_T, bitset_len);
  76         zend_bitset_clear(taken_T, bitset_len);
  77 
  78     end = op_array->opcodes;
  79     opline = &op_array->opcodes[op_array->last - 1];
  80 
  81     while (opline >= end) {
  82                 if ((ZEND_OP1_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
  83                         currT = VAR_NUM(ZEND_OP1(opline).var) - offset;
  84                         if (opline->opcode == ZEND_ROPE_END) {
  85                                 int num = (((opline->extended_value + 1) * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
  86                                 int var;
  87 
  88                                 var = max;
  89                                 while (var >= 0 && !zend_bitset_in(taken_T, var)) {
  90                                         var--;
  91                                 }
  92                                 max = MAX(max, var + num);
  93                                 var = var + 1;
  94                                 map_T[currT] = var;
  95                                 zend_bitset_incl(valid_T, currT);
  96                                 zend_bitset_incl(taken_T, var);
  97                                 ZEND_OP1(opline).var = NUM_VAR(var + offset);
  98                                 while (num > 1) {
  99                                         num--;
 100                                         zend_bitset_incl(taken_T, var + num);
 101                                 }
 102                         } else {
 103                                 if (!zend_bitset_in(valid_T, currT)) {
 104                                         int use_new_var = 0;
 105 
 106                                         /* Code in "finally" blocks may modify temorary variables.
 107                                          * We allocate new temporaries for values that need to
 108                                          * relive FAST_CALLs.
 109                                          */
 110                                         if ((op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) &&
 111                                             (opline->opcode == ZEND_RETURN ||
 112                                              opline->opcode == ZEND_RETURN_BY_REF ||
 113                                              opline->opcode == ZEND_FREE ||
 114                                              opline->opcode == ZEND_FE_FREE)) {
 115                                                 zend_op *curr = opline;
 116 
 117                                                 while (--curr >= end) {
 118                                                         if (curr->opcode == ZEND_FAST_CALL) {
 119                                                                 use_new_var = 1;
 120                                                                 break;
 121                                                         } else if (curr->opcode != ZEND_FREE &&
 122                                                                    curr->opcode != ZEND_FE_FREE &&
 123                                                                    curr->opcode != ZEND_VERIFY_RETURN_TYPE &&
 124                                                                    curr->opcode != ZEND_DISCARD_EXCEPTION) {
 125                                                                 break;
 126                                                         }
 127                                                 }
 128                                         }
 129                                         if (use_new_var) {
 130                                                 i = ++max;
 131                                                 zend_bitset_incl(taken_T, i);
 132                                         } else {
 133                                                 GET_AVAILABLE_T();
 134                                         }
 135                                         map_T[currT] = i;
 136                                         zend_bitset_incl(valid_T, currT);
 137                                 }
 138                                 ZEND_OP1(opline).var = NUM_VAR(map_T[currT] + offset);
 139                         }
 140                 }
 141 
 142                 /* Skip OP_DATA */
 143                 if (opline->opcode == ZEND_OP_DATA &&
 144                     (opline-1)->opcode == ZEND_ASSIGN_DIM) {
 145                     opline--;
 146                     continue;
 147                 }
 148 
 149                 if ((ZEND_OP2_TYPE(opline) & (IS_VAR | IS_TMP_VAR))) {
 150                         currT = VAR_NUM(ZEND_OP2(opline).var) - offset;
 151                         if (!zend_bitset_in(valid_T, currT)) {
 152                                 GET_AVAILABLE_T();
 153                                 map_T[currT] = i;
 154                                 zend_bitset_incl(valid_T, currT);
 155                         }
 156                         ZEND_OP2(opline).var = NUM_VAR(map_T[currT] + offset);
 157                 }
 158 
 159                 if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
 160                     opline->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS ||
 161             opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
 162                         currT = VAR_NUM(opline->extended_value) - offset;
 163                         if (!zend_bitset_in(valid_T, currT)) {
 164                                 GET_AVAILABLE_T();
 165                                 map_T[currT] = i;
 166                                 zend_bitset_incl(valid_T, currT);
 167                         }
 168                         opline->extended_value = NUM_VAR(map_T[currT] + offset);
 169                 }
 170 
 171                 /* Allocate OP_DATA->op2 after "operands", but before "result" */
 172                 if (opline->opcode == ZEND_ASSIGN_DIM &&
 173                     (opline + 1)->opcode == ZEND_OP_DATA &&
 174                     ZEND_OP2_TYPE(opline + 1) & (IS_VAR | IS_TMP_VAR)) {
 175                         currT = VAR_NUM(ZEND_OP2(opline + 1).var) - offset;
 176                         GET_AVAILABLE_T();
 177                         map_T[currT] = i;
 178                         zend_bitset_incl(valid_T, currT);
 179                         zend_bitset_excl(taken_T, i);
 180                         ZEND_OP2(opline + 1).var = NUM_VAR(i + offset);
 181                         var_to_free = i;
 182                 }
 183 
 184                 if (ZEND_RESULT_TYPE(opline) & (IS_VAR | IS_TMP_VAR)) {
 185                         currT = VAR_NUM(ZEND_RESULT(opline).var) - offset;
 186                         if (zend_bitset_in(valid_T, currT)) {
 187                                 if (start_of_T[currT] == opline) {
 188                                         /* ZEND_FAST_CALL can not share temporary var with others
 189                                          * since the fast_var could also be set by ZEND_HANDLE_EXCEPTION
 190                                          * which could be ahead of it */
 191                                         if (opline->opcode != ZEND_FAST_CALL) {
 192                                                 zend_bitset_excl(taken_T, map_T[currT]);
 193                                         }
 194                                 }
 195                                 ZEND_RESULT(opline).var = NUM_VAR(map_T[currT] + offset);
 196                                 if (opline->opcode == ZEND_ROPE_INIT) {
 197                                         if (start_of_T[currT] == opline) {
 198                                                 uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
 199                                                 while (num > 1) {
 200                                                         num--;
 201                                                         zend_bitset_excl(taken_T, map_T[currT]+num);
 202                                                 }
 203                                         }
 204                                 }
 205                         } else { /* Au still needs to be assigned a T which is a bit dumb. Should consider changing Zend */
 206                                 GET_AVAILABLE_T();
 207 
 208                                 if (RESULT_UNUSED(opline)) {
 209                                         zend_bitset_excl(taken_T, i);
 210                                 } else {
 211                                         /* Code which gets here is using a wrongly built opcode such as RECV() */
 212                                         map_T[currT] = i;
 213                                         zend_bitset_incl(valid_T, currT);
 214                                 }
 215                                 ZEND_RESULT(opline).var = NUM_VAR(i + offset);
 216                         }
 217                 }
 218 
 219                 if (var_to_free >= 0) {
 220                         zend_bitset_excl(taken_T, var_to_free);
 221                         var_to_free = -1;
 222                 }
 223 
 224                 opline--;
 225         }
 226 
 227         zend_arena_release(&ctx->arena, checkpoint);
 228         op_array->T = max + 1;
 229 }

/* [<][>][^][v][top][bottom][index][help] */