Class InstructionListUtils

java.lang.Object
org.plumelib.bcelutil.StackMapUtils
org.plumelib.bcelutil.InstructionListUtils

public abstract class InstructionListUtils extends StackMapUtils
This class provides utility methods to maintain and modify a method's InstructionList within a Java class file. It is a subclass of StackMapUtils and thus handles all the StackMap side effects of InstructionList modification. It can be thought of as an extension to BCEL.

BCEL ought to automatically build and maintain the StackMapTable in a manner similar to the LineNumberTable and the LocalVariableTable. However, for historical reasons, it does not.

If you wish to modify a Java class file, you should create a subclass of InstructionListUtils to do the modifications. Then a rough program template for that class would be:

   import org.apache.bcel.classfile.*;
   import org.apache.bcel.generic.*;

  try {
    // Parse the bytes of the classfile, die on any errors
    ClassParser parser = new ClassParser(new ByteArrayInputStream(classfileBuffer), className);
    JavaClass jc = parser.parse();

    // Transform the file
    modifyClass(jc);

  } catch (Throwable e) {
    throw new RuntimeException("Unexpected error", e);
  }

  void modifyClass(JavaClass jc) {
    ClassGen cg = new ClassGen(jc);
    String classname = cg.getClassName();
    //save ConstantPool for use by StackMapUtils
    pool = cg.getConstantPool();

    for (Method m : cg.getMethods()) {
      try {
        MethodGen mg = new MethodGen(m, classname, pool);
        // Get the instruction list and skip methods with no instructions
        InstructionList il = mg.getInstructionList();
        if (il == null) {
          continue;
        }

        // Get existing StackMapTable (if present)
        setCurrentStackMapTable(mg, cg.getMajor());
        fixLocalVariableTable(mg);

        // Create a map of Uninitialized_variable_info offsets to
        // InstructionHandles.
        buildUninitializedNewMap(il);

 This is where you would insert your code to modify the current method (mg).
 Most often this is done with members of the 
invalid @link
org.apache.bcel.generic
package. However, you should use the members of InstrutionListUtils to update the byte code instructions of mg rather than similar methods in the BCEL generic package in order to maintain the integrity of the method's StackMapTable. // Update the Uninitialized_variable_info offsets before // we write out the new StackMapTable. updateUninitializedNewOffsets(il); createNewStackMapAttribute(mg); // Update the instruction list mg.setInstructionList(il); mg.update(); // Update the max stack mg.setMaxStack(); mg.setMaxLocals(); mg.update(); remove_local_variable_type_table(mg); // Update the method in the class cg.replaceMethod(m, mg.getMethod()); } catch (Throwable t) { throw new Error("Unexpected error processing " + classname + "." + m.getName(), t); } } }

It one only wishes to examine a class file, the use of this class is not necessary. See BcelUtil for notes on inspecting a Java class file.

  • Constructor Details

    • InstructionListUtils

      public InstructionListUtils()
      Create a new InstructionListUtils.
  • Method Details

    • append_inst

      protected final void append_inst(org.apache.bcel.generic.InstructionList il, org.apache.bcel.generic.Instruction inst)
      Appends the specified instruction to the end of the specified list. Required because for some reason you can't directly append jump instructions to the list -- but you can create new ones and append them.
      Parameters:
      il - InstructionList to be modified
      inst - Instruction to be appended
    • insertAtMethodStart

      protected final void insertAtMethodStart(org.apache.bcel.generic.MethodGen mg, org.apache.bcel.generic.InstructionList newIl)
      Inserts an instruction list at the beginning of a method.
      Parameters:
      mg - MethodGen of method to be modified
      newIl - InstructionList holding the new code
    • insertBeforeHandle

      protected final void insertBeforeHandle(org.apache.bcel.generic.MethodGen mg, org.apache.bcel.generic.InstructionHandle ih, @Nullable org.apache.bcel.generic.InstructionList newIl, boolean redirectBranches)
      Inserts a new instruction list into an existing instruction list just prior to the indicated instruction handle (which must be a member of the existing instruction list). If newIl is null, do nothing.
      Parameters:
      mg - MethodGen containing the instruction handle
      ih - InstructionHandle indicating where to insert new code
      newIl - InstructionList holding the new code
      redirectBranches - flag indicating if branch targets should be moved from ih to newIl
    • build_il

      protected final org.apache.bcel.generic.InstructionList build_il(org.apache.bcel.generic.Instruction... instructions)
      Convenience function to build an instruction list.
      Parameters:
      instructions - a variable number of BCEL instructions
      Returns:
      an InstructionList
    • delete_instructions

      protected final void delete_instructions(org.apache.bcel.generic.MethodGen mg, org.apache.bcel.generic.InstructionHandle startIh, org.apache.bcel.generic.InstructionHandle endIh)
      Delete instruction(s) from startIh thru endIh in an instruction list. startIh may be the first instruction of the list, but endIh must not be the last instruction of the list. startIh may be equal to endIh. There must not be any targeters on any of the instructions to be deleted except for startIh. Those targeters will be moved to the first instruction following endIh.
      Parameters:
      mg - MethodGen containing the instruction handles
      startIh - InstructionHandle indicating first instruction to be deleted
      endIh - InstructionHandle indicating last instruction to be deleted
    • calculateLiveLocalTypes

      protected final org.apache.bcel.classfile.StackMapType[] calculateLiveLocalTypes(org.apache.bcel.generic.MethodGen mg, int location)
      Compute the StackMapTypes of the live variables of the current method at a specific location within the method. There may be gaps ("Bogus" or non-live slots) so we can't just count the number of live variables, we must find the max index of all the live variables.
      Parameters:
      mg - MethodGen for the current method
      location - the code location to be evaluated
      Returns:
      an array of StackMapType describing the live locals at location
    • calculateLiveStackTypes

      protected final org.apache.bcel.classfile.StackMapType[] calculateLiveStackTypes(org.apache.bcel.verifier.structurals.OperandStack stack)
      Compute the StackMapTypes of the items on the execution stack as described by the OperandStack argument.
      Parameters:
      stack - an OperandStack object
      Returns:
      an array of StackMapType describing the stack contents
    • replaceInstructions

      protected final void replaceInstructions(org.apache.bcel.generic.MethodGen mg, org.apache.bcel.generic.InstructionList il, org.apache.bcel.generic.InstructionHandle ih, @Nullable org.apache.bcel.generic.InstructionList newIl)
      Replace instruction ih in list il with the instructions in newIl. If newIl is null, do nothing.
      Parameters:
      mg - MethodGen containing the instruction handle
      il - InstructionList containing ih
      ih - InstructionHandle indicating where to insert new code
      newIl - InstructionList holding the new code