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

Generated by: LCOV version 1.10

Generated at Wed, 02 Sep 2015 17:19:14 +0000 (28 hours ago)

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