You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.8 KiB

  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2014 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: Andi Gutmans <andi@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@zend.com> |
  19. +----------------------------------------------------------------------+
  20. */
  21. /* pass 10:
  22. * - remove NOPs
  23. */
  24. #include "php.h"
  25. #include "Optimizer/zend_optimizer.h"
  26. #include "Optimizer/zend_optimizer_internal.h"
  27. #include "zend_API.h"
  28. #include "zend_constants.h"
  29. #include "zend_execute.h"
  30. #include "zend_vm.h"
  31. void zend_optimizer_nop_removal(zend_op_array *op_array)
  32. {
  33. zend_op *end, *opline;
  34. uint32_t new_count, i, shift;
  35. int j;
  36. uint32_t *shiftlist;
  37. ALLOCA_FLAG(use_heap);
  38. shiftlist = (uint32_t *)DO_ALLOCA(sizeof(uint32_t) * op_array->last);
  39. i = new_count = shift = 0;
  40. end = op_array->opcodes + op_array->last;
  41. for (opline = op_array->opcodes; opline < end; opline++) {
  42. /* GOTO target is unresolved yet. We can't optimize. */
  43. if (opline->opcode == ZEND_GOTO &&
  44. Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) {
  45. /* TODO: in general we can avoid this restriction */
  46. FREE_ALLOCA(shiftlist);
  47. return;
  48. }
  49. /* Kill JMP-over-NOP-s */
  50. if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) {
  51. /* check if there are only NOPs under the branch */
  52. zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1;
  53. while (target->opcode == ZEND_NOP) {
  54. target--;
  55. }
  56. if (target == opline) {
  57. /* only NOPs */
  58. opline->opcode = ZEND_NOP;
  59. }
  60. }
  61. shiftlist[i++] = shift;
  62. if (opline->opcode == ZEND_NOP) {
  63. shift++;
  64. } else {
  65. if (shift) {
  66. op_array->opcodes[new_count] = *opline;
  67. }
  68. new_count++;
  69. }
  70. }
  71. if (shift) {
  72. op_array->last = new_count;
  73. end = op_array->opcodes + op_array->last;
  74. /* update JMPs */
  75. for (opline = op_array->opcodes; opline<end; opline++) {
  76. switch (opline->opcode) {
  77. case ZEND_JMP:
  78. case ZEND_GOTO:
  79. case ZEND_FAST_CALL:
  80. ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num];
  81. break;
  82. case ZEND_JMPZ:
  83. case ZEND_JMPNZ:
  84. case ZEND_JMPZ_EX:
  85. case ZEND_JMPNZ_EX:
  86. case ZEND_FE_FETCH:
  87. case ZEND_FE_RESET:
  88. case ZEND_NEW:
  89. case ZEND_JMP_SET:
  90. case ZEND_JMP_SET_VAR:
  91. ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
  92. break;
  93. case ZEND_JMPZNZ:
  94. ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num];
  95. opline->extended_value -= shiftlist[opline->extended_value];
  96. break;
  97. case ZEND_CATCH:
  98. opline->extended_value -= shiftlist[opline->extended_value];
  99. break;
  100. }
  101. }
  102. /* update brk/cont array */
  103. for (j = 0; j < op_array->last_brk_cont; j++) {
  104. op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk];
  105. op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont];
  106. op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start];
  107. }
  108. /* update try/catch array */
  109. for (j = 0; j < op_array->last_try_catch; j++) {
  110. op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op];
  111. op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op];
  112. if (op_array->try_catch_array[j].finally_op) {
  113. op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op];
  114. op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
  115. }
  116. }
  117. /* update early binding list */
  118. if (op_array->early_binding != (uint32_t)-1) {
  119. uint32_t *opline_num = &op_array->early_binding;
  120. do {
  121. *opline_num -= shiftlist[*opline_num];
  122. opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num;
  123. } while (*opline_num != (uint32_t)-1);
  124. }
  125. }
  126. FREE_ALLOCA(shiftlist);
  127. }