void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var) { if (op_array->last_live_range) { int i = 0; int j = 0; uint32_t *map; ALLOCA_FLAG(use_heap); map = (uint32_t *)DO_ALLOCA(sizeof(uint32_t) * op_array->last_live_range); do { if (op_array->opcodes[op_array->live_range[i].end].op1.var != var) { map[i] = j; if (i != j) { op_array->live_range[j] = op_array->live_range[i]; } j++; } i++; } while (i < op_array->last_live_range); if (i != j) { zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; op_array->last_live_range = j; while (opline != end) { if ((opline->opcode == ZEND_FREE || opline->opcode == ZEND_FE_FREE) && opline->extended_value == ZEND_FREE_ON_RETURN) { opline->op2.num = map[opline->op2.num]; } opline++; } } } }
void zend_optimizer_nop_removal(zend_op_array *op_array) { zend_op *end, *opline; uint32_t new_count, i, shift; int j; uint32_t *shiftlist; ALLOCA_FLAG(use_heap); shiftlist = (uint32_t *)DO_ALLOCA(sizeof(uint32_t) * op_array->last); i = new_count = shift = 0; end = op_array->opcodes + op_array->last; for (opline = op_array->opcodes; opline < end; opline++) { /* Kill JMP-over-NOP-s */ if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) { /* check if there are only NOPs under the branch */ zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1; while (target->opcode == ZEND_NOP) { target--; } if (target == opline) { /* only NOPs */ opline->opcode = ZEND_NOP; } } shiftlist[i++] = shift; if (opline->opcode == ZEND_NOP) { shift++; } else { if (shift) { op_array->opcodes[new_count] = *opline; } new_count++; } } if (shift) { op_array->last = new_count; end = op_array->opcodes + op_array->last; /* update JMPs */ for (opline = op_array->opcodes; opline<end; opline++) { switch (opline->opcode) { case ZEND_JMP: case ZEND_FAST_CALL: case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num]; break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: case ZEND_NEW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; break; case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: opline->extended_value -= shiftlist[opline->extended_value]; break; case ZEND_JMPZNZ: ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; opline->extended_value -= shiftlist[opline->extended_value]; break; case ZEND_CATCH: opline->extended_value -= shiftlist[opline->extended_value]; break; } } /* update try/catch array */ for (j = 0; j < op_array->last_try_catch; j++) { op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; if (op_array->try_catch_array[j].finally_op) { op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; } } /* update early binding list */ if (op_array->early_binding != (uint32_t)-1) { uint32_t *opline_num = &op_array->early_binding; do { *opline_num -= shiftlist[*opline_num]; opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num; } while (*opline_num != (uint32_t)-1); } } FREE_ALLOCA(shiftlist); }
static void nop_removal(zend_op_array *op_array) { zend_op *end, *opline; zend_uint new_count, i, shift; int j; zend_uint *shiftlist; ALLOCA_FLAG(use_heap); shiftlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint) * op_array->last); i = new_count = shift = 0; end = op_array->opcodes+op_array->last; for (opline = op_array->opcodes; opline < end; opline++) { #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO /* GOTO target is unresolved yet. We can't optimize. */ if (opline->opcode == ZEND_GOTO && Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_LONG) { /* TODO: in general we can avoid this restriction */ FREE_ALLOCA(shiftlist); return; } #endif /* Kill JMP-over-NOP-s */ if (opline->opcode == ZEND_JMP && ZEND_OP1(opline).opline_num > i) { /* check if there are only NOPs under the branch */ zend_op *target = op_array->opcodes + ZEND_OP1(opline).opline_num - 1; while (target->opcode == ZEND_NOP) { target--; } if (target == opline) { /* only NOPs */ opline->opcode = ZEND_NOP; } } shiftlist[i++] = shift; if (opline->opcode == ZEND_NOP) { shift++; } else { if (shift) { op_array->opcodes[new_count] = *opline; } new_count++; } } if (shift) { op_array->last = new_count; end = op_array->opcodes + op_array->last; /* update JMPs */ for (opline = op_array->opcodes; opline<end; opline++) { switch (opline->opcode) { case ZEND_JMP: #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO case ZEND_GOTO: #endif #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO case ZEND_FAST_CALL: #endif ZEND_OP1(opline).opline_num -= shiftlist[ZEND_OP1(opline).opline_num]; break; case ZEND_JMPZ: case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: case ZEND_FE_FETCH: case ZEND_FE_RESET: case ZEND_NEW: #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO case ZEND_JMP_SET: #endif #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO case ZEND_JMP_SET_VAR: #endif ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; break; case ZEND_JMPZNZ: ZEND_OP2(opline).opline_num -= shiftlist[ZEND_OP2(opline).opline_num]; opline->extended_value -= shiftlist[opline->extended_value]; break; case ZEND_CATCH: opline->extended_value -= shiftlist[opline->extended_value]; break; } } /* update brk/cont array */ for (i=0; i<op_array->last_brk_cont; i++) { op_array->brk_cont_array[i].brk -= shiftlist[op_array->brk_cont_array[i].brk]; op_array->brk_cont_array[i].cont -= shiftlist[op_array->brk_cont_array[i].cont]; op_array->brk_cont_array[i].start -= shiftlist[op_array->brk_cont_array[i].start]; } /* update try/catch array */ for (j=0; j<op_array->last_try_catch; j++) { op_array->try_catch_array[j].try_op -= shiftlist[op_array->try_catch_array[j].try_op]; op_array->try_catch_array[j].catch_op -= shiftlist[op_array->try_catch_array[j].catch_op]; #if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO if (op_array->try_catch_array[j].finally_op) { op_array->try_catch_array[j].finally_op -= shiftlist[op_array->try_catch_array[j].finally_op]; op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; } #endif } #if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO /* update early binding list */ if (op_array->early_binding != -1) { zend_uint *opline_num = &op_array->early_binding; do { *opline_num -= shiftlist[*opline_num]; opline_num = &ZEND_RESULT(&op_array->opcodes[*opline_num]).opline_num; } while (*opline_num != -1); } #endif } FREE_ALLOCA(shiftlist); }
if (jmp_hitlist[i] == ZEND_OP2(&op_array->opcodes[target]).opline_num) { \ goto label; \ } \ } \ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2(&op_array->opcodes[target]).opline_num; if (ZEND_OPTIMIZER_PASS_3 & OPTIMIZATION_LEVEL) { zend_op *opline; zend_op *end = op_array->opcodes + op_array->last; zend_uint *jmp_hitlist; int jmp_hitlist_count; int i; zend_uint opline_num = 0; ALLOCA_FLAG(use_heap); jmp_hitlist = (zend_uint *)DO_ALLOCA(sizeof(zend_uint)*op_array->last); opline = op_array->opcodes; while (opline < end) { jmp_hitlist_count = 0; switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_CONCAT: case ZEND_SL: case ZEND_SR: case ZEND_BW_OR:
goto label; \ } \ } \ jmp_hitlist[jmp_hitlist_count++] = ZEND_OP2(&op_array->opcodes[target]).opline_num; void zend_optimizer_pass3(zend_op_array *op_array TSRMLS_DC) { zend_op *opline; zend_op *end = op_array->opcodes + op_array->last; uint32_t *jmp_hitlist; int jmp_hitlist_count; int i; uint32_t opline_num = 0; ALLOCA_FLAG(use_heap); jmp_hitlist = (uint32_t *)DO_ALLOCA(sizeof(uint32_t)*op_array->last); opline = op_array->opcodes; while (opline < end) { jmp_hitlist_count = 0; switch (opline->opcode) { case ZEND_ADD: case ZEND_SUB: case ZEND_MUL: case ZEND_DIV: case ZEND_MOD: case ZEND_POW: case ZEND_CONCAT: case ZEND_SL: case ZEND_SR: