Class 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 Detail

      • InstructionListUtils

        public InstructionListUtils()
    • Method Detail

      • 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
      • print_il

        private void print_il​(org.apache.bcel.generic.InstructionHandle start,
                              String label)
        Print a BCEL instruction list to the debug_instrument log.
        Parameters:
        start - start of the instruction list
        label - a descriptive string for the instruction list
      • 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