1 /* 2 +----------------------------------------------------------------------+ 3 | Zend OPcache | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2017 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 22 /* pass 10: 23 * - remove NOPs 24 */ 25 26 #include "php.h" 27 #include "Optimizer/zend_optimizer.h" 28 #include "Optimizer/zend_optimizer_internal.h" 29 #include "zend_API.h" 30 #include "zend_constants.h" 31 #include "zend_execute.h" 32 #include "zend_vm.h" 33 zend_optimizer_nop_removal(zend_op_array * op_array)34void zend_optimizer_nop_removal(zend_op_array *op_array) 35 { 36 zend_op *end, *opline; 37 uint32_t new_count, i, shift; 38 int j; 39 uint32_t *shiftlist; 40 ALLOCA_FLAG(use_heap); 41 42 shiftlist = (uint32_t *)DO_ALLOCA(sizeof(uint32_t) * op_array->last); 43 i = new_count = shift = 0; 44 end = op_array->opcodes + op_array->last; 45 for (opline = op_array->opcodes; opline < end; opline++) { 46 47 /* Kill JMP-over-NOP-s */ 48 if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) { 49 /* check if there are only NOPs under the branch */ 50 zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1; 51 52 while (target->opcode == ZEND_NOP) { 53 target--; 54 } 55 if (target == opline) { 56 /* only NOPs */ 57 opline->opcode = ZEND_NOP; 58 } 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 72 if (shift) { 73 op_array->last = new_count; 74 end = op_array->opcodes + op_array->last; 75 76 /* update JMPs */ 77 for (opline = op_array->opcodes; opline<end; opline++) { 78 switch (opline->opcode) { 79 case ZEND_JMP: 80 case ZEND_FAST_CALL: 81 case ZEND_DECLARE_ANON_CLASS: 82 case ZEND_DECLARE_ANON_INHERITED_CLASS: 83 ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num]; 84 break; 85 case ZEND_JMPZ: 86 case ZEND_JMPNZ: 87 case ZEND_JMPZ_EX: 88 case ZEND_JMPNZ_EX: 89 case ZEND_FE_RESET_R: 90 case ZEND_FE_RESET_RW: 91 case ZEND_NEW: 92 case ZEND_JMP_SET: 93 case ZEND_COALESCE: 94 case ZEND_ASSERT_CHECK: 95 ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; 96 break; 97 case ZEND_FE_FETCH_R: 98 case ZEND_FE_FETCH_RW: 99 opline->extended_value -= shiftlist[opline->extended_value]; 100 break; 101 case ZEND_JMPZNZ: 102 ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; 103 opline->extended_value -= shiftlist[opline->extended_value]; 104 break; 105 case ZEND_CATCH: 106 opline->extended_value -= shiftlist[opline->extended_value]; 107 break; 108 } 109 } 110 111 /* update brk/cont array */ 112 for (j = 0; j < op_array->last_brk_cont; j++) { 113 op_array->brk_cont_array[j].brk -= shiftlist[op_array->brk_cont_array[j].brk]; 114 op_array->brk_cont_array[j].cont -= shiftlist[op_array->brk_cont_array[j].cont]; 115 op_array->brk_cont_array[j].start -= shiftlist[op_array->brk_cont_array[j].start]; 116 } 117 118 /* update try/catch array */ 119 for (j = 0; j < op_array->last_try_catch; j++) { 120 op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; 121 op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; 122 if (op_array->try_catch_array[j].finally_op) { 123 op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; 124 op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; 125 } 126 } 127 128 /* update early binding list */ 129 if (op_array->early_binding != (uint32_t)-1) { 130 uint32_t *opline_num = &op_array->early_binding; 131 132 do { 133 *opline_num -= shiftlist[*opline_num]; 134 opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num; 135 } while (*opline_num != (uint32_t)-1); 136 } 137 } 138 FREE_ALLOCA(shiftlist); 139 } 140