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_inference.h (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 36 40 90.0 %
Date: 2018-09-10 Functions: 0 0 -
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine, e-SSA based Type & Range Inference                      |
       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             :    +----------------------------------------------------------------------+
      17             : */
      18             : 
      19             : #ifndef ZEND_INFERENCE_H
      20             : #define ZEND_INFERENCE_H
      21             : 
      22             : #include "zend_optimizer.h"
      23             : #include "zend_ssa.h"
      24             : #include "zend_bitset.h"
      25             : 
      26             : /* Bitmask for type inference (zend_ssa_var_info.type) */
      27             : #include "zend_type_info.h"
      28             : 
      29             : #define MAY_BE_IN_REG               (1<<25) /* value allocated in CPU register */
      30             : 
      31             : //TODO: remome MAY_BE_RC1, MAY_BE_RCN???
      32             : #define MAY_BE_RC1                  (1<<27) /* may be non-reference with refcount == 1 */
      33             : #define MAY_BE_RCN                  (1<<28) /* may be non-reference with refcount > 1  */
      34             : 
      35             : 
      36             : #define DEFINE_SSA_OP_HAS_RANGE(opN) \
      37             :         static zend_always_inline zend_bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
      38             :         { \
      39             :                 if (opline->opN##_type == IS_CONST) { \
      40             :                         zval *zv = CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants); \
      41             :                         return (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL); \
      42             :                 } else { \
      43             :                         return (opline->opN##_type != IS_UNUSED && \
      44             :                         ssa->ops && \
      45             :                         ssa->var_info && \
      46             :                         ssa->ops[opline - op_array->opcodes].opN##_use >= 0 && \
      47             :                             ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].has_range); \
      48             :                 } \
      49             :                 return 0; \
      50             :         }
      51             : 
      52             : #define DEFINE_SSA_OP_MIN_RANGE(opN) \
      53             :         static zend_always_inline zend_long _ssa_##opN##_min_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
      54             :         { \
      55             :                 if (opline->opN##_type == IS_CONST) { \
      56             :                         zval *zv = CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants); \
      57             :                         if (Z_TYPE_P(zv) == IS_LONG) { \
      58             :                                 return Z_LVAL_P(zv); \
      59             :                         } else if (Z_TYPE_P(zv) == IS_TRUE) { \
      60             :                                 return 1; \
      61             :                         } else if (Z_TYPE_P(zv) == IS_FALSE) { \
      62             :                                 return 0; \
      63             :                         } else if (Z_TYPE_P(zv) == IS_NULL) { \
      64             :                                 return 0; \
      65             :                         } \
      66             :                 } else if (opline->opN##_type != IS_UNUSED && \
      67             :                     ssa->ops && \
      68             :                     ssa->var_info && \
      69             :                     ssa->ops[opline - op_array->opcodes].opN##_use >= 0 && \
      70             :                     ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].has_range) { \
      71             :                         return ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].range.min; \
      72             :                 } \
      73             :                 return ZEND_LONG_MIN; \
      74             :         }
      75             : 
      76             : #define DEFINE_SSA_OP_MAX_RANGE(opN) \
      77             :         static zend_always_inline zend_long _ssa_##opN##_max_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
      78             :         { \
      79             :                 if (opline->opN##_type == IS_CONST) { \
      80             :                         zval *zv = CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants); \
      81             :                         if (Z_TYPE_P(zv) == IS_LONG) { \
      82             :                                 return Z_LVAL_P(zv); \
      83             :                         } else if (Z_TYPE_P(zv) == IS_TRUE) { \
      84             :                                 return 1; \
      85             :                         } else if (Z_TYPE_P(zv) == IS_FALSE) { \
      86             :                                 return 0; \
      87             :                         } else if (Z_TYPE_P(zv) == IS_NULL) { \
      88             :                                 return 0; \
      89             :                         } \
      90             :                 } else if (opline->opN##_type != IS_UNUSED && \
      91             :                     ssa->ops && \
      92             :                     ssa->var_info && \
      93             :                     ssa->ops[opline - op_array->opcodes].opN##_use >= 0 && \
      94             :                     ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].has_range) { \
      95             :                         return ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].range.max; \
      96             :                 } \
      97             :                 return ZEND_LONG_MAX; \
      98             :         }
      99             : 
     100             : #define DEFINE_SSA_OP_RANGE_UNDERFLOW(opN) \
     101             :         static zend_always_inline char _ssa_##opN##_range_underflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
     102             :         { \
     103             :                 if (opline->opN##_type == IS_CONST) { \
     104             :                         zval *zv = CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants); \
     105             :                         if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
     106             :                                 return 0; \
     107             :                         } \
     108             :                 } else if (opline->opN##_type != IS_UNUSED && \
     109             :                     ssa->ops && \
     110             :                     ssa->var_info && \
     111             :                     ssa->ops[opline - op_array->opcodes].opN##_use >= 0 && \
     112             :                     ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].has_range) { \
     113             :                         return ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].range.underflow; \
     114             :                 } \
     115             :                 return 1; \
     116             :         }
     117             : 
     118             : #define DEFINE_SSA_OP_RANGE_OVERFLOW(opN) \
     119             :         static zend_always_inline char _ssa_##opN##_range_overflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
     120             :         { \
     121             :                 if (opline->opN##_type == IS_CONST) { \
     122             :                         zval *zv = CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants); \
     123             :                         if (Z_TYPE_P(zv) == IS_LONG || Z_TYPE_P(zv) == IS_TRUE || Z_TYPE_P(zv) == IS_FALSE || Z_TYPE_P(zv) == IS_NULL) { \
     124             :                                 return 0; \
     125             :                         } \
     126             :                 } else if (opline->opN##_type != IS_UNUSED && \
     127             :                     ssa->ops && \
     128             :                     ssa->var_info && \
     129             :                     ssa->ops[opline - op_array->opcodes].opN##_use >= 0 && \
     130             :                     ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].has_range) { \
     131             :                         return ssa->var_info[ssa->ops[opline - op_array->opcodes].opN##_use].range.overflow; \
     132             :                 } \
     133             :                 return 1; \
     134             :         }
     135             : 
     136         349 : DEFINE_SSA_OP_HAS_RANGE(op1)
     137         314 : DEFINE_SSA_OP_MIN_RANGE(op1)
     138         314 : DEFINE_SSA_OP_MAX_RANGE(op1)
     139         263 : DEFINE_SSA_OP_RANGE_UNDERFLOW(op1)
     140         255 : DEFINE_SSA_OP_RANGE_OVERFLOW(op1)
     141         658 : DEFINE_SSA_OP_HAS_RANGE(op2)
     142         463 : DEFINE_SSA_OP_MIN_RANGE(op2)
     143         463 : DEFINE_SSA_OP_MAX_RANGE(op2)
     144         290 : DEFINE_SSA_OP_RANGE_UNDERFLOW(op2)
     145         296 : DEFINE_SSA_OP_RANGE_OVERFLOW(op2)
     146             : 
     147             : #define OP1_HAS_RANGE()         (_ssa_op1_has_range (op_array, ssa, opline))
     148             : #define OP1_MIN_RANGE()         (_ssa_op1_min_range (op_array, ssa, opline))
     149             : #define OP1_MAX_RANGE()         (_ssa_op1_max_range (op_array, ssa, opline))
     150             : #define OP1_RANGE_UNDERFLOW()   (_ssa_op1_range_underflow (op_array, ssa, opline))
     151             : #define OP1_RANGE_OVERFLOW()    (_ssa_op1_range_overflow (op_array, ssa, opline))
     152             : #define OP2_HAS_RANGE()         (_ssa_op2_has_range (op_array, ssa, opline))
     153             : #define OP2_MIN_RANGE()         (_ssa_op2_min_range (op_array, ssa, opline))
     154             : #define OP2_MAX_RANGE()         (_ssa_op2_max_range (op_array, ssa, opline))
     155             : #define OP2_RANGE_UNDERFLOW()   (_ssa_op2_range_underflow (op_array, ssa, opline))
     156             : #define OP2_RANGE_OVERFLOW()    (_ssa_op2_range_overflow (op_array, ssa, opline))
     157             : 
     158             : static zend_always_inline uint32_t _const_op_type(const zval *zv) {
     159        3044 :         if (Z_TYPE_P(zv) == IS_CONSTANT) {
     160           0 :                 return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
     161        3044 :         } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
     162           0 :                 return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
     163        3044 :         } else if (Z_TYPE_P(zv) == IS_ARRAY) {
     164          60 :                 HashTable *ht = Z_ARRVAL_P(zv);
     165          60 :                 uint32_t tmp = MAY_BE_ARRAY;
     166             : 
     167          60 :                 if (Z_REFCOUNTED_P(zv)) {
     168          60 :                         tmp |= MAY_BE_RC1 | MAY_BE_RCN;
     169             :                 } else {
     170           0 :                         tmp |= MAY_BE_RCN;
     171             :                 }
     172             :                 zend_string *str;
     173             :                 zval *val;
     174         292 :                 ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
     175         116 :                         if (str) {
     176          41 :                                 tmp |= MAY_BE_ARRAY_KEY_STRING;
     177             :                         } else {
     178          75 :                                 tmp |= MAY_BE_ARRAY_KEY_LONG;
     179             :                         }
     180         116 :                         tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
     181             :                 } ZEND_HASH_FOREACH_END();
     182          60 :                 return tmp;
     183             :         } else {
     184        2984 :                 uint32_t tmp = (1 << Z_TYPE_P(zv));
     185             : 
     186        2984 :                 if (Z_REFCOUNTED_P(zv)) {
     187        1811 :                         tmp |= MAY_BE_RC1 | MAY_BE_RCN;
     188        1173 :                 } else if (Z_TYPE_P(zv) == IS_STRING) {
     189           4 :                         tmp |= MAY_BE_RCN;
     190             :                 }
     191        2984 :                 return tmp;
     192             :         }
     193             : }
     194             : 
     195             : static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa_var_num)
     196             : {
     197        4845 :         if (ssa->var_info && ssa_var_num >= 0) {
     198        3838 :                 return ssa->var_info[ssa_var_num].type;
     199             :         } else {
     200        1007 :                 return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF | MAY_BE_ERROR;
     201             :         }
     202             : }
     203             : 
     204             : #define DEFINE_SSA_OP_INFO(opN) \
     205             :         static zend_always_inline uint32_t _ssa_##opN##_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
     206             :         {                                                                                                                                               \
     207             :                 if (opline->opN##_type == IS_CONST) {                                                        \
     208             :                         return _const_op_type(CRT_CONSTANT_EX(op_array, opline->opN, ssa->rt_constants)); \
     209             :                 } else { \
     210             :                         return get_ssa_var_info(ssa, ssa->ops ? ssa->ops[opline - op_array->opcodes].opN##_use : -1); \
     211             :                 } \
     212             :         }
     213             : 
     214             : #define DEFINE_SSA_OP_DEF_INFO(opN) \
     215             :         static zend_always_inline uint32_t _ssa_##opN##_def_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline) \
     216             :         { \
     217             :                 return get_ssa_var_info(ssa, ssa->ops ? ssa->ops[opline - op_array->opcodes].opN##_def : -1); \
     218             :         }
     219             : 
     220             : 
     221        8340 : DEFINE_SSA_OP_INFO(op1)
     222        4996 : DEFINE_SSA_OP_INFO(op2)
     223           0 : DEFINE_SSA_OP_INFO(result)
     224          64 : DEFINE_SSA_OP_DEF_INFO(op1)
     225             : DEFINE_SSA_OP_DEF_INFO(op2)
     226        1906 : DEFINE_SSA_OP_DEF_INFO(result)
     227             : 
     228             : #define OP1_INFO()              (_ssa_op1_info(op_array, ssa, opline))
     229             : #define OP2_INFO()              (_ssa_op2_info(op_array, ssa, opline))
     230             : #define OP1_DATA_INFO()         (_ssa_op1_info(op_array, ssa, (opline+1)))
     231             : #define OP2_DATA_INFO()         (_ssa_op2_info(op_array, ssa, (opline+1)))
     232             : #define RES_USE_INFO()          (_ssa_result_info(op_array, ssa, opline))
     233             : #define OP1_DEF_INFO()          (_ssa_op1_def_info(op_array, ssa, opline))
     234             : #define OP2_DEF_INFO()          (_ssa_op2_def_info(op_array, ssa, opline))
     235             : #define OP1_DATA_DEF_INFO()     (_ssa_op1_def_info(op_array, ssa, (opline+1)))
     236             : #define OP2_DATA_DEF_INFO()     (_ssa_op2_def_info(op_array, ssa, (opline+1)))
     237             : #define RES_INFO()              (_ssa_result_def_info(op_array, ssa, opline))
     238             : 
     239             : 
     240             : BEGIN_EXTERN_C()
     241             : 
     242             : int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa);
     243             : int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
     244             : int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa);
     245             : 
     246             : uint32_t zend_array_element_type(uint32_t t1, int write, int insert);
     247             : 
     248             : int  zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp);
     249             : void zend_inference_init_range(const zend_op_array *op_array, zend_ssa *ssa, int var, zend_bool underflow, zend_long min, zend_long max, zend_bool overflow);
     250             : int  zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
     251             : int  zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
     252             : void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
     253             : 
     254             : int  zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist);
     255             : 
     256             : void zend_init_func_return_info(const zend_op_array   *op_array,
     257             :                                 const zend_script     *script,
     258             :                                 zend_ssa_var_info     *ret);
     259             : void zend_func_return_info(const zend_op_array   *op_array,
     260             :                            const zend_script     *script,
     261             :                            int                    recursive,
     262             :                            int                    widening,
     263             :                            zend_ssa_var_info     *ret);
     264             : 
     265             : END_EXTERN_C()
     266             : 
     267             : #endif /* ZEND_INFERENCE_H */
     268             : 
     269             : /*
     270             :  * Local variables:
     271             :  * tab-width: 4
     272             :  * c-basic-offset: 4
     273             :  * indent-tabs-mode: t
     274             :  * End:
     275             :  */

Generated by: LCOV version 1.10

Generated at Mon, 10 Sep 2018 14:11:41 +0000 (10 days ago)

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