/** Instrument the specified method to replace mapped calls. */ public void instrument_method(Method m, MethodGen mg) { // Loop through each instruction, making substitutions InstructionList il = mg.getInstructionList(); for (InstructionHandle ih = il.getStart(); ih != null; ) { if (debug_instrument_inst.enabled()) { debug_instrument_inst.log("instrumenting instruction %s%n", ih); // ih.getInstruction().toString(pool.getConstantPool())); } InstructionList new_il = null; // Remember the next instruction to process InstructionHandle next_ih = ih.getNext(); // Get the translation for this instruction (if any) new_il = xform_inst(mg, ih.getInstruction()); if (debug_instrument_inst.enabled()) debug_instrument_inst.log(" new inst: %s%n", new_il); // If this instruction was modified, replace it with the new // instruction list. If this instruction was the target of any // jumps or line numbers , replace them with the first // instruction in the new list replace_instructions(il, ih, new_il); ih = next_ih; } }
/** * Replace instruction ih in list il with the instructions in new_il. If new_il is null, do * nothing */ protected static void replace_instructions( InstructionList il, InstructionHandle ih, InstructionList new_il) { if ((new_il == null) || new_il.isEmpty()) return; // If there is only one new instruction, just replace it in the handle if (new_il.getLength() == 1) { ih.setInstruction(new_il.getEnd().getInstruction()); return; } // Get the start and end instruction of the new instructions InstructionHandle new_end = new_il.getEnd(); InstructionHandle new_start = il.insert(ih, new_il); // Move all of the branches from the old instruction to the new start il.redirectBranches(ih, new_start); // Move other targets to the new instuctions. if (ih.hasTargeters()) { for (InstructionTargeter it : ih.getTargeters()) { if (it instanceof LineNumberGen) { it.updateTarget(ih, new_start); } else if (it instanceof LocalVariableGen) { it.updateTarget(ih, new_end); } else if (it instanceof CodeExceptionGen) { CodeExceptionGen exc = (CodeExceptionGen) it; if (exc.getStartPC() == ih) exc.updateTarget(ih, new_start); else if (exc.getEndPC() == ih) exc.updateTarget(ih, new_end); else if (exc.getHandlerPC() == ih) exc.setHandlerPC(new_start); else System.out.printf("Malformed CodeException: %s%n", exc); } else { System.out.printf("unexpected target %s%n", it); } } } // Remove the old handle. There should be no targeters left to it. try { il.delete(ih); } catch (Exception e) { throw new Error("Can't delete instruction", e); } }
/** * Long output format: * * <p><position in byte code> <name of opcode> "["<opcode number>"]" * "("<length of instruction>")" "<"<target instruction>">" "@"<branch target * offset> * * @param verbose long/short format switch * @return mnemonic for instruction */ public String toString(boolean verbose) { String s = super.toString(verbose); String t = "null"; if (verbose) { if (target != null) { if (target.getInstruction() == this) t = "<points to itself>"; else if (target.getInstruction() == null) t = "<null instruction!!!?>"; else t = target.getInstruction().toString(false); // Avoid circles } } else { if (target != null) { index = getTargetOffset(); t = "" + (index + position); } } return s + " -> " + t; }
/** * @param target branch target * @return the offset to `target' relative to this instruction */ protected int getTargetOffset(InstructionHandle target) { if (target == null) throw new ClassGenException("Target of " + super.toString(true) + " is invalid null handle"); int t = target.getPosition(); if (t < 0) throw new ClassGenException( "Invalid branch target position offset for " + super.toString(true) + ":" + t + ":" + target); return t - position; }
/** Used by BranchInstruction, LocalVariableGen, CodeExceptionGen */ static final void notifyTarget( InstructionHandle old_ih, InstructionHandle new_ih, InstructionTargeter t) { if (old_ih != null) old_ih.removeTargeter(t); if (new_ih != null) new_ih.addTargeter(t); }