zend_inference.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine, e-SSA based Type & Range Inference |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 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. | https://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@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #ifndef ZEND_INFERENCE_H
  19. #define ZEND_INFERENCE_H
  20. #include "zend_optimizer.h"
  21. #include "zend_ssa.h"
  22. #include "zend_bitset.h"
  23. /* Bitmask for type inference (zend_ssa_var_info.type) */
  24. #include "zend_type_info.h"
  25. #define MAY_BE_PACKED_GUARD (1<<27) /* needs packed array guard */
  26. #define MAY_BE_CLASS_GUARD (1<<27) /* needs class guard */
  27. #define MAY_BE_GUARD (1<<28) /* needs type guard */
  28. //#define MAY_BE_IN_REG (1<<29) /* deprecated and not used */
  29. #define MAY_HAVE_DTOR \
  30. (MAY_BE_OBJECT|MAY_BE_RESOURCE \
  31. |MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE)
  32. #define DEFINE_SSA_OP_HAS_RANGE(opN) \
  33. static zend_always_inline bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  34. { \
  35. if (opline->opN##_type == IS_CONST) { \
  36. zval *zv = CRT_CONSTANT(opline->opN); \
  37. 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); \
  38. } else { \
  39. return (opline->opN##_type != IS_UNUSED && \
  40. ssa->var_info && \
  41. ssa_op->opN##_use >= 0 && \
  42. ssa->var_info[ssa_op->opN##_use].has_range); \
  43. } \
  44. return 0; \
  45. } \
  46. #define DEFINE_SSA_OP_MIN_RANGE(opN) \
  47. static zend_always_inline zend_long _ssa_##opN##_min_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  48. { \
  49. if (opline->opN##_type == IS_CONST) { \
  50. zval *zv = CRT_CONSTANT(opline->opN); \
  51. if (Z_TYPE_P(zv) == IS_LONG) { \
  52. return Z_LVAL_P(zv); \
  53. } else if (Z_TYPE_P(zv) == IS_TRUE) { \
  54. return 1; \
  55. } else if (Z_TYPE_P(zv) == IS_FALSE) { \
  56. return 0; \
  57. } else if (Z_TYPE_P(zv) == IS_NULL) { \
  58. return 0; \
  59. } \
  60. } else if (opline->opN##_type != IS_UNUSED && \
  61. ssa->var_info && \
  62. ssa_op->opN##_use >= 0 && \
  63. ssa->var_info[ssa_op->opN##_use].has_range) { \
  64. return ssa->var_info[ssa_op->opN##_use].range.min; \
  65. } \
  66. return ZEND_LONG_MIN; \
  67. } \
  68. #define DEFINE_SSA_OP_MAX_RANGE(opN) \
  69. static zend_always_inline zend_long _ssa_##opN##_max_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  70. { \
  71. if (opline->opN##_type == IS_CONST) { \
  72. zval *zv = CRT_CONSTANT(opline->opN); \
  73. if (Z_TYPE_P(zv) == IS_LONG) { \
  74. return Z_LVAL_P(zv); \
  75. } else if (Z_TYPE_P(zv) == IS_TRUE) { \
  76. return 1; \
  77. } else if (Z_TYPE_P(zv) == IS_FALSE) { \
  78. return 0; \
  79. } else if (Z_TYPE_P(zv) == IS_NULL) { \
  80. return 0; \
  81. } \
  82. } else if (opline->opN##_type != IS_UNUSED && \
  83. ssa->var_info && \
  84. ssa_op->opN##_use >= 0 && \
  85. ssa->var_info[ssa_op->opN##_use].has_range) { \
  86. return ssa->var_info[ssa_op->opN##_use].range.max; \
  87. } \
  88. return ZEND_LONG_MAX; \
  89. } \
  90. #define DEFINE_SSA_OP_RANGE_UNDERFLOW(opN) \
  91. static zend_always_inline char _ssa_##opN##_range_underflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  92. { \
  93. if (opline->opN##_type == IS_CONST) { \
  94. zval *zv = CRT_CONSTANT(opline->opN); \
  95. 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) { \
  96. return 0; \
  97. } \
  98. } else if (opline->opN##_type != IS_UNUSED && \
  99. ssa->var_info && \
  100. ssa_op->opN##_use >= 0 && \
  101. ssa->var_info[ssa_op->opN##_use].has_range) { \
  102. return ssa->var_info[ssa_op->opN##_use].range.underflow; \
  103. } \
  104. return 1; \
  105. } \
  106. #define DEFINE_SSA_OP_RANGE_OVERFLOW(opN) \
  107. static zend_always_inline char _ssa_##opN##_range_overflow(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  108. { \
  109. if (opline->opN##_type == IS_CONST) { \
  110. zval *zv = CRT_CONSTANT(opline->opN); \
  111. 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) { \
  112. return 0; \
  113. } \
  114. } else if (opline->opN##_type != IS_UNUSED && \
  115. ssa->var_info && \
  116. ssa_op->opN##_use >= 0 && \
  117. ssa->var_info[ssa_op->opN##_use].has_range) { \
  118. return ssa->var_info[ssa_op->opN##_use].range.overflow; \
  119. } \
  120. return 1; \
  121. } \
  122. DEFINE_SSA_OP_HAS_RANGE(op1)
  123. DEFINE_SSA_OP_MIN_RANGE(op1)
  124. DEFINE_SSA_OP_MAX_RANGE(op1)
  125. DEFINE_SSA_OP_RANGE_UNDERFLOW(op1)
  126. DEFINE_SSA_OP_RANGE_OVERFLOW(op1)
  127. DEFINE_SSA_OP_HAS_RANGE(op2)
  128. DEFINE_SSA_OP_MIN_RANGE(op2)
  129. DEFINE_SSA_OP_MAX_RANGE(op2)
  130. DEFINE_SSA_OP_RANGE_UNDERFLOW(op2)
  131. DEFINE_SSA_OP_RANGE_OVERFLOW(op2)
  132. #define OP1_HAS_RANGE() (_ssa_op1_has_range (op_array, ssa, opline, ssa_op))
  133. #define OP1_MIN_RANGE() (_ssa_op1_min_range (op_array, ssa, opline, ssa_op))
  134. #define OP1_MAX_RANGE() (_ssa_op1_max_range (op_array, ssa, opline, ssa_op))
  135. #define OP1_RANGE_UNDERFLOW() (_ssa_op1_range_underflow (op_array, ssa, opline, ssa_op))
  136. #define OP1_RANGE_OVERFLOW() (_ssa_op1_range_overflow (op_array, ssa, opline, ssa_op))
  137. #define OP2_HAS_RANGE() (_ssa_op2_has_range (op_array, ssa, opline, ssa_op))
  138. #define OP2_MIN_RANGE() (_ssa_op2_min_range (op_array, ssa, opline, ssa_op))
  139. #define OP2_MAX_RANGE() (_ssa_op2_max_range (op_array, ssa, opline, ssa_op))
  140. #define OP2_RANGE_UNDERFLOW() (_ssa_op2_range_underflow (op_array, ssa, opline, ssa_op))
  141. #define OP2_RANGE_OVERFLOW() (_ssa_op2_range_overflow (op_array, ssa, opline, ssa_op))
  142. static zend_always_inline uint32_t _const_op_type(const zval *zv) {
  143. if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
  144. return MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY;
  145. } else if (Z_TYPE_P(zv) == IS_ARRAY) {
  146. HashTable *ht = Z_ARRVAL_P(zv);
  147. uint32_t tmp = MAY_BE_ARRAY;
  148. zend_string *str;
  149. zval *val;
  150. if (Z_REFCOUNTED_P(zv)) {
  151. tmp |= MAY_BE_RC1 | MAY_BE_RCN;
  152. } else {
  153. tmp |= MAY_BE_RCN;
  154. }
  155. ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
  156. if (str) {
  157. tmp |= MAY_BE_ARRAY_KEY_STRING;
  158. } else {
  159. tmp |= MAY_BE_ARRAY_KEY_LONG;
  160. }
  161. tmp |= 1 << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
  162. } ZEND_HASH_FOREACH_END();
  163. if (HT_IS_PACKED(ht)) {
  164. tmp &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH);
  165. }
  166. return tmp;
  167. } else {
  168. uint32_t tmp = (1 << Z_TYPE_P(zv));
  169. if (Z_REFCOUNTED_P(zv)) {
  170. tmp |= MAY_BE_RC1 | MAY_BE_RCN;
  171. } else if (Z_TYPE_P(zv) == IS_STRING) {
  172. tmp |= MAY_BE_RCN;
  173. }
  174. return tmp;
  175. }
  176. }
  177. static zend_always_inline uint32_t get_ssa_var_info(const zend_ssa *ssa, int ssa_var_num)
  178. {
  179. if (ssa->var_info && ssa_var_num >= 0) {
  180. return ssa->var_info[ssa_var_num].type;
  181. } else {
  182. return MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_INDIRECT | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF;
  183. }
  184. }
  185. #define DEFINE_SSA_OP_INFO(opN) \
  186. static zend_always_inline uint32_t _ssa_##opN##_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  187. { \
  188. if (opline->opN##_type == IS_CONST) { \
  189. return _const_op_type(CRT_CONSTANT(opline->opN)); \
  190. } else { \
  191. return get_ssa_var_info(ssa, ssa->var_info ? ssa_op->opN##_use : -1); \
  192. } \
  193. } \
  194. #define DEFINE_SSA_OP_DEF_INFO(opN) \
  195. static zend_always_inline uint32_t _ssa_##opN##_def_info(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \
  196. { \
  197. return get_ssa_var_info(ssa, ssa->var_info ? ssa_op->opN##_def : -1); \
  198. } \
  199. DEFINE_SSA_OP_INFO(op1)
  200. DEFINE_SSA_OP_INFO(op2)
  201. DEFINE_SSA_OP_INFO(result)
  202. DEFINE_SSA_OP_DEF_INFO(op1)
  203. DEFINE_SSA_OP_DEF_INFO(op2)
  204. DEFINE_SSA_OP_DEF_INFO(result)
  205. #define OP1_INFO() (_ssa_op1_info(op_array, ssa, opline, ssa_op))
  206. #define OP2_INFO() (_ssa_op2_info(op_array, ssa, opline, ssa_op))
  207. #define OP1_DATA_INFO() (_ssa_op1_info(op_array, ssa, (opline+1), (ssa_op+1)))
  208. #define OP2_DATA_INFO() (_ssa_op2_info(op_array, ssa, (opline+1), (ssa_op+1)))
  209. #define RES_USE_INFO() (_ssa_result_info(op_array, ssa, opline, ssa_op))
  210. #define OP1_DEF_INFO() (_ssa_op1_def_info(op_array, ssa, opline, ssa_op))
  211. #define OP2_DEF_INFO() (_ssa_op2_def_info(op_array, ssa, opline, ssa_op))
  212. #define OP1_DATA_DEF_INFO() (_ssa_op1_def_info(op_array, ssa, (opline+1), (ssa_op+1)))
  213. #define OP2_DATA_DEF_INFO() (_ssa_op2_def_info(op_array, ssa, (opline+1), (ssa_op+1)))
  214. #define RES_INFO() (_ssa_result_def_info(op_array, ssa, opline, ssa_op))
  215. static zend_always_inline bool zend_add_will_overflow(zend_long a, zend_long b) {
  216. return (b > 0 && a > ZEND_LONG_MAX - b)
  217. || (b < 0 && a < ZEND_LONG_MIN - b);
  218. }
  219. static zend_always_inline bool zend_sub_will_overflow(zend_long a, zend_long b) {
  220. return (b > 0 && a < ZEND_LONG_MIN + b)
  221. || (b < 0 && a > ZEND_LONG_MAX + b);
  222. }
  223. BEGIN_EXTERN_C()
  224. ZEND_API int zend_ssa_find_false_dependencies(const zend_op_array *op_array, zend_ssa *ssa);
  225. ZEND_API int zend_ssa_find_sccs(const zend_op_array *op_array, zend_ssa *ssa);
  226. ZEND_API int zend_ssa_inference(zend_arena **raena, const zend_op_array *op_array, const zend_script *script, zend_ssa *ssa, zend_long optimization_level);
  227. ZEND_API uint32_t zend_array_element_type(uint32_t t1, zend_uchar op_type, int write, int insert);
  228. ZEND_API int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp);
  229. ZEND_API uint32_t zend_fetch_arg_info_type(
  230. const zend_script *script, zend_arg_info *arg_info, zend_class_entry **pce);
  231. ZEND_API void zend_init_func_return_info(
  232. const zend_op_array *op_array, const zend_script *script, zend_ssa_var_info *ret);
  233. uint32_t zend_get_return_info_from_signature_only(
  234. const zend_function *func, const zend_script *script,
  235. zend_class_entry **ce, bool *ce_is_instanceof, bool use_tentative_return_info);
  236. ZEND_API int zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, uint32_t t1, uint32_t t2);
  237. ZEND_API int zend_may_throw(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa);
  238. ZEND_API int zend_update_type_info(
  239. const zend_op_array *op_array, zend_ssa *ssa, const zend_script *script,
  240. zend_op *opline, zend_ssa_op *ssa_op, const zend_op **ssa_opcodes,
  241. zend_long optimization_level);
  242. END_EXTERN_C()
  243. #endif /* ZEND_INFERENCE_H */