compact_vars.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine, Removing unused variables |
  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: Nikita Popov <nikic@php.net> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include "ZendAccelerator.h"
  19. #include "Optimizer/zend_optimizer_internal.h"
  20. #include "zend_bitset.h"
  21. /* This pass removes all CVs and temporaries that are completely unused. It does *not* merge any CVs or TMPs.
  22. * This pass does not operate on SSA form anymore. */
  23. void zend_optimizer_compact_vars(zend_op_array *op_array) {
  24. int i;
  25. ALLOCA_FLAG(use_heap1);
  26. ALLOCA_FLAG(use_heap2);
  27. uint32_t used_vars_len = zend_bitset_len(op_array->last_var + op_array->T);
  28. zend_bitset used_vars = ZEND_BITSET_ALLOCA(used_vars_len, use_heap1);
  29. uint32_t *vars_map = do_alloca((op_array->last_var + op_array->T) * sizeof(uint32_t), use_heap2);
  30. uint32_t num_cvs, num_tmps;
  31. /* Determine which CVs are used */
  32. zend_bitset_clear(used_vars, used_vars_len);
  33. for (i = 0; i < op_array->last; i++) {
  34. zend_op *opline = &op_array->opcodes[i];
  35. if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  36. zend_bitset_incl(used_vars, VAR_NUM(opline->op1.var));
  37. }
  38. if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  39. zend_bitset_incl(used_vars, VAR_NUM(opline->op2.var));
  40. }
  41. if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  42. zend_bitset_incl(used_vars, VAR_NUM(opline->result.var));
  43. if (opline->opcode == ZEND_ROPE_INIT) {
  44. uint32_t num = ((opline->extended_value * sizeof(zend_string*)) + (sizeof(zval) - 1)) / sizeof(zval);
  45. while (num > 1) {
  46. num--;
  47. zend_bitset_incl(used_vars, VAR_NUM(opline->result.var) + num);
  48. }
  49. }
  50. }
  51. }
  52. num_cvs = 0;
  53. for (i = 0; i < op_array->last_var; i++) {
  54. if (zend_bitset_in(used_vars, i)) {
  55. vars_map[i] = num_cvs++;
  56. } else {
  57. vars_map[i] = (uint32_t) -1;
  58. }
  59. }
  60. num_tmps = 0;
  61. for (i = op_array->last_var; i < op_array->last_var + op_array->T; i++) {
  62. if (zend_bitset_in(used_vars, i)) {
  63. vars_map[i] = num_cvs + num_tmps++;
  64. } else {
  65. vars_map[i] = (uint32_t) -1;
  66. }
  67. }
  68. free_alloca(used_vars, use_heap1);
  69. if (num_cvs == op_array->last_var && num_tmps == op_array->T) {
  70. free_alloca(vars_map, use_heap2);
  71. return;
  72. }
  73. ZEND_ASSERT(num_cvs <= op_array->last_var);
  74. ZEND_ASSERT(num_tmps <= op_array->T);
  75. /* Update CV and TMP references in opcodes */
  76. for (i = 0; i < op_array->last; i++) {
  77. zend_op *opline = &op_array->opcodes[i];
  78. if (opline->op1_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  79. opline->op1.var = NUM_VAR(vars_map[VAR_NUM(opline->op1.var)]);
  80. }
  81. if (opline->op2_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  82. opline->op2.var = NUM_VAR(vars_map[VAR_NUM(opline->op2.var)]);
  83. }
  84. if (opline->result_type & (IS_CV|IS_VAR|IS_TMP_VAR)) {
  85. opline->result.var = NUM_VAR(vars_map[VAR_NUM(opline->result.var)]);
  86. }
  87. }
  88. /* Update TMP references in live ranges */
  89. if (op_array->live_range) {
  90. for (i = 0; i < op_array->last_live_range; i++) {
  91. op_array->live_range[i].var =
  92. (op_array->live_range[i].var & ZEND_LIVE_MASK) |
  93. NUM_VAR(vars_map[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK)]);
  94. }
  95. }
  96. /* Update CV name table */
  97. if (num_cvs != op_array->last_var) {
  98. if (num_cvs) {
  99. zend_string **names = safe_emalloc(sizeof(zend_string *), num_cvs, 0);
  100. for (i = 0; i < op_array->last_var; i++) {
  101. if (vars_map[i] != (uint32_t) -1) {
  102. names[vars_map[i]] = op_array->vars[i];
  103. } else {
  104. zend_string_release_ex(op_array->vars[i], 0);
  105. }
  106. }
  107. efree(op_array->vars);
  108. op_array->vars = names;
  109. } else {
  110. for (i = 0; i < op_array->last_var; i++) {
  111. zend_string_release_ex(op_array->vars[i], 0);
  112. }
  113. efree(op_array->vars);
  114. op_array->vars = NULL;
  115. }
  116. op_array->last_var = num_cvs;
  117. }
  118. op_array->T = num_tmps;
  119. free_alloca(vars_map, use_heap2);
  120. }