Class CodeAttributeComposer

  • All Implemented Interfaces:
    LocalVariableTargetElementVisitor, TargetInfoVisitor, TypeAnnotationVisitor, StackMapFrameVisitor, VerificationTypeVisitor, AttributeVisitor, ExceptionInfoVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, InstructionVisitor

    public class CodeAttributeComposer
    extends java.lang.Object
    implements AttributeVisitor, InstructionVisitor, ExceptionInfoVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LineNumberInfoVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor, TypeAnnotationVisitor, TargetInfoVisitor, LocalVariableTargetElementVisitor
    This AttributeVisitor accumulates instructions, exceptions and line numbers, and then adds them to a method or copies them into code attributes that it visits.

    The class supports composing instructions (appendInstruction(Instruction)), labels (appendLabel(int)), exception handlers (appendException(ExceptionInfo)), and line numbers (appendLineNumber(LineNumberInfo)).

    The labels are numeric labels that you can choose freely, for example instruction offsets from existing code that you are copying. You can then refer to them in branches and exception handlers. You can compose the code as a hierarchy of code fragments with their own local labels.

    You should provide an estimated maximum size (expressed in number of bytes in the bytecode), so the implementation can efficiently allocate the necessary internal buffers without reallocating them as the code grows.

    For example:

         ProgramClass  programClass  = ...
         ProgramMethod programMethod = ...
    
         // Create any constants for the code.
         ConstantPoolEditor constantPoolEditor =
             new ConstantPoolEditor(programClass);
    
         int exceptionType =
             constantPoolEditor.addClassConstant("java/lang/Exception", null);
    
         // Compose the code.
         CodeAttributeComposer composer =
             new CodeAttributeComposer();
    
         final int TRY_LABEL   =  0;
         final int IF_LABEL    =  1;
         final int THEN_LABEL  = 10;
         final int ELSE_LABEL  = 20;
         final int CATCH_LABEL = 30;
    
         composer.beginCodeFragment(50);
         composer.appendLabel(TRY_LABEL);
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_ICONST_1));
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_ICONST_2));
         composer.appendLabel(IF_LABEL);
         composer.appendInstruction(new BranchInstruction(Instruction.OP_IFICMPLT, ELSE_LABEL - IF_LABEL));
    
         composer.appendLabel(THEN_LABEL);
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_ICONST_1));
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_IRETURN));
    
         composer.appendLabel(ELSE_LABEL);
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_ICONST_2));
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_IRETURN));
    
         composer.appendLabel(CATCH_LABEL);
         composer.appendException(new ExceptionInfo(TRY_LABEL, CATCH_LABEL, CATCH_LABEL, exceptionType));
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_ICONST_M1));
         composer.appendInstruction(new SimpleInstruction(Instruction.OP_IRETURN));
         composer.endCodeFragment();
    
          // Add the code as a code attribute to the given method.
          composer.addCodeAttribute(programClass, programMethod, constantPoolEditor);
     

    This class is mostly convenient to compose code based on existing code, where the instructions are already available. For a more compact and readable alternative to compose code programmatically from scratch, see CompactCodeAttributeComposer.

    If you're building many method bodies, it is more efficient to reuse a single instance of this composer for all methods that you add.