zend_dfg.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine, DFG - Data Flow Graph |
  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. #include "zend_compile.h"
  19. #include "zend_dfg.h"
  20. static zend_always_inline void _zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
  21. {
  22. uint32_t var_num;
  23. const zend_op *next;
  24. if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  25. var_num = EX_VAR_TO_NUM(opline->op1.var);
  26. if (!zend_bitset_in(def, var_num)) {
  27. zend_bitset_incl(use, var_num);
  28. }
  29. }
  30. if (((opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0
  31. && opline->opcode != ZEND_FE_FETCH_R
  32. && opline->opcode != ZEND_FE_FETCH_RW)
  33. || (opline->op2_type == IS_CV)) {
  34. var_num = EX_VAR_TO_NUM(opline->op2.var);
  35. if (!zend_bitset_in(def, var_num)) {
  36. zend_bitset_incl(use, var_num);
  37. }
  38. }
  39. if ((build_flags & ZEND_SSA_USE_CV_RESULTS)
  40. && opline->result_type == IS_CV
  41. && opline->opcode != ZEND_RECV) {
  42. var_num = EX_VAR_TO_NUM(opline->result.var);
  43. if (!zend_bitset_in(def, var_num)) {
  44. zend_bitset_incl(use, var_num);
  45. }
  46. }
  47. switch (opline->opcode) {
  48. case ZEND_ASSIGN:
  49. if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op2_type == IS_CV) {
  50. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
  51. }
  52. if (opline->op1_type == IS_CV) {
  53. add_op1_def:
  54. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op1.var));
  55. }
  56. break;
  57. case ZEND_ASSIGN_REF:
  58. if (opline->op2_type == IS_CV) {
  59. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
  60. }
  61. if (opline->op1_type == IS_CV) {
  62. goto add_op1_def;
  63. }
  64. break;
  65. case ZEND_ASSIGN_DIM:
  66. case ZEND_ASSIGN_OBJ:
  67. next = opline + 1;
  68. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  69. var_num = EX_VAR_TO_NUM(next->op1.var);
  70. if (!zend_bitset_in(def, var_num)) {
  71. zend_bitset_incl(use, var_num);
  72. }
  73. if (build_flags & ZEND_SSA_RC_INFERENCE && next->op1_type == IS_CV) {
  74. zend_bitset_incl(def, var_num);
  75. }
  76. }
  77. if (opline->op1_type == IS_CV) {
  78. goto add_op1_def;
  79. }
  80. break;
  81. case ZEND_ASSIGN_OBJ_REF:
  82. next = opline + 1;
  83. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  84. var_num = EX_VAR_TO_NUM(next->op1.var);
  85. if (!zend_bitset_in(def, var_num)) {
  86. zend_bitset_incl(use, var_num);
  87. }
  88. if (next->op1_type == IS_CV) {
  89. zend_bitset_incl(def, var_num);
  90. }
  91. }
  92. if (opline->op1_type == IS_CV) {
  93. goto add_op1_def;
  94. }
  95. break;
  96. case ZEND_ASSIGN_STATIC_PROP:
  97. next = opline + 1;
  98. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  99. var_num = EX_VAR_TO_NUM(next->op1.var);
  100. if (!zend_bitset_in(def, var_num)) {
  101. zend_bitset_incl(use, var_num);
  102. }
  103. if ((build_flags & ZEND_SSA_RC_INFERENCE) && next->op1_type == IS_CV) {
  104. zend_bitset_incl(def, var_num);
  105. }
  106. }
  107. break;
  108. case ZEND_ASSIGN_STATIC_PROP_REF:
  109. next = opline + 1;
  110. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  111. var_num = EX_VAR_TO_NUM(next->op1.var);
  112. if (!zend_bitset_in(def, var_num)) {
  113. zend_bitset_incl(use, var_num);
  114. }
  115. if (next->op1_type == IS_CV) {
  116. zend_bitset_incl(def, var_num);
  117. }
  118. }
  119. break;
  120. case ZEND_ASSIGN_STATIC_PROP_OP:
  121. next = opline + 1;
  122. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  123. var_num = EX_VAR_TO_NUM(next->op1.var);
  124. if (!zend_bitset_in(def, var_num)) {
  125. zend_bitset_incl(use, var_num);
  126. }
  127. }
  128. break;
  129. case ZEND_ASSIGN_DIM_OP:
  130. case ZEND_ASSIGN_OBJ_OP:
  131. next = opline + 1;
  132. if (next->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  133. var_num = EX_VAR_TO_NUM(next->op1.var);
  134. if (!zend_bitset_in(def, var_num)) {
  135. zend_bitset_incl(use, var_num);
  136. }
  137. }
  138. if (opline->op1_type == IS_CV) {
  139. goto add_op1_def;
  140. }
  141. break;
  142. case ZEND_ASSIGN_OP:
  143. case ZEND_PRE_INC:
  144. case ZEND_PRE_DEC:
  145. case ZEND_POST_INC:
  146. case ZEND_POST_DEC:
  147. case ZEND_BIND_GLOBAL:
  148. case ZEND_BIND_STATIC:
  149. case ZEND_SEND_VAR_NO_REF:
  150. case ZEND_SEND_VAR_NO_REF_EX:
  151. case ZEND_SEND_VAR_EX:
  152. case ZEND_SEND_FUNC_ARG:
  153. case ZEND_SEND_REF:
  154. case ZEND_SEND_UNPACK:
  155. case ZEND_FE_RESET_RW:
  156. case ZEND_MAKE_REF:
  157. case ZEND_PRE_INC_OBJ:
  158. case ZEND_PRE_DEC_OBJ:
  159. case ZEND_POST_INC_OBJ:
  160. case ZEND_POST_DEC_OBJ:
  161. case ZEND_UNSET_DIM:
  162. case ZEND_UNSET_OBJ:
  163. case ZEND_FETCH_DIM_W:
  164. case ZEND_FETCH_DIM_RW:
  165. case ZEND_FETCH_DIM_FUNC_ARG:
  166. case ZEND_FETCH_DIM_UNSET:
  167. case ZEND_FETCH_LIST_W:
  168. if (opline->op1_type == IS_CV) {
  169. goto add_op1_def;
  170. }
  171. break;
  172. case ZEND_SEND_VAR:
  173. case ZEND_CAST:
  174. case ZEND_QM_ASSIGN:
  175. case ZEND_JMP_SET:
  176. case ZEND_COALESCE:
  177. case ZEND_FE_RESET_R:
  178. if ((build_flags & ZEND_SSA_RC_INFERENCE) && opline->op1_type == IS_CV) {
  179. goto add_op1_def;
  180. }
  181. break;
  182. case ZEND_ADD_ARRAY_UNPACK:
  183. var_num = EX_VAR_TO_NUM(opline->result.var);
  184. if (!zend_bitset_in(def, var_num)) {
  185. zend_bitset_incl(use, var_num);
  186. }
  187. break;
  188. case ZEND_ADD_ARRAY_ELEMENT:
  189. var_num = EX_VAR_TO_NUM(opline->result.var);
  190. if (!zend_bitset_in(def, var_num)) {
  191. zend_bitset_incl(use, var_num);
  192. }
  193. ZEND_FALLTHROUGH;
  194. case ZEND_INIT_ARRAY:
  195. if (((build_flags & ZEND_SSA_RC_INFERENCE)
  196. || (opline->extended_value & ZEND_ARRAY_ELEMENT_REF))
  197. && opline->op1_type == IS_CV) {
  198. goto add_op1_def;
  199. }
  200. break;
  201. case ZEND_YIELD:
  202. if (opline->op1_type == IS_CV
  203. && ((op_array->fn_flags & ZEND_ACC_RETURN_REFERENCE)
  204. || (build_flags & ZEND_SSA_RC_INFERENCE))) {
  205. goto add_op1_def;
  206. }
  207. break;
  208. case ZEND_UNSET_CV:
  209. goto add_op1_def;
  210. case ZEND_VERIFY_RETURN_TYPE:
  211. if (opline->op1_type & (IS_TMP_VAR|IS_VAR|IS_CV)) {
  212. goto add_op1_def;
  213. }
  214. break;
  215. case ZEND_FE_FETCH_R:
  216. case ZEND_FE_FETCH_RW:
  217. #if 0
  218. /* This special case was handled above the switch */
  219. if (opline->op2_type != IS_CV) {
  220. op2_use = -1; /* not used */
  221. }
  222. #endif
  223. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
  224. break;
  225. case ZEND_BIND_LEXICAL:
  226. if ((opline->extended_value & ZEND_BIND_REF) || (build_flags & ZEND_SSA_RC_INFERENCE)) {
  227. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->op2.var));
  228. }
  229. break;
  230. default:
  231. break;
  232. }
  233. if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  234. zend_bitset_incl(def, EX_VAR_TO_NUM(opline->result.var));
  235. }
  236. }
  237. /* }}} */
  238. ZEND_API void zend_dfg_add_use_def_op(const zend_op_array *op_array, const zend_op *opline, uint32_t build_flags, zend_bitset use, zend_bitset def) /* {{{ */
  239. {
  240. _zend_dfg_add_use_def_op(op_array, opline, build_flags, use, def);
  241. }
  242. /* }}} */
  243. int zend_build_dfg(const zend_op_array *op_array, const zend_cfg *cfg, zend_dfg *dfg, uint32_t build_flags) /* {{{ */
  244. {
  245. int set_size;
  246. zend_basic_block *blocks = cfg->blocks;
  247. int blocks_count = cfg->blocks_count;
  248. zend_bitset tmp, def, use, in, out;
  249. int k;
  250. int j;
  251. set_size = dfg->size;
  252. tmp = dfg->tmp;
  253. def = dfg->def;
  254. use = dfg->use;
  255. in = dfg->in;
  256. out = dfg->out;
  257. /* Collect "def" and "use" sets */
  258. for (j = 0; j < blocks_count; j++) {
  259. zend_op *opline, *end;
  260. zend_bitset b_use, b_def;
  261. if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
  262. continue;
  263. }
  264. opline = op_array->opcodes + blocks[j].start;
  265. end = opline + blocks[j].len;
  266. b_use = DFG_BITSET(use, set_size, j);
  267. b_def = DFG_BITSET(def, set_size, j);
  268. for (; opline < end; opline++) {
  269. if (opline->opcode != ZEND_OP_DATA) {
  270. _zend_dfg_add_use_def_op(op_array, opline, build_flags, b_use, b_def);
  271. }
  272. }
  273. }
  274. /* Calculate "in" and "out" sets */
  275. {
  276. uint32_t worklist_len = zend_bitset_len(blocks_count);
  277. zend_bitset worklist;
  278. ALLOCA_FLAG(use_heap);
  279. worklist = ZEND_BITSET_ALLOCA(worklist_len, use_heap);
  280. memset(worklist, 0, worklist_len * ZEND_BITSET_ELM_SIZE);
  281. for (j = 0; j < blocks_count; j++) {
  282. zend_bitset_incl(worklist, j);
  283. }
  284. while (!zend_bitset_empty(worklist, worklist_len)) {
  285. /* We use the last block on the worklist, because predecessors tend to be located
  286. * before the succeeding block, so this converges faster. */
  287. j = zend_bitset_last(worklist, worklist_len);
  288. zend_bitset_excl(worklist, j);
  289. if ((blocks[j].flags & ZEND_BB_REACHABLE) == 0) {
  290. continue;
  291. }
  292. if (blocks[j].successors_count != 0) {
  293. zend_bitset_copy(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[0]), set_size);
  294. for (k = 1; k < blocks[j].successors_count; k++) {
  295. zend_bitset_union(DFG_BITSET(out, set_size, j), DFG_BITSET(in, set_size, blocks[j].successors[k]), set_size);
  296. }
  297. } else {
  298. zend_bitset_clear(DFG_BITSET(out, set_size, j), set_size);
  299. }
  300. 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);
  301. if (!zend_bitset_equal(DFG_BITSET(in, set_size, j), tmp, set_size)) {
  302. zend_bitset_copy(DFG_BITSET(in, set_size, j), tmp, set_size);
  303. /* Add predecessors of changed block to worklist */
  304. {
  305. int *predecessors = &cfg->predecessors[blocks[j].predecessor_offset];
  306. for (k = 0; k < blocks[j].predecessors_count; k++) {
  307. zend_bitset_incl(worklist, predecessors[k]);
  308. }
  309. }
  310. }
  311. }
  312. free_alloca(worklist, use_heap);
  313. }
  314. return SUCCESS;
  315. }
  316. /* }}} */