/** * Called when the peephole optimizer is finished with an instruction. This method will pass the * instruction through to the next IMethodBodyVisitor, and call any needed labeling methods. * * @param info The InstructionInfo that the optimizer is done with */ private void finishInstruction(InstructionInfo info) { finisher.visitInstruction(info.getInstruction()); for (Label l : info.getLabelCurrents()) { finisher.labelCurrent(l); } for (Label l : info.getLabelNexts()) { finisher.labelNext(l); } }
/** * Delete the previous instruction(s), from the end of the peephole window up to i. Must not be * called with an index that falls outside of the peephole window. * * @param i the index of the previous instruction to replace. Follows the same indexing strategy * as the previous() method 0 is the last instruction in the window, 1 is two instructions * ago, up to PEEPHOLE_WINDOW_SIZE-1 which is the oldest instruction that can be replaced. */ private void delete(int i) { int size = instructions.size(); int idx = i + 1; if (size >= idx) { int realIdx = size - idx; assert !indexBeforeLabel(realIdx) : "Attempting to delete instruction sequence that spans a label"; List<Label> labels = null; for (int r = size - 1; r >= realIdx; --r) { InstructionInfo temp = instructions.remove(r); if (r == size - 1) { // Save any label nexts from the last deleted instruction List<Label> labelNexts = temp.getLabelNexts(); if (!labelNexts.isEmpty()) { if (labels == null) labels = new ArrayList<Label>(); labels.addAll(labelNexts); } } else if (r == realIdx) { // save any label currents from the first deleted instruction List<Label> labelCurrents = temp.getLabelCurrents(); if (!labelCurrents.isEmpty()) { if (labels == null) labels = new ArrayList<Label>(); labels.addAll(labelCurrents); } } } if (labels != null) { if (labelsFromDeletedInsns == null) labelsFromDeletedInsns = labels; else labelsFromDeletedInsns.addAll(labels); } } else { assert false : "Trying to delete instructions that fall outside the peephole window"; } }
/** * Perform optimizations on the instructions currently held in the window. This is so we don't do * the optimizations until we are sure a particular instruction was or was not the target of a * jump. If it was a target, then we don't do the optimizations as we don't have enough * information to determine all the ways control might flow to that instruction. */ private void processPreviousInstructions() { InstructionInfo last = previous(0); InstructionInfo secondLast = previous(1); // Check if we have a labelCurrent on the last instruction, or a labelNext on the previous // instruction if (last.getLabelCurrents().isEmpty() && secondLast.getLabelNexts().isEmpty()) { switch (last.getOpcode()) { case OP_convert_b: { op_convert_b(last); break; } case OP_convert_d: { op_convert_d(last); break; } case OP_convert_i: { op_convert_i(last); break; } case OP_convert_u: { op_convert_u(last); break; } case OP_convert_s: { op_convert_s(last); break; } case OP_getproperty: { op_getproperty(last); break; } case OP_iffalse: { op_iffalse(last); break; } case OP_iftrue: { op_iftrue(last); break; } case OP_pop: { op_pop(last); break; } case OP_nop: { delete(0); break; } case OP_getlocal: { OP_getlocal(last); break; } case OP_returnvoid: { op_returnvoid(last); break; } default: { break; } } } }