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 - compact_literals.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 227 253 89.7 %
Date: 2019-04-07 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend OPcache                                                         |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2018 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: Dmitry Stogov <dmitry@zend.com>                             |
      16             :    |          Xinchen Hui <laruence@php.net>                              |
      17             :    +----------------------------------------------------------------------+
      18             : */
      19             : 
      20             : /* pass 11
      21             :  * - compact literals table
      22             :  */
      23             : 
      24             : #include "php.h"
      25             : #include "Optimizer/zend_optimizer.h"
      26             : #include "Optimizer/zend_optimizer_internal.h"
      27             : #include "zend_API.h"
      28             : #include "zend_constants.h"
      29             : #include "zend_execute.h"
      30             : #include "zend_vm.h"
      31             : 
      32             : #define DEBUG_COMPACT_LITERALS 0
      33             : 
      34             : #define LITERAL_VALUE                        0x0100
      35             : #define LITERAL_FUNC                         0x0200
      36             : #define LITERAL_CLASS                        0x0300
      37             : #define LITERAL_CONST                        0x0400
      38             : #define LITERAL_CLASS_CONST                  0x0500
      39             : #define LITERAL_STATIC_METHOD                0x0600
      40             : #define LITERAL_STATIC_PROPERTY              0x0700
      41             : #define LITERAL_METHOD                       0x0800
      42             : #define LITERAL_PROPERTY                     0x0900
      43             : #define LITERAL_GLOBAL                       0x0A00
      44             : 
      45             : #define LITERAL_EX_CLASS                     0x4000
      46             : #define LITERAL_EX_OBJ                       0x2000
      47             : #define LITERAL_MAY_MERGE                    0x1000
      48             : #define LITERAL_KIND_MASK                    0x0f00
      49             : #define LITERAL_NUM_RELATED_MASK             0x000f
      50             : #define LITERAL_NUM_SLOTS_MASK               0x00f0
      51             : #define LITERAL_NUM_SLOTS_SHIFT              4
      52             : 
      53             : #define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK)
      54             : #define LITERAL_NUM_SLOTS(info)   ((info & LITERAL_NUM_SLOTS_MASK) >> LITERAL_NUM_SLOTS_SHIFT)
      55             : 
      56             : typedef struct _literal_info {
      57             :         uint32_t  flags; /* bitmask (see defines above) */
      58             :         union {
      59             :                 int    num;   /* variable number or class name literal number */
      60             :         } u;
      61             : } literal_info;
      62             : 
      63             : #define LITERAL_FLAGS(kind, slots, related) \
      64             :         ((kind) | ((slots) << LITERAL_NUM_SLOTS_SHIFT) | (related))
      65             : 
      66             : #define LITERAL_INFO(n, kind, merge, slots, related) do { \
      67             :                 info[n].flags = (((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
      68             :         } while (0)
      69             : 
      70             : #define LITERAL_INFO_CLASS(n, kind, merge, slots, related, _num) do { \
      71             :                 info[n].flags = (LITERAL_EX_CLASS | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
      72             :                 info[n].u.num = (_num); \
      73             :         } while (0)
      74             : 
      75             : #define LITERAL_INFO_OBJ(n, kind, merge, slots, related) do { \
      76             :                 info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \
      77             :                 info[n].u.num = (uint32_t)-1; \
      78             :         } while (0)
      79             : 
      80          42 : static void optimizer_literal_obj_info(literal_info   *info,
      81             :                                        zend_uchar      op_type,
      82             :                                        znode_op        op,
      83             :                                        int             constant,
      84             :                                        uint32_t       kind,
      85             :                                        uint32_t       slots,
      86             :                                        uint32_t       related,
      87             :                                        zend_op_array  *op_array)
      88             : {
      89             :         /* For now we merge only $this object properties and methods.
      90             :          * In general it's also possible to do it for any CV variable as well,
      91             :          * but it would require complex dataflow and/or type analysis.
      92             :          */
      93          84 :         if (Z_TYPE(op_array->literals[constant]) == IS_STRING &&
      94             :             op_type == IS_UNUSED) {
      95           2 :                 LITERAL_INFO_OBJ(constant, kind, 1, slots, related);
      96             :         } else {
      97          40 :                 LITERAL_INFO(constant, kind, 0, slots, related);
      98             :         }
      99          42 : }
     100             : 
     101         159 : static void optimizer_literal_class_info(literal_info   *info,
     102             :                                          zend_uchar      op_type,
     103             :                                          znode_op        op,
     104             :                                          int             constant,
     105             :                                          uint32_t       kind,
     106             :                                          uint32_t       slots,
     107             :                                          uint32_t       related,
     108             :                                          zend_op_array  *op_array)
     109             : {
     110         159 :         if (op_type == IS_CONST) {
     111         143 :                 LITERAL_INFO_CLASS(constant, kind, 1, slots, related, op.constant);
     112             :         } else {
     113          16 :                 LITERAL_INFO(constant, kind, 0, slots, related);
     114             :         }
     115         159 : }
     116             : 
     117         729 : void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx *ctx)
     118             : {
     119             :         zend_op *opline, *end;
     120             :         int i, j, n, *map, cache_size;
     121             :         zval zv, *pos;
     122             :         literal_info *info;
     123         729 :         int l_null = -1;
     124         729 :         int l_false = -1;
     125         729 :         int l_true = -1;
     126             :         HashTable hash;
     127         729 :         zend_string *key = NULL;
     128        1458 :         void *checkpoint = zend_arena_checkpoint(ctx->arena);
     129             : 
     130         729 :         if (op_array->last_literal) {
     131         729 :                 cache_size = 0;
     132        1458 :                 info = (literal_info*)zend_arena_calloc(&ctx->arena, op_array->last_literal, sizeof(literal_info));
     133             : 
     134             :             /* Mark literals of specific types */
     135         729 :                 opline = op_array->opcodes;
     136         729 :                 end = opline + op_array->last;
     137        9584 :                 while (opline < end) {
     138        8126 :                         switch (opline->opcode) {
     139        1145 :                                 case ZEND_INIT_FCALL:
     140        1145 :                                         LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 1);
     141        1145 :                                         break;
     142          10 :                                 case ZEND_INIT_FCALL_BY_NAME:
     143          10 :                                         LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2);
     144          10 :                                         break;
     145           2 :                                 case ZEND_INIT_NS_FCALL_BY_NAME:
     146           2 :                                         LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3);
     147           2 :                                         break;
     148          36 :                                 case ZEND_INIT_METHOD_CALL:
     149          36 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     150           0 :                                                 LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
     151             :                                         }
     152          36 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     153          72 :                                                 optimizer_literal_obj_info(
     154             :                                                         info,
     155          36 :                                                         opline->op1_type,
     156             :                                                         opline->op1,
     157          36 :                                                         opline->op2.constant,
     158             :                                                         LITERAL_METHOD, 2, 2,
     159             :                                                         op_array);
     160             :                                         }
     161          36 :                                         break;
     162         126 :                                 case ZEND_INIT_STATIC_METHOD_CALL:
     163         126 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     164         121 :                                                 LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
     165             :                                         }
     166         126 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     167         378 :                                                 optimizer_literal_class_info(
     168             :                                                         info,
     169         126 :                                                         opline->op1_type,
     170             :                                                         opline->op1,
     171         126 :                                                         opline->op2.constant,
     172         126 :                                                         LITERAL_STATIC_METHOD, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 2,
     173             :                                                         op_array);
     174             :                                         }
     175         126 :                                         break;
     176          16 :                                 case ZEND_CATCH:
     177          16 :                                         LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
     178          16 :                                         break;
     179           0 :                                 case ZEND_DEFINED:
     180           0 :                                         LITERAL_INFO(opline->op1.constant, LITERAL_CONST, 1, 1, 2);
     181           0 :                                         break;
     182          69 :                                 case ZEND_FETCH_CONSTANT:
     183          69 :                                         if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) {
     184           0 :                                                 LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5);
     185             :                                         } else {
     186          69 :                                                 LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3);
     187             :                                         }
     188          69 :                                         break;
     189          24 :                                 case ZEND_FETCH_CLASS_CONSTANT:
     190          24 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     191          16 :                                                 LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
     192             :                                         }
     193          72 :                                         optimizer_literal_class_info(
     194             :                                                 info,
     195          24 :                                                 opline->op1_type,
     196             :                                                 opline->op1,
     197          24 :                                                 opline->op2.constant,
     198          24 :                                                 LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1,
     199             :                                                 op_array);
     200          24 :                                         break;
     201           9 :                                 case ZEND_FETCH_STATIC_PROP_R:
     202             :                                 case ZEND_FETCH_STATIC_PROP_W:
     203             :                                 case ZEND_FETCH_STATIC_PROP_RW:
     204             :                                 case ZEND_FETCH_STATIC_PROP_IS:
     205             :                                 case ZEND_FETCH_STATIC_PROP_UNSET:
     206             :                                 case ZEND_FETCH_STATIC_PROP_FUNC_ARG:
     207             :                                 case ZEND_UNSET_STATIC_PROP:
     208             :                                 case ZEND_ISSET_ISEMPTY_STATIC_PROP:
     209           9 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     210           6 :                                                 LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
     211             :                                         }
     212           9 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     213          18 :                                                 optimizer_literal_class_info(
     214             :                                                         info,
     215           9 :                                                         opline->op2_type,
     216             :                                                         opline->op2,
     217           9 :                                                         opline->op1.constant,
     218             :                                                         LITERAL_STATIC_PROPERTY, 2, 1,
     219             :                                                         op_array);
     220             :                                         }
     221           9 :                                         break;
     222          14 :                                 case ZEND_FETCH_CLASS:
     223             :                                 case ZEND_ADD_INTERFACE:
     224             :                                 case ZEND_ADD_TRAIT:
     225             :                                 case ZEND_INSTANCEOF:
     226          14 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     227           6 :                                                 LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2);
     228             :                                         }
     229          14 :                                         break;
     230          44 :                                 case ZEND_NEW:
     231          44 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     232          43 :                                                 LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2);
     233             :                                         }
     234          44 :                                         break;
     235           6 :                                 case ZEND_ASSIGN_OBJ:
     236             :                                 case ZEND_FETCH_OBJ_R:
     237             :                                 case ZEND_FETCH_OBJ_W:
     238             :                                 case ZEND_FETCH_OBJ_RW:
     239             :                                 case ZEND_FETCH_OBJ_IS:
     240             :                                 case ZEND_FETCH_OBJ_UNSET:
     241             :                                 case ZEND_FETCH_OBJ_FUNC_ARG:
     242             :                                 case ZEND_UNSET_OBJ:
     243             :                                 case ZEND_PRE_INC_OBJ:
     244             :                                 case ZEND_PRE_DEC_OBJ:
     245             :                                 case ZEND_POST_INC_OBJ:
     246             :                                 case ZEND_POST_DEC_OBJ:
     247             :                                 case ZEND_ISSET_ISEMPTY_PROP_OBJ:
     248           6 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     249          12 :                                                 optimizer_literal_obj_info(
     250             :                                                         info,
     251           6 :                                                         opline->op1_type,
     252             :                                                         opline->op1,
     253           6 :                                                         opline->op2.constant,
     254             :                                                         LITERAL_PROPERTY, 2, 1,
     255             :                                                         op_array);
     256             :                                         }
     257           6 :                                         break;
     258          11 :                                 case ZEND_ASSIGN_ADD:
     259             :                                 case ZEND_ASSIGN_SUB:
     260             :                                 case ZEND_ASSIGN_MUL:
     261             :                                 case ZEND_ASSIGN_DIV:
     262             :                                 case ZEND_ASSIGN_POW:
     263             :                                 case ZEND_ASSIGN_MOD:
     264             :                                 case ZEND_ASSIGN_SL:
     265             :                                 case ZEND_ASSIGN_SR:
     266             :                                 case ZEND_ASSIGN_CONCAT:
     267             :                                 case ZEND_ASSIGN_BW_OR:
     268             :                                 case ZEND_ASSIGN_BW_AND:
     269             :                                 case ZEND_ASSIGN_BW_XOR:
     270          11 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     271           3 :                                                 if (opline->extended_value == ZEND_ASSIGN_OBJ) {
     272           0 :                                                         optimizer_literal_obj_info(
     273             :                                                                 info,
     274           0 :                                                                 opline->op1_type,
     275             :                                                                 opline->op1,
     276           0 :                                                                 opline->op2.constant,
     277             :                                                                 LITERAL_PROPERTY, 2, 1,
     278             :                                                                 op_array);
     279             :                                                 } else {
     280           3 :                                                         LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
     281             :                                                 }
     282             :                                         }
     283          11 :                                         break;
     284           1 :                                 case ZEND_BIND_GLOBAL:
     285           1 :                                         LITERAL_INFO(opline->op2.constant, LITERAL_GLOBAL, 0, 1, 1);
     286           1 :                                         break;
     287           8 :                                 case ZEND_RECV_INIT:
     288           8 :                                         LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 0, 0, 1);
     289           8 :                                         if (Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) != (uint32_t)-1) {
     290           0 :                                                 Z_CACHE_SLOT(op_array->literals[opline->op2.constant]) = cache_size;
     291           0 :                                                 cache_size += sizeof(void *);
     292             :                                         }
     293           8 :                                         break;
     294          12 :                                 case ZEND_DECLARE_FUNCTION:
     295             :                                 case ZEND_DECLARE_CLASS:
     296             :                                 case ZEND_DECLARE_INHERITED_CLASS:
     297             :                                 case ZEND_DECLARE_INHERITED_CLASS_DELAYED:
     298          12 :                                         LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 0, 0, 2);
     299          12 :                                         break;
     300          55 :                                 case ZEND_RECV:
     301             :                                 case ZEND_RECV_VARIADIC:
     302             :                                 case ZEND_VERIFY_RETURN_TYPE:
     303          55 :                                         if (opline->op2.num != (uint32_t)-1) {
     304           4 :                                                 opline->op2.num = cache_size;
     305           4 :                                                 cache_size += sizeof(void *);
     306             :                                         }
     307             :                                 default:
     308        6593 :                                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     309        2532 :                                                 LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1);
     310             :                                         }
     311        6593 :                                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     312         664 :                                                 LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1);
     313             :                                         }
     314        6593 :                                         break;
     315             :                         }
     316        8126 :                         opline++;
     317             :                 }
     318             : 
     319             : #if DEBUG_COMPACT_LITERALS
     320             :                 {
     321             :                         int i, use_copy;
     322             :                         fprintf(stderr, "File %s func %s\n", op_array->filename->val,
     323             :                                         op_array->function_name ? op_array->function_name->val : "main");
     324             :                         fprintf(stderr, "Literlas table size %d\n", op_array->last_literal);
     325             : 
     326             :                         for (i = 0; i < op_array->last_literal; i++) {
     327             :                                 zval zv;
     328             :                                 ZVAL_COPY_VALUE(&zv, op_array->literals + i);
     329             :                                 use_copy = zend_make_printable_zval(op_array->literals + i, &zv);
     330             :                                 fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
     331             :                                 if (use_copy) {
     332             :                                         zval_dtor(&zv);
     333             :                                 }
     334             :                         }
     335             :                         fflush(stderr);
     336             :                 }
     337             : #endif
     338             : 
     339             :                 /* Merge equal constants */
     340         729 :                 j = 0;
     341         729 :                 zend_hash_init(&hash, op_array->last_literal, NULL, NULL, 0);
     342        1458 :                 map = (int*)zend_arena_alloc(&ctx->arena, op_array->last_literal * sizeof(int));
     343         729 :                 memset(map, 0, op_array->last_literal * sizeof(int));
     344        7336 :                 for (i = 0; i < op_array->last_literal; i++) {
     345        6607 :                         if (!info[i].flags) {
     346             :                                 /* unsed literal */
     347        1752 :                                 zval_dtor(&op_array->literals[i]);
     348        1752 :                                 continue;
     349             :                         }
     350        9710 :                         switch (Z_TYPE(op_array->literals[i])) {
     351         107 :                                 case IS_NULL:
     352             :                                         /* Only checking MAY_MERGE for IS_NULL here
     353             :                                          * is because only IS_NULL can be default value for class type hinting(RECV_INIT). */
     354         107 :                                         if ((info[i].flags & LITERAL_MAY_MERGE)) {
     355         107 :                                                 if (l_null < 0) {
     356          96 :                                                         l_null = j;
     357          96 :                                                         if (i != j) {
     358          21 :                                                                 op_array->literals[j] = op_array->literals[i];
     359          21 :                                                                 info[j] = info[i];
     360             :                                                         }
     361          96 :                                                         j++;
     362             :                                                 }
     363         107 :                                                 map[i] = l_null;
     364             :                                         } else {
     365           0 :                                                 map[i] = j;
     366           0 :                                                 if (i != j) {
     367           0 :                                                         op_array->literals[j] = op_array->literals[i];
     368           0 :                                                         info[j] = info[i];
     369             :                                                 }
     370           0 :                                                 j++;
     371             :                                         }
     372         107 :                                         break;
     373          32 :                                 case IS_FALSE:
     374          32 :                                         if (l_false < 0) {
     375          29 :                                                 l_false = j;
     376          29 :                                                 if (i != j) {
     377          24 :                                                         op_array->literals[j] = op_array->literals[i];
     378          24 :                                                         info[j] = info[i];
     379             :                                                 }
     380          29 :                                                 j++;
     381             :                                         }
     382          32 :                                         map[i] = l_false;
     383          32 :                                         break;
     384          20 :                                 case IS_TRUE:
     385          20 :                                         if (l_true < 0) {
     386          14 :                                                 l_true = j;
     387          14 :                                                 if (i != j) {
     388           8 :                                                         op_array->literals[j] = op_array->literals[i];
     389           8 :                                                         info[j] = info[i];
     390             :                                                 }
     391          14 :                                                 j++;
     392             :                                         }
     393          20 :                                         map[i] = l_true;
     394          20 :                                         break;
     395         969 :                                 case IS_LONG:
     396         969 :                                         if ((pos = zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i]))) != NULL) {
     397         175 :                                                 map[i] = Z_LVAL_P(pos);
     398             :                                         } else {
     399         794 :                                                 map[i] = j;
     400         794 :                                                 ZVAL_LONG(&zv, j);
     401         794 :                                                 zend_hash_index_add_new(&hash, Z_LVAL(op_array->literals[i]), &zv);
     402         794 :                                                 if (i != j) {
     403         477 :                                                         op_array->literals[j] = op_array->literals[i];
     404         477 :                                                         info[j] = info[i];
     405             :                                                 }
     406         794 :                                                 j++;
     407             :                                         }
     408         969 :                                         break;
     409           0 :                                 case IS_DOUBLE:
     410           0 :                                         if ((pos = zend_hash_str_find(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double))) != NULL) {
     411           0 :                                                 map[i] = Z_LVAL_P(pos);
     412             :                                         } else {
     413           0 :                                                 map[i] = j;
     414           0 :                                                 ZVAL_LONG(&zv, j);
     415           0 :                                                 zend_hash_str_add(&hash, (char*)&Z_DVAL(op_array->literals[i]), sizeof(double), &zv);
     416           0 :                                                 if (i != j) {
     417           0 :                                                         op_array->literals[j] = op_array->literals[i];
     418           0 :                                                         info[j] = info[i];
     419             :                                                 }
     420           0 :                                                 j++;
     421             :                                         }
     422           0 :                                         break;
     423        3647 :                                 case IS_STRING:
     424             :                                 case IS_CONSTANT:
     425        3647 :                                         if (info[i].flags & LITERAL_MAY_MERGE) {
     426        3571 :                                                 if (info[i].flags & LITERAL_EX_OBJ) {
     427           2 :                                                         int key_len = sizeof("$this->") - 1 + Z_STRLEN(op_array->literals[i]);
     428           4 :                                                         key = zend_string_alloc(key_len, 0);
     429           2 :                                                         memcpy(ZSTR_VAL(key), "$this->", sizeof("$this->") - 1);
     430           2 :                                                         memcpy(ZSTR_VAL(key) + sizeof("$this->") - 1, Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]) + 1);
     431           2 :                                                         ZSTR_LEN(key) = key_len;
     432        3569 :                                                 } else if (info[i].flags & LITERAL_EX_CLASS) {
     433             :                                                         int key_len;
     434         143 :                                                         zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num];
     435         143 :                                                         key_len = Z_STRLEN_P(class_name) + sizeof("::") - 1 + Z_STRLEN(op_array->literals[i]);
     436         286 :                                                         key = zend_string_alloc(key_len, 0);
     437         143 :                                                         memcpy(ZSTR_VAL(key), Z_STRVAL_P(class_name), Z_STRLEN_P(class_name));
     438         143 :                                                         memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name), "::", sizeof("::") - 1);
     439         286 :                                                         memcpy(ZSTR_VAL(key) + Z_STRLEN_P(class_name) + sizeof("::") - 1,
     440         143 :                                                                 Z_STRVAL(op_array->literals[i]),
     441         143 :                                                                 Z_STRLEN(op_array->literals[i]) + 1);
     442             :                                                 } else {
     443        6852 :                                                         key = zend_string_init(Z_STRVAL(op_array->literals[i]), Z_STRLEN(op_array->literals[i]), 0);
     444             :                                                 }
     445        3571 :                                                 ZSTR_H(key) = zend_hash_func(ZSTR_VAL(key), ZSTR_LEN(key));
     446        3571 :                                                 ZSTR_H(key) += info[i].flags;
     447             :                                         }
     448        4521 :                                         if ((info[i].flags & LITERAL_MAY_MERGE) &&
     449         874 :                                                 (pos = zend_hash_find(&hash, key)) != NULL &&
     450        3496 :                                                 Z_TYPE(op_array->literals[i]) == Z_TYPE(op_array->literals[Z_LVAL_P(pos)]) &&
     451         874 :                                                 info[i].flags == info[Z_LVAL_P(pos)].flags) {
     452             : 
     453             :                                                 zend_string_release(key);
     454         874 :                                                 map[i] = Z_LVAL_P(pos);
     455         874 :                                                 zval_dtor(&op_array->literals[i]);
     456         874 :                                                 n = LITERAL_NUM_RELATED(info[i].flags);
     457        1855 :                                                 while (n > 1) {
     458         107 :                                                         i++;
     459         107 :                                                         zval_dtor(&op_array->literals[i]);
     460         107 :                                                         n--;
     461             :                                                 }
     462             :                                         } else {
     463        2773 :                                                 map[i] = j;
     464        2773 :                                                 if (info[i].flags & LITERAL_MAY_MERGE) {
     465        2697 :                                                         ZVAL_LONG(&zv, j);
     466        2697 :                                                         zend_hash_add_new(&hash, key, &zv);
     467             :                                                         zend_string_release(key);
     468             :                                                 }
     469        2773 :                                                 if (i != j) {
     470        1220 :                                                         op_array->literals[j] = op_array->literals[i];
     471        1220 :                                                         info[j] = info[i];
     472             :                                                 }
     473        2773 :                                                 if (LITERAL_NUM_SLOTS(info[i].flags)) {
     474        1079 :                                                         Z_CACHE_SLOT(op_array->literals[j]) = cache_size;
     475        1079 :                                                         cache_size += LITERAL_NUM_SLOTS(info[i].flags) * sizeof(void*);
     476             :                                                 }
     477        2773 :                                                 j++;
     478        2773 :                                                 n = LITERAL_NUM_RELATED(info[i].flags);
     479        5973 :                                                 while (n > 1) {
     480         427 :                                                         i++;
     481         427 :                                                         if (i != j) op_array->literals[j] = op_array->literals[i];
     482         427 :                                                         j++;
     483         427 :                                                         n--;
     484             :                                                 }
     485             :                                         }
     486        3647 :                                         break;
     487          80 :                                 default:
     488             :                                         /* don't merge other types */
     489          80 :                                         map[i] = j;
     490          80 :                                         if (i != j) {
     491          31 :                                                 op_array->literals[j] = op_array->literals[i];
     492          31 :                                                 info[j] = info[i];
     493             :                                         }
     494          80 :                                         j++;
     495          80 :                                         break;
     496             :                         }
     497             :                 }
     498         729 :                 zend_hash_destroy(&hash);
     499         729 :                 op_array->last_literal = j;
     500         729 :                 op_array->cache_size = cache_size;
     501             : 
     502             :             /* Update opcodes to use new literals table */
     503         729 :                 opline = op_array->opcodes;
     504         729 :                 end = opline + op_array->last;
     505        9584 :                 while (opline < end) {
     506        8126 :                         if (ZEND_OP1_TYPE(opline) == IS_CONST) {
     507        2749 :                                 opline->op1.constant = map[opline->op1.constant];
     508             :                         }
     509        8126 :                         if (ZEND_OP2_TYPE(opline) == IS_CONST) {
     510        2106 :                                 opline->op2.constant = map[opline->op2.constant];
     511             :                         }
     512        8126 :                         opline++;
     513             :                 }
     514         729 :                 zend_arena_release(&ctx->arena, checkpoint);
     515             : 
     516             : #if DEBUG_COMPACT_LITERALS
     517             :                 {
     518             :                         int i, use_copy;
     519             :                         fprintf(stderr, "Optimized literlas table size %d\n", op_array->last_literal);
     520             : 
     521             :                         for (i = 0; i < op_array->last_literal; i++) {
     522             :                                 zval zv;
     523             :                                 ZVAL_COPY_VALUE(&zv, op_array->literals + i);
     524             :                                 use_copy = zend_make_printable_zval(op_array->literals + i, &zv);
     525             :                                 fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv));
     526             :                                 if (use_copy) {
     527             :                                         zval_dtor(&zv);
     528             :                                 }
     529             :                         }
     530             :                         fflush(stderr);
     531             :                 }
     532             : #endif
     533             :         }
     534         729 : }

Generated by: LCOV version 1.10

Generated at Sun, 07 Apr 2019 20:56:52 +0000 (11 days ago)

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