PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/opcache/Optimizer - zend_optimizer.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 160 304 52.6 %
Date: 2015-05-30 Functions: 11 13 84.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sat, 30 May 2015 05:52:52 +0000 (14 hours ago)

Copyright © 2005-2015 The PHP Group
All rights reserved.