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 one wishes 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)
        set_current_stack_map_table(mg, cg.getMajor());
        fix_local_variable_table(mg);

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

 This is where you would insert your code to modify the current method (mg).
 Most often this is done with members of the 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.
        update_uninitialized_NEW_offsets(il);
        create_new_stack_map_attribute(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()
  • 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
    • insert_at_method_start

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

      protected final void insert_before_handle(org.apache.bcel.generic.MethodGen mg, org.apache.bcel.generic.InstructionHandle ih, @Nullable org.apache.bcel.generic.InstructionList new_il, boolean redirect_branches)
      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 new_il is null, do nothing.
      Parameters:
      mg - MethodGen containing the instruction handle
      ih - InstructionHandle indicating where to insert new code
      new_il - InstructionList holding the new code
      redirect_branches - flag indicating if branch targets should be moved from ih to new_il
    • 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 start_ih, org.apache.bcel.generic.InstructionHandle end_ih)
      Delete instruction(s) from start_ih thru end_ih in an instruction list. start_ih may be the first instruction of the list, but end_ih must not be the last instruction of the list. start_ih may be equal to end_ih. There must not be any targeters on any of the instructions to be deleted except for start_ih. Those targeters will be moved to the first instruction following end_ih.
      Parameters:
      mg - MethodGen containing the instruction handles
      start_ih - InstructionHandle indicating first instruction to be deleted
      end_ih - InstructionHandle indicating last instruction to be deleted
    • calculate_live_local_types

      protected final org.apache.bcel.classfile.StackMapType[] calculate_live_local_types(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
    • calculate_live_stack_types

      protected final org.apache.bcel.classfile.StackMapType[] calculate_live_stack_types(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
    • replace_instructions

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