zend_dfg.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine, DFG - Data Flow Graph |
  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@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "php.h"
  19. #include "zend_compile.h"
  20. #include "zend_dfg.h"
  21. int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags) /* {{{ */
  22. {
  23. int set_size;
  24. zend_basic_block *blocks = cfg->blocks;
  25. int blocks_count = cfg->blocks_count;
  26. zend_bitset tmp, def, use, in, out;
  27. int k;
  28. uint32_t var_num;
  29. int j;
  30. set_size = dfg->size;
  31. tmp = dfg->tmp;
  32. def = dfg->def;
  33. use = dfg->use;
  34. in = dfg->in;
  35. out = dfg->out;
  36. /* Collect "def" and "use" sets */
  37. for (j = 0; j < blocks_count; j++) {
  38. zend_op *opline, *end;
  39. if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
  40. continue;
  41. }
  42. opline = op_array->opcodes + blocks[j].start;
  43. end = opline + blocks[j].len;
  44. for (; opline < end; opline++) {
  45. if (opline->opcode != ZEND_OP_DATA) {
  46. zend_op *next = opline + 1;
  47. if (next < end && next->opcode == ZEND_OP_DATA) {
  48. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  49. var_num = EX_VAR_TO_NUM(next->op1.var);
  50. if (!DFG_ISSET(def, set_size, j, var_num)) {
  51. DFG_SET(use, set_size, j, var_num);
  52. }
  53. }
  54. if (next->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  55. var_num = EX_VAR_TO_NUM(next->op2.var);
  56. if (!DFG_ISSET(def, set_size, j, var_num)) {
  57. DFG_SET(use, set_size, j, var_num);
  58. }
  59. }
  60. }
  61. if (opline->op1_type == IS_CV) {
  62. var_num = EX_VAR_TO_NUM(opline->op1.var);
  63. switch (opline->opcode) {
  64. case ZEND_ADD_ARRAY_ELEMENT:
  65. case ZEND_INIT_ARRAY:
  66. if ((build_flags & ZEND_SSA_RC_INFERENCE)
  67. || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF)) {
  68. goto op1_def;
  69. }
  70. goto op1_use;
  71. case ZEND_FE_RESET_R:
  72. case ZEND_SEND_VAR:
  73. case ZEND_CAST:
  74. case ZEND_QM_ASSIGN:
  75. case ZEND_JMP_SET:
  76. case ZEND_COALESCE:
  77. if (build_flags & ZEND_SSA_RC_INFERENCE) {
  78. goto op1_def;
  79. }
  80. goto op1_use;
  81. case ZEND_YIELD:
  82. if ((build_flags & ZEND_SSA_RC_INFERENCE)
  83. || (op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
  84. goto op1_def;
  85. }
  86. goto op1_use;
  87. case ZEND_UNSET_CV:
  88. case ZEND_ASSIGN:
  89. case ZEND_ASSIGN_REF:
  90. case ZEND_BIND_GLOBAL:
  91. case ZEND_BIND_STATIC:
  92. case ZEND_SEND_VAR_EX:
  93. case ZEND_SEND_FUNC_ARG:
  94. case ZEND_SEND_REF:
  95. case ZEND_SEND_VAR_NO_REF:
  96. case ZEND_SEND_VAR_NO_REF_EX:
  97. case ZEND_FE_RESET_RW:
  98. case ZEND_ASSIGN_ADD:
  99. case ZEND_ASSIGN_SUB:
  100. case ZEND_ASSIGN_MUL:
  101. case ZEND_ASSIGN_DIV:
  102. case ZEND_ASSIGN_MOD:
  103. case ZEND_ASSIGN_SL:
  104. case ZEND_ASSIGN_SR:
  105. case ZEND_ASSIGN_CONCAT:
  106. case ZEND_ASSIGN_BW_OR:
  107. case ZEND_ASSIGN_BW_AND:
  108. case ZEND_ASSIGN_BW_XOR:
  109. case ZEND_ASSIGN_POW:
  110. case ZEND_PRE_INC:
  111. case ZEND_PRE_DEC:
  112. case ZEND_POST_INC:
  113. case ZEND_POST_DEC:
  114. case ZEND_ASSIGN_DIM:
  115. case ZEND_ASSIGN_OBJ:
  116. case ZEND_UNSET_DIM:
  117. case ZEND_UNSET_OBJ:
  118. case ZEND_FETCH_DIM_W:
  119. case ZEND_FETCH_DIM_RW:
  120. case ZEND_FETCH_DIM_FUNC_ARG:
  121. case ZEND_FETCH_DIM_UNSET:
  122. case ZEND_FETCH_OBJ_W:
  123. case ZEND_FETCH_OBJ_RW:
  124. case ZEND_FETCH_OBJ_FUNC_ARG:
  125. case ZEND_FETCH_OBJ_UNSET:
  126. case ZEND_FETCH_LIST_W:
  127. case ZEND_VERIFY_RETURN_TYPE:
  128. case ZEND_PRE_INC_OBJ:
  129. case ZEND_PRE_DEC_OBJ:
  130. case ZEND_POST_INC_OBJ:
  131. case ZEND_POST_DEC_OBJ:
  132. op1_def:
  133. /* `def` always come along with dtor or separation,
  134. * thus the origin var info might be also `use`d in the feature(CG) */
  135. DFG_SET(use, set_size, j, var_num);
  136. DFG_SET(def, set_size, j, var_num);
  137. break;
  138. default:
  139. op1_use:
  140. if (!DFG_ISSET(def, set_size, j, var_num)) {
  141. DFG_SET(use, set_size, j, var_num);
  142. }
  143. }
  144. } else if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) {
  145. var_num = EX_VAR_TO_NUM(opline->op1.var);
  146. if (!DFG_ISSET(def, set_size, j, var_num)) {
  147. DFG_SET(use, set_size, j, var_num);
  148. }
  149. if (opline->opcode == ZEND_VERIFY_RETURN_TYPE) {
  150. DFG_SET(def, set_size, j, var_num);
  151. }
  152. }
  153. if (opline->op2_type == IS_CV) {
  154. var_num = EX_VAR_TO_NUM(opline->op2.var);
  155. switch (opline->opcode) {
  156. case ZEND_ASSIGN:
  157. if (build_flags & ZEND_SSA_RC_INFERENCE) {
  158. goto op2_def;
  159. }
  160. goto op2_use;
  161. case ZEND_BIND_LEXICAL:
  162. if ((build_flags & ZEND_SSA_RC_INFERENCE) || (opline->extended_value & ZEND_BIND_REF)) {
  163. goto op2_def;
  164. }
  165. goto op2_use;
  166. case ZEND_ASSIGN_REF:
  167. case ZEND_FE_FETCH_R:
  168. case ZEND_FE_FETCH_RW:
  169. op2_def:
  170. // FIXME: include into "use" too ...?
  171. DFG_SET(use, set_size, j, var_num);
  172. DFG_SET(def, set_size, j, var_num);
  173. break;
  174. default:
  175. op2_use:
  176. if (!DFG_ISSET(def, set_size, j, var_num)) {
  177. DFG_SET(use, set_size, j, var_num);
  178. }
  179. break;
  180. }
  181. } else if (opline->op2_type & (IS_VAR|IS_TMP_VAR)) {
  182. var_num = EX_VAR_TO_NUM(opline->op2.var);
  183. if (opline->opcode == ZEND_FE_FETCH_R || opline->opcode == ZEND_FE_FETCH_RW) {
  184. DFG_SET(def, set_size, j, var_num);
  185. } else {
  186. if (!DFG_ISSET(def, set_size, j, var_num)) {
  187. DFG_SET(use, set_size, j, var_num);
  188. }
  189. }
  190. }
  191. if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  192. var_num = EX_VAR_TO_NUM(opline->result.var);
  193. if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
  194. && opline->result_type == IS_CV) {
  195. DFG_SET(use, set_size, j, var_num);
  196. }
  197. DFG_SET(def, set_size, j, var_num);
  198. }
  199. }
  200. }
  201. }
  202. /* Calculate "in" and "out" sets */
  203. {
  204. uint32_t worklist_len = zend_bitset_len(blocks_count);
  205. zend_bitset worklist;
  206. ALLOCA_FLAG(use_heap);
  207. worklist = ZEND_BITSET_ALLOCA(worklist_len, use_heap);
  208. memset(worklist, 0, worklist_len * ZEND_BITSET_ELM_SIZE);
  209. for (j = 0; j < blocks_count; j++) {
  210. zend_bitset_incl(worklist, j);
  211. }
  212. while (!zend_bitset_empty(worklist, worklist_len)) {
  213. /* We use the last block on the worklist, because predecessors tend to be located
  214. * before the succeeding block, so this converges faster. */
  215. j = zend_bitset_last(worklist, worklist_len);
  216. zend_bitset_excl(worklist, j);
  217. if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
  218. continue;
  219. }
  220. if (blocks[j].successors_count != 0) {
  221. zend_bitset_copy(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[0]), set_size);
  222. for (k = 1; k < blocks[j].successors_count; k++) {
  223. zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[k]), set_size);
  224. }
  225. } else {
  226. zend_bitset_clear(DFG_BITSET(out, set_size, j), set_size);
  227. }
  228. zend_bitset_union_with_difference(tmp, DFG_BITSET(use, set_size, j), DFG_BITSET(out, set_size, j), DFG_BITSET(def, set_size, j), set_size);
  229. if (!zend_bitset_equal(DFG_BITSET(in, set_size, j), tmp, set_size)) {
  230. zend_bitset_copy(DFG_BITSET(in, set_size, j), tmp, set_size);
  231. /* Add predecessors of changed block to worklist */
  232. {
  233. int *predecessors = &cfg->predecessors[blocks[j].predecessor_offset];
  234. for (k = 0; k < blocks[j].predecessors_count; k++) {
  235. zend_bitset_incl(worklist, predecessors[k]);
  236. }
  237. }
  238. }
  239. }
  240. free_alloca(worklist, use_heap);
  241. }
  242. return SUCCESS;
  243. }
  244. /* }}} */
  245. /*
  246. * Local variables:
  247. * tab-width: 4
  248. * c-basic-offset: 4
  249. * indent-tabs-mode: t
  250. * End:
  251. */