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