source: src/router/php7/ext/opcache/Optimizer/zend_inference.h @ 31874

Last change on this file since 31874 was 31874, checked in by brainslayer, 2 months ago

update php

File size: 11.3 KB
Line 
1/*
2   +----------------------------------------------------------------------+
3   | Zend Engine, e-SSA based Type & Range Inference                      |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1998-2017 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
136DEFINE_SSA_OP_HAS_RANGE(op1)
137DEFINE_SSA_OP_MIN_RANGE(op1)
138DEFINE_SSA_OP_MAX_RANGE(op1)
139DEFINE_SSA_OP_RANGE_UNDERFLOW(op1)
140DEFINE_SSA_OP_RANGE_OVERFLOW(op1)
141DEFINE_SSA_OP_HAS_RANGE(op2)
142DEFINE_SSA_OP_MIN_RANGE(op2)
143DEFINE_SSA_OP_MAX_RANGE(op2)
144DEFINE_SSA_OP_RANGE_UNDERFLOW(op2)
145DEFINE_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
158static zend_always_inline uint32_t _const_op_type(const zval *zv) {
159        if (Z_TYPE_P(zv) == IS_CONSTANT) {
160                return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
161        } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
162                return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
163        } else if (Z_TYPE_P(zv) == IS_ARRAY) {
164                HashTable *ht = Z_ARRVAL_P(zv);
165                uint32_t tmp = MAY_BE_ARRAY;
166
167                if (Z_REFCOUNTED_P(zv)) {
168                        tmp |= MAY_BE_RC1 | MAY_BE_RCN;
169                } else {
170                        tmp |= MAY_BE_RCN;
171                }
172                zend_string *str;
173                zval *val;
174                ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
175                        if (str) {
176                                tmp |= MAY_BE_ARRAY_KEY_STRING;
177                        } else {
178                                tmp |= MAY_BE_ARRAY_KEY_LONG;
179                        }
180                        tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
181                } ZEND_HASH_FOREACH_END();
182                return tmp;
183        } else {
184                uint32_t tmp = (1 << Z_TYPE_P(zv));
185
186                if (Z_REFCOUNTED_P(zv)) {
187                        tmp |= MAY_BE_RC1 | MAY_BE_RCN;
188                } else if (Z_TYPE_P(zv) == IS_STRING) {
189                        tmp |= MAY_BE_RCN;
190                }
191                return tmp;
192        }
193}
194
195static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa_var_num)
196{
197        if (ssa->var_info && ssa_var_num >= 0) {
198                return ssa->var_info[ssa_var_num].type;
199        } else {
200                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
221DEFINE_SSA_OP_INFO(op1)
222DEFINE_SSA_OP_INFO(op2)
223DEFINE_SSA_OP_INFO(result)
224DEFINE_SSA_OP_DEF_INFO(op1)
225DEFINE_SSA_OP_DEF_INFO(op2)
226DEFINE_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
240BEGIN_EXTERN_C()
241
242int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa);
243int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
244int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa);
245
246uint32_t zend_array_element_type(uint32_t t1, int write, int insert);
247
248int  zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int var, int widening, int narrowing, zend_ssa_range *tmp);
249void 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);
250int  zend_inference_narrowing_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
251int  zend_inference_widening_meet(zend_ssa_var_info *var_info, zend_ssa_range *r);
252void zend_inference_check_recursive_dependencies(zend_op_array *op_array);
253
254int  zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_bitset worklist);
255
256void zend_init_func_return_info(const zend_op_array   *op_array,
257                                const zend_script     *script,
258                                zend_ssa_var_info     *ret);
259void 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
265END_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 */
Note: See TracBrowser for help on using the repository browser.