root/ext/opcache/Optimizer/zend_optimizer.c

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

DEFINITIONS

This source file includes following definitions.
  1. zend_optimizer_zval_dtor_wrapper
  2. zend_optimizer_collect_constant
  3. zend_optimizer_get_collected_constant
  4. zend_optimizer_lookup_cv
  5. zend_optimizer_add_literal
  6. zend_optimizer_add_literal_string
  7. zend_optimizer_is_disabled_func
  8. drop_leading_backslash
  9. alloc_cache_slots_op1
  10. alloc_cache_slots_op2
  11. zend_optimizer_update_op1_const
  12. zend_optimizer_update_op2_const
  13. zend_optimizer_replace_by_const
  14. zend_optimize
  15. zend_accel_optimize
  16. zend_accel_adjust_fcall_stack_size
  17. zend_accel_script_optimize

   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 
  30 static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
  31 {
  32         zval_dtor(zvalue);
  33 }
  34 
  35 void zend_optimizer_collect_constant(zend_optimizer_ctx *ctx, zval *name, zval* value)
  36 {
  37         zval val;
  38 
  39         if (!ctx->constants) {
  40                 ctx->constants = zend_arena_alloc(&ctx->arena, sizeof(HashTable));
  41                 zend_hash_init(ctx->constants, 16, NULL, zend_optimizer_zval_dtor_wrapper, 0);
  42         }
  43         ZVAL_DUP(&val, value);
  44         zend_hash_add(ctx->constants, Z_STR_P(name), &val);
  45 }
  46 
  47 int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
  48 {
  49         zval *val;
  50 
  51         if ((val = zend_hash_find(constants, Z_STR_P(name))) != NULL) {
  52                 ZVAL_DUP(value, val);
  53                 return 1;
  54         }
  55         return 0;
  56 }
  57 
  58 int zend_optimizer_lookup_cv(zend_op_array *op_array, zend_string* name)
  59 {
  60         int i = 0;
  61         zend_ulong hash_value = zend_string_hash_val(name);
  62 
  63         while (i < op_array->last_var) {
  64                 if (op_array->vars[i] == name ||
  65                     (ZSTR_H(op_array->vars[i]) == hash_value &&
  66                      ZSTR_LEN(op_array->vars[i]) == ZSTR_LEN(name) &&
  67                      memcmp(ZSTR_VAL(op_array->vars[i]), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)) {
  68                         return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i);
  69                 }
  70                 i++;
  71         }
  72         i = op_array->last_var;
  73         op_array->last_var++;
  74         op_array->vars = erealloc(op_array->vars, op_array->last_var * sizeof(zend_string*));
  75         op_array->vars[i] = zend_string_dup(name, 0);
  76 
  77         /* all IS_TMP_VAR and IS_VAR variable numbers have to be adjusted */
  78         {
  79                 zend_op *opline = op_array->opcodes;
  80                 zend_op *end = opline + op_array->last;
  81                 while (opline < end) {
  82                         if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {
  83                                 opline->op1.var += sizeof(zval);
  84                         }
  85                         if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) {
  86                                 opline->op2.var += sizeof(zval);
  87                         }
  88                         if (opline->result_type & (IS_TMP_VAR|IS_VAR)) {
  89                                 opline->result.var += sizeof(zval);
  90                         }
  91                         if (opline->opcode == ZEND_DECLARE_INHERITED_CLASS ||
  92                             opline->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS ||
  93                             opline->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED) {
  94                                 opline->extended_value += sizeof(zval);
  95                         }
  96                         opline++;
  97                 }
  98         }
  99 
 100         return (int)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, i);
 101 }
 102 
 103 int zend_optimizer_add_literal(zend_op_array *op_array, zval *zv)
 104 {
 105         int i = op_array->last_literal;
 106         op_array->last_literal++;
 107         op_array->literals = (zval*)erealloc(op_array->literals, op_array->last_literal * sizeof(zval));
 108         ZVAL_COPY_VALUE(&op_array->literals[i], zv);
 109         Z_CACHE_SLOT(op_array->literals[i]) = -1;
 110         return i;
 111 }
 112 
 113 static inline int zend_optimizer_add_literal_string(zend_op_array *op_array, zend_string *str) {
 114         zval zv;
 115         ZVAL_STR(&zv, str);
 116         zend_string_hash_val(str);
 117         return zend_optimizer_add_literal(op_array, &zv);
 118 }
 119 
 120 int zend_optimizer_is_disabled_func(const char *name, size_t len) {
 121         zend_function *fbc = (zend_function *)zend_hash_str_find_ptr(EG(function_table), name, len);
 122 
 123         return (fbc && fbc->type == ZEND_INTERNAL_FUNCTION &&
 124                         fbc->internal_function.handler == ZEND_FN(display_disabled_function));
 125 }
 126 
 127 static inline void drop_leading_backslash(zval *val) {
 128         if (Z_STRVAL_P(val)[0] == '\\') {
 129                 zend_string *str = zend_string_init(Z_STRVAL_P(val) + 1, Z_STRLEN_P(val) - 1, 0);
 130                 zval_dtor(val);
 131                 ZVAL_STR(val, str);
 132         }
 133 }
 134 
 135 static inline void alloc_cache_slots_op1(zend_op_array *op_array, zend_op *opline, uint32_t num) {
 136         Z_CACHE_SLOT(op_array->literals[opline->op1.constant]) = op_array->cache_size;
 137         op_array->cache_size += num * sizeof(void *);
 138 }
 139 static inline void alloc_cache_slots_op2(zend_op_array *op_array, zend_op *opline, uint32_t num) {
 140         Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = op_array->cache_size;
 141         op_array->cache_size += num * sizeof(void *);
 142 }
 143 
 144 #define REQUIRES_STRING(val) do { \
 145         if (Z_TYPE_P(val) != IS_STRING) { \
 146                 zval_dtor(val); \
 147                 return 0; \
 148         } \
 149 } while (0)
 150 
 151 #define TO_STRING_NOWARN(val) do { \
 152         if (Z_TYPE_P(val) >= IS_ARRAY) { \
 153                 zval_dtor(val); \
 154                 return 0; \
 155         } \
 156         convert_to_string(val); \
 157 } while (0)
 158 
 159 int zend_optimizer_update_op1_const(zend_op_array *op_array,
 160                                     zend_op       *opline,
 161                                     zval          *val)
 162 {
 163         switch (opline->opcode) {
 164                 case ZEND_FREE:
 165                         MAKE_NOP(opline);
 166                         zval_dtor(val);
 167                         return 1;
 168                 case ZEND_INIT_STATIC_METHOD_CALL:
 169                 case ZEND_CATCH:
 170                 case ZEND_FETCH_CONSTANT:
 171                 case ZEND_DEFINED:
 172                 case ZEND_NEW:
 173                         REQUIRES_STRING(val);
 174                         drop_leading_backslash(val);
 175                         opline->op1.constant = zend_optimizer_add_literal(op_array, val);
 176                         alloc_cache_slots_op1(op_array, opline, 1);
 177                         zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
 178                         break;
 179                 case ZEND_FETCH_R:
 180                 case ZEND_FETCH_W:
 181                 case ZEND_FETCH_RW:
 182                 case ZEND_FETCH_IS:
 183                 case ZEND_FETCH_UNSET:
 184                 case ZEND_FETCH_FUNC_ARG:
 185                         TO_STRING_NOWARN(val);
 186                         opline->op1.constant = zend_optimizer_add_literal(op_array, val);
 187                         if (opline->extended_value == ZEND_FETCH_STATIC_MEMBER) {
 188                                 alloc_cache_slots_op1(op_array, opline, 2);
 189                         }
 190                         break;
 191                 case ZEND_CONCAT:
 192                 case ZEND_FAST_CONCAT:
 193                         TO_STRING_NOWARN(val);
 194                         /* break missing intentionally */
 195                 default:
 196                         opline->op1.constant = zend_optimizer_add_literal(op_array, val);
 197                         break;
 198         }
 199 
 200         ZEND_OP1_TYPE(opline) = IS_CONST;
 201         if (Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING) {
 202                 zend_string_hash_val(Z_STR(ZEND_OP1_LITERAL(opline)));
 203         }
 204         return 1;
 205 }
 206 
 207 int zend_optimizer_update_op2_const(zend_op_array *op_array,
 208                                     zend_op       *opline,
 209                                     zval          *val)
 210 {
 211         switch (opline->opcode) {
 212                 case ZEND_ASSIGN_REF:
 213                         zval_dtor(val);
 214                         return 0;
 215                 case ZEND_FETCH_R:
 216                 case ZEND_FETCH_W:
 217                 case ZEND_FETCH_RW:
 218                 case ZEND_FETCH_IS:
 219                 case ZEND_FETCH_UNSET:
 220                 case ZEND_FETCH_FUNC_ARG:
 221                 case ZEND_FETCH_CLASS:
 222                 case ZEND_INIT_FCALL_BY_NAME:
 223                 /*case ZEND_INIT_NS_FCALL_BY_NAME:*/
 224                 case ZEND_UNSET_VAR:
 225                 case ZEND_ISSET_ISEMPTY_VAR:
 226                 case ZEND_ADD_INTERFACE:
 227                 case ZEND_ADD_TRAIT:
 228                 case ZEND_INSTANCEOF:
 229                         REQUIRES_STRING(val);
 230                         drop_leading_backslash(val);
 231                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 232                         zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
 233                         alloc_cache_slots_op2(op_array, opline, 1);
 234                         break;
 235                 case ZEND_INIT_FCALL:
 236                         REQUIRES_STRING(val);
 237                         zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
 238                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 239                         alloc_cache_slots_op2(op_array, opline, 1);
 240                         break;
 241                 case ZEND_INIT_DYNAMIC_CALL:
 242                         if (Z_TYPE_P(val) == IS_STRING) {
 243                                 if (zend_memrchr(Z_STRVAL_P(val), ':', Z_STRLEN_P(val))) {
 244                                         zval_dtor(val);
 245                                         return 0;
 246                                 }
 247 
 248                                 opline->opcode = ZEND_INIT_FCALL_BY_NAME;
 249                                 drop_leading_backslash(val);
 250                                 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 251                                 zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
 252                                 alloc_cache_slots_op2(op_array, opline, 1);
 253                         } else {
 254                                 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 255                         }
 256                         break;
 257                 case ZEND_INIT_METHOD_CALL:
 258                 case ZEND_INIT_STATIC_METHOD_CALL:
 259                         REQUIRES_STRING(val);
 260                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 261                         zend_optimizer_add_literal_string(op_array, zend_string_tolower(Z_STR_P(val)));
 262                         alloc_cache_slots_op2(op_array, opline, 2);
 263                         break;
 264                 /*case ZEND_FETCH_CONSTANT:*/
 265                 case ZEND_ASSIGN_OBJ:
 266                 case ZEND_FETCH_OBJ_R:
 267                 case ZEND_FETCH_OBJ_W:
 268                 case ZEND_FETCH_OBJ_RW:
 269                 case ZEND_FETCH_OBJ_IS:
 270                 case ZEND_FETCH_OBJ_UNSET:
 271                 case ZEND_FETCH_OBJ_FUNC_ARG:
 272                 case ZEND_UNSET_OBJ:
 273                 case ZEND_PRE_INC_OBJ:
 274                 case ZEND_PRE_DEC_OBJ:
 275                 case ZEND_POST_INC_OBJ:
 276                 case ZEND_POST_DEC_OBJ:
 277                 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
 278                         TO_STRING_NOWARN(val);
 279                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 280                         alloc_cache_slots_op2(op_array, opline, 2);
 281                         break;
 282                 case ZEND_ASSIGN_ADD:
 283                 case ZEND_ASSIGN_SUB:
 284                 case ZEND_ASSIGN_MUL:
 285                 case ZEND_ASSIGN_DIV:
 286                 case ZEND_ASSIGN_POW:
 287                 case ZEND_ASSIGN_MOD:
 288                 case ZEND_ASSIGN_SL:
 289                 case ZEND_ASSIGN_SR:
 290                 case ZEND_ASSIGN_CONCAT:
 291                 case ZEND_ASSIGN_BW_OR:
 292                 case ZEND_ASSIGN_BW_AND:
 293                 case ZEND_ASSIGN_BW_XOR:
 294                         if (opline->extended_value == ZEND_ASSIGN_OBJ) {
 295                                 TO_STRING_NOWARN(val);
 296                                 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 297                                 alloc_cache_slots_op2(op_array, opline, 2);
 298                         } else {
 299                                 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 300                         }
 301                         break;
 302                 case ZEND_OP_DATA:
 303                         if ((opline-1)->opcode != ZEND_ASSIGN_DIM &&
 304                                 ((opline-1)->extended_value != ZEND_ASSIGN_DIM ||
 305                                  ((opline-1)->opcode != ZEND_ASSIGN_ADD &&
 306                                  (opline-1)->opcode != ZEND_ASSIGN_SUB &&
 307                                  (opline-1)->opcode != ZEND_ASSIGN_MUL &&
 308                                  (opline-1)->opcode != ZEND_ASSIGN_DIV &&
 309                                  (opline-1)->opcode != ZEND_ASSIGN_POW &&
 310                                  (opline-1)->opcode != ZEND_ASSIGN_MOD &&
 311                                  (opline-1)->opcode != ZEND_ASSIGN_SL &&
 312                                  (opline-1)->opcode != ZEND_ASSIGN_SR &&
 313                                  (opline-1)->opcode != ZEND_ASSIGN_CONCAT &&
 314                                  (opline-1)->opcode != ZEND_ASSIGN_BW_OR &&
 315                                  (opline-1)->opcode != ZEND_ASSIGN_BW_AND &&
 316                                  (opline-1)->opcode != ZEND_ASSIGN_BW_XOR))
 317                         ) {
 318                                 opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 319                                 break;
 320                         }
 321                         /* break missing intentionally */
 322                 case ZEND_ISSET_ISEMPTY_DIM_OBJ:
 323                 case ZEND_ADD_ARRAY_ELEMENT:
 324                 case ZEND_INIT_ARRAY:
 325                 case ZEND_ASSIGN_DIM:
 326                 case ZEND_UNSET_DIM:
 327                 case ZEND_FETCH_DIM_R:
 328                 case ZEND_FETCH_DIM_W:
 329                 case ZEND_FETCH_DIM_RW:
 330                 case ZEND_FETCH_DIM_IS:
 331                 case ZEND_FETCH_DIM_FUNC_ARG:
 332                 case ZEND_FETCH_DIM_UNSET:
 333                 case ZEND_FETCH_LIST:
 334                         if (Z_TYPE_P(val) == IS_STRING) {
 335                                 zend_ulong index;
 336                                 if (ZEND_HANDLE_NUMERIC(Z_STR_P(val), index)) {
 337                                         zval_dtor(val);
 338                                         ZVAL_LONG(val, index);
 339                                 }
 340                         }
 341                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 342                         break;
 343                 case ZEND_ROPE_INIT:
 344                 case ZEND_ROPE_ADD:
 345                 case ZEND_ROPE_END:
 346                 case ZEND_CONCAT:
 347                 case ZEND_FAST_CONCAT:
 348                         TO_STRING_NOWARN(val);
 349                         /* break missing intentionally */
 350                 default:
 351                         opline->op2.constant = zend_optimizer_add_literal(op_array, val);
 352                         break;
 353         }
 354 
 355         ZEND_OP2_TYPE(opline) = IS_CONST;
 356         if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) {
 357                 zend_string_hash_val(Z_STR(ZEND_OP2_LITERAL(opline)));
 358         }
 359         return 1;
 360 }
 361 
 362 int zend_optimizer_replace_by_const(zend_op_array *op_array,
 363                                     zend_op       *opline,
 364                                     zend_uchar     type,
 365                                     uint32_t       var,
 366                                     zval          *val)
 367 {
 368         zend_op *end = op_array->opcodes + op_array->last;
 369 
 370         while (opline < end) {
 371                 if (ZEND_OP1_TYPE(opline) == type &&
 372                         ZEND_OP1(opline).var == var) {
 373                         switch (opline->opcode) {
 374                                 case ZEND_FETCH_DIM_W:
 375                                 case ZEND_FETCH_DIM_RW:
 376                                 case ZEND_FETCH_DIM_FUNC_ARG:
 377                                 case ZEND_FETCH_DIM_UNSET:
 378                                 case ZEND_ASSIGN_DIM:
 379                                 case ZEND_SEPARATE:
 380                                 case ZEND_RETURN_BY_REF:
 381                                         zval_dtor(val);
 382                                         return 0;
 383                                 case ZEND_SEND_VAR:
 384                                         opline->extended_value = 0;
 385                                         opline->opcode = ZEND_SEND_VAL;
 386                                         break;
 387                                 case ZEND_SEND_VAR_EX:
 388                                         opline->extended_value = 0;
 389                                         opline->opcode = ZEND_SEND_VAL_EX;
 390                                         break;
 391                                 case ZEND_SEND_VAR_NO_REF:
 392                                         if (opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) {
 393                                                 if (opline->extended_value & ZEND_ARG_SEND_BY_REF) {
 394                                                         zval_dtor(val);
 395                                                         return 0;
 396                                                 }
 397                                                 opline->extended_value = 0;
 398                                                 opline->opcode = ZEND_SEND_VAL_EX;
 399                                         } else {
 400                                                 opline->extended_value = 0;
 401                                                 opline->opcode = ZEND_SEND_VAL;
 402                                         }
 403                                         break;
 404                                 case ZEND_SEND_USER:
 405                                         opline->opcode = ZEND_SEND_VAL_EX;
 406                                         break;
 407                                 /* In most cases IS_TMP_VAR operand may be used only once.
 408                                  * The operands are usually destroyed by the opcode handler.
 409                                  * ZEND_CASE is an exception, that keeps operand unchanged,
 410                                  * and allows its reuse. The number of ZEND_CASE instructions
 411                                  * usually terminated by ZEND_FREE that finally kills the value.
 412                                  */
 413                                 case ZEND_FREE:
 414                                 case ZEND_CASE: {
 415                                         zend_op *m, *n;
 416                                         int brk = op_array->last_brk_cont;
 417                                         zend_bool in_switch = 0;
 418                                         while (brk--) {
 419                                                 if (op_array->brk_cont_array[brk].start <= (opline - op_array->opcodes) &&
 420                                                                 op_array->brk_cont_array[brk].brk > (opline - op_array->opcodes)) {
 421                                                         in_switch = 1;
 422                                                         break;
 423                                                 }
 424                                         }
 425 
 426                                         if (!in_switch) {
 427                                                 ZEND_ASSERT(opline->opcode == ZEND_FREE);
 428                                                 MAKE_NOP(opline);
 429                                                 zval_dtor(val);
 430                                                 return 1;
 431                                         }
 432 
 433                                         m = opline;
 434                                         n = op_array->opcodes + op_array->brk_cont_array[brk].brk + 1;
 435                                         while (m < n) {
 436                                                 if (ZEND_OP1_TYPE(m) == type &&
 437                                                                 ZEND_OP1(m).var == var) {
 438                                                         if (m->opcode == ZEND_CASE) {
 439                                                                 zval old_val;
 440                                                                 ZVAL_COPY_VALUE(&old_val, val);
 441                                                                 zval_copy_ctor(val);
 442                                                                 zend_optimizer_update_op1_const(op_array, m, val);
 443                                                                 ZVAL_COPY_VALUE(val, &old_val);
 444                                                         } else if (m->opcode == ZEND_FREE) {
 445                                                                 MAKE_NOP(m);
 446                                                         } else {
 447                                                                 ZEND_ASSERT(0);
 448                                                         }
 449                                                 }
 450                                                 m++;
 451                                         }
 452                                         zval_dtor(val);
 453                                         return 1;
 454                                 }
 455                                 case ZEND_VERIFY_RETURN_TYPE: {
 456                                         zend_arg_info *ret_info = op_array->arg_info - 1;
 457                                         ZEND_ASSERT((opline + 1)->opcode == ZEND_RETURN || (opline + 1)->opcode == ZEND_RETURN_BY_REF);
 458                                         if (ret_info->class_name
 459                                                 || ret_info->type_hint == IS_CALLABLE
 460                                                 || !ZEND_SAME_FAKE_TYPE(ret_info->type_hint, Z_TYPE_P(val))
 461                                                 || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
 462                                                 zval_dtor(val);
 463                                                 return 0;
 464                                         }
 465                                         MAKE_NOP(opline);
 466                                         zend_optimizer_update_op1_const(op_array, opline + 1, val);
 467                                         return 1;
 468                                   }
 469                                 default:
 470                                         break;
 471                         }
 472                         return zend_optimizer_update_op1_const(op_array, opline, val);
 473                 }
 474 
 475                 if (ZEND_OP2_TYPE(opline) == type &&
 476                         ZEND_OP2(opline).var == var) {
 477                         return zend_optimizer_update_op2_const(op_array, opline, val);
 478                 }
 479                 opline++;
 480         }
 481 
 482         return 1;
 483 }
 484 
 485 static void zend_optimize(zend_op_array      *op_array,
 486                           zend_optimizer_ctx *ctx)
 487 {
 488         if (op_array->type == ZEND_EVAL_CODE) {
 489                 return;
 490         }
 491 
 492         /* pass 1
 493          * - substitute persistent constants (true, false, null, etc)
 494          * - perform compile-time evaluation of constant binary and unary operations
 495          * - optimize series of ADD_STRING and/or ADD_CHAR
 496          * - convert CAST(IS_BOOL,x) into BOOL(x)
 497          */
 498         if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
 499                 zend_optimizer_pass1(op_array, ctx);
 500         }
 501 
 502         /* pass 2:
 503          * - convert non-numeric constants to numeric constants in numeric operators
 504          * - optimize constant conditional JMPs
 505          * - optimize static BRKs and CONTs
 506          * - pre-evaluate constant function calls
 507          */
 508         if (ZEND_OPTIMIZER_PASS_2 & OPTIMIZATION_LEVEL) {
 509                 zend_optimizer_pass2(op_array);
 510         }
 511 
 512         /* pass 3:
 513          * - optimize $i = $i+expr to $i+=expr
 514          * - optimize series of JMPs
 515          * - change $i++ to ++$i where possible
 516          */
 517         if (ZEND_OPTIMIZER_PASS_3 & OPTIMIZATION_LEVEL) {
 518                 zend_optimizer_pass3(op_array);
 519         }
 520 
 521         /* pass 4:
 522          * - INIT_FCALL_BY_NAME -> DO_FCALL
 523          */
 524         if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) {
 525                 optimize_func_calls(op_array, ctx);
 526         }
 527 
 528         /* pass 5:
 529          * - CFG optimization
 530          */
 531         if (ZEND_OPTIMIZER_PASS_5 & OPTIMIZATION_LEVEL) {
 532                 optimize_cfg(op_array, ctx);
 533         }
 534 
 535         /* pass 9:
 536          * - Optimize temp variables usage
 537          */
 538         if (ZEND_OPTIMIZER_PASS_9 & OPTIMIZATION_LEVEL) {
 539                 optimize_temporary_variables(op_array, ctx);
 540         }
 541 
 542         /* pass 10:
 543          * - remove NOPs
 544          */
 545         if (((ZEND_OPTIMIZER_PASS_10|ZEND_OPTIMIZER_PASS_5) & OPTIMIZATION_LEVEL) == ZEND_OPTIMIZER_PASS_10) {
 546                 zend_optimizer_nop_removal(op_array);
 547         }
 548 
 549         /* pass 11:
 550          * - Compact literals table
 551          */
 552         if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
 553                 zend_optimizer_compact_literals(op_array, ctx);
 554         }
 555 }
 556 
 557 static void zend_accel_optimize(zend_op_array      *op_array,
 558                                 zend_optimizer_ctx *ctx)
 559 {
 560         zend_op *opline, *end;
 561 
 562         /* Revert pass_two() */
 563         opline = op_array->opcodes;
 564         end = opline + op_array->last;
 565         while (opline < end) {
 566                 if (opline->op1_type == IS_CONST) {
 567                         ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline->op1);
 568                 }
 569                 if (opline->op2_type == IS_CONST) {
 570                         ZEND_PASS_TWO_UNDO_CONSTANT(op_array, opline->op2);
 571                 }
 572                 switch (opline->opcode) {
 573                         case ZEND_JMP:
 574                         case ZEND_FAST_CALL:
 575                         case ZEND_DECLARE_ANON_CLASS:
 576                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
 577                                 ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
 578                                 break;
 579                         case ZEND_JMPZNZ:
 580                                 /* relative offset into absolute index */
 581                                 opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
 582                                 /* break omitted intentionally */
 583                         case ZEND_JMPZ:
 584                         case ZEND_JMPNZ:
 585                         case ZEND_JMPZ_EX:
 586                         case ZEND_JMPNZ_EX:
 587                         case ZEND_JMP_SET:
 588                         case ZEND_COALESCE:
 589                         case ZEND_NEW:
 590                         case ZEND_FE_RESET_R:
 591                         case ZEND_FE_RESET_RW:
 592                         case ZEND_ASSERT_CHECK:
 593                                 ZEND_PASS_TWO_UNDO_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
 594                                 break;
 595                         case ZEND_FE_FETCH_R:
 596                         case ZEND_FE_FETCH_RW:
 597                                 opline->extended_value = ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value);
 598                                 break;
 599                 }
 600                 opline++;
 601         }
 602 
 603         /* Do actual optimizations */
 604         zend_optimize(op_array, ctx);
 605 
 606         /* Redo pass_two() */
 607         opline = op_array->opcodes;
 608         end = opline + op_array->last;
 609         while (opline < end) {
 610                 if (opline->op1_type == IS_CONST) {
 611                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op1);
 612                 }
 613                 if (opline->op2_type == IS_CONST) {
 614                         ZEND_PASS_TWO_UPDATE_CONSTANT(op_array, opline->op2);
 615                 }
 616                 switch (opline->opcode) {
 617                         case ZEND_JMP:
 618                         case ZEND_FAST_CALL:
 619                         case ZEND_DECLARE_ANON_CLASS:
 620                         case ZEND_DECLARE_ANON_INHERITED_CLASS:
 621                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP1(opline));
 622                                 break;
 623                         case ZEND_JMPZNZ:
 624                                 /* absolute index to relative offset */
 625                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
 626                                 /* break omitted intentionally */
 627                         case ZEND_JMPZ:
 628                         case ZEND_JMPNZ:
 629                         case ZEND_JMPZ_EX:
 630                         case ZEND_JMPNZ_EX:
 631                         case ZEND_JMP_SET:
 632                         case ZEND_COALESCE:
 633                         case ZEND_NEW:
 634                         case ZEND_FE_RESET_R:
 635                         case ZEND_FE_RESET_RW:
 636                         case ZEND_ASSERT_CHECK:
 637                                 ZEND_PASS_TWO_UPDATE_JMP_TARGET(op_array, opline, ZEND_OP2(opline));
 638                                 break;
 639                         case ZEND_FE_FETCH_R:
 640                         case ZEND_FE_FETCH_RW:
 641                                 opline->extended_value = ZEND_OPLINE_NUM_TO_OFFSET(op_array, opline, opline->extended_value);
 642                                 break;
 643                 }
 644                 ZEND_VM_SET_OPCODE_HANDLER(opline);
 645                 opline++;
 646         }
 647 }
 648 
 649 static void zend_accel_adjust_fcall_stack_size(zend_op_array *op_array, zend_optimizer_ctx *ctx)
 650 {
 651         zend_function *func;
 652         zend_op *opline, *end;
 653 
 654         opline = op_array->opcodes;
 655         end = opline + op_array->last;
 656         while (opline < end) {
 657                 if (opline->opcode == ZEND_INIT_FCALL) {
 658                         func = zend_hash_find_ptr(
 659                                 &ctx->script->function_table,
 660                                 Z_STR_P(RT_CONSTANT(op_array, opline->op2)));
 661                         if (func) {
 662                                 opline->op1.num = zend_vm_calc_used_stack(opline->extended_value, func);
 663                         }
 664                 }
 665                 opline++;
 666         }
 667 }
 668 
 669 int zend_accel_script_optimize(zend_persistent_script *script)
 670 {
 671         uint idx, j;
 672         Bucket *p, *q;
 673         zend_class_entry *ce;
 674         zend_op_array *op_array;
 675         zend_optimizer_ctx ctx;
 676 
 677         ctx.arena = zend_arena_create(64 * 1024);
 678         ctx.script = script;
 679         ctx.constants = NULL;
 680 
 681         zend_accel_optimize(&script->main_op_array, &ctx);
 682 
 683         for (idx = 0; idx < script->function_table.nNumUsed; idx++) {
 684                 p = script->function_table.arData + idx;
 685                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
 686                 op_array = (zend_op_array*)Z_PTR(p->val);
 687                 zend_accel_optimize(op_array, &ctx);
 688         }
 689 
 690         for (idx = 0; idx < script->class_table.nNumUsed; idx++) {
 691                 p = script->class_table.arData + idx;
 692                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
 693                 ce = (zend_class_entry*)Z_PTR(p->val);
 694                 for (j = 0; j < ce->function_table.nNumUsed; j++) {
 695                         q = ce->function_table.arData + j;
 696                         if (Z_TYPE(q->val) == IS_UNDEF) continue;
 697                         op_array = (zend_op_array*)Z_PTR(q->val);
 698                         if (op_array->scope == ce) {
 699                                 zend_accel_optimize(op_array, &ctx);
 700                         } else if (op_array->type == ZEND_USER_FUNCTION) {
 701                                 zend_op_array *orig_op_array;
 702                                 if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, q->key)) != NULL) {
 703                                         HashTable *ht = op_array->static_variables;
 704                                         *op_array = *orig_op_array;
 705                                         op_array->static_variables = ht;
 706                                 }
 707                         }
 708                 }
 709         }
 710 
 711         if (ZEND_OPTIMIZER_PASS_12 & OPTIMIZATION_LEVEL) {
 712                 zend_accel_adjust_fcall_stack_size(&script->main_op_array, &ctx);
 713 
 714                 for (idx = 0; idx < script->function_table.nNumUsed; idx++) {
 715                         p = script->function_table.arData + idx;
 716                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
 717                         op_array = (zend_op_array*)Z_PTR(p->val);
 718                         zend_accel_adjust_fcall_stack_size(op_array, &ctx);
 719                 }
 720 
 721                 for (idx = 0; idx < script->class_table.nNumUsed; idx++) {
 722                         p = script->class_table.arData + idx;
 723                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
 724                         ce = (zend_class_entry*)Z_PTR(p->val);
 725                         for (j = 0; j < ce->function_table.nNumUsed; j++) {
 726                                 q = ce->function_table.arData + j;
 727                                 if (Z_TYPE(q->val) == IS_UNDEF) continue;
 728                                 op_array = (zend_op_array*)Z_PTR(q->val);
 729                                 if (op_array->scope == ce) {
 730                                         zend_accel_adjust_fcall_stack_size(op_array, &ctx);
 731                                 } else if (op_array->type == ZEND_USER_FUNCTION) {
 732                                         zend_op_array *orig_op_array;
 733                                         if ((orig_op_array = zend_hash_find_ptr(&op_array->scope->function_table, q->key)) != NULL) {
 734                                                 HashTable *ht = op_array->static_variables;
 735                                                 *op_array = *orig_op_array;
 736                                                 op_array->static_variables = ht;
 737                                         }
 738                                 }
 739                         }
 740                 }
 741         }
 742 
 743         if (ctx.constants) {
 744                 zend_hash_destroy(ctx.constants);
 745         }
 746         zend_arena_destroy(ctx.arena);
 747 
 748         return 1;
 749 }

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