Class Frame

java.lang.Object
org.eclipse.sisu.space.asm.Frame
Direct Known Subclasses:
CurrentFrame

class Frame extends Object
The input and output stack map frames of a basic block.

Stack map frames are computed in two steps:

  • During the visit of each instruction in MethodWriter, the state of the frame at the end of the current basic block is updated by simulating the action of the instruction on the previous state of this so called "output frame".
  • After all instructions have been visited, a fix point algorithm is used in MethodWriter to compute the "input frame" of each basic block (i.e. the stack map frame at the beginning of the basic block). See MethodWriter.computeAllFrames().

Output stack map frames are computed relatively to the input frame of the basic block, which is not yet known when output frames are computed. It is therefore necessary to be able to represent abstract types such as "the type at position x in the input frame locals" or "the type at position x from the top of the input frame stack" or even "the type at position x in the input frame, with y more (or less) array dimensions". This explains the rather complicated type format used in this class, explained below.

The local variables and the operand stack of input and output frames contain values called "abstract types" hereafter. An abstract type is represented with 4 fields named DIM, KIND, FLAGS and VALUE, packed in a single int value for better performance and memory efficiency:

   =====================================
   |...DIM|KIND|.F|...............VALUE|
   =====================================
 

Output frames can contain abstract types of any kind and with a positive or negative array dimension (and even unassigned types, represented by 0 - which does not correspond to any valid abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND, UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type table contains only internal type names (array type descriptors are forbidden - array dimensions must be represented through the DIM field).

The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE + TOP), for local variables as well as in the operand stack. This is necessary to be able to simulate DUPx_y instructions, whose effect would be dependent on the concrete types represented by the abstract types in the stack (which are not always known).

  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    (package private) static final int
     
    private static final int
    The constant to be added to an abstract type to get one with one more array dimension.
    private static final int
     
    private static final int
     
    private static final int
     
    (package private) static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
    The constant to be added to an abstract type to get one with one less array dimension.
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    (package private) static final int
     
    private int
    The number of types that are initialized in the basic block.
    private int[]
    The abstract types that are initialized in the basic block.
    private int[]
    The input stack map frame locals.
    private int[]
    The input stack map frame stack.
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private int[]
    The output stack map frame locals.
    private int[]
    The output stack map frame stack.
    private short
    The start of the output stack, relatively to the input stack.
    private short
    The index of the top stack element in outputStack.
    (package private) Label
    The basic block to which these input and output stack map frames correspond.
    private static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    (package private) static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
    A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been partially overridden with an xSTORE instruction).
    private static final int
     
    private static final int
     
    private static final int
     
    private static final int
     
  • Constructor Summary

    Constructors
    Constructor
    Description
    Frame(Label owner)
    Constructs a new Frame.
  • Method Summary

    Modifier and Type
    Method
    Description
    (package private) final void
    accept(MethodWriter methodWriter)
    Makes the given MethodWriter visit the input frame of this Frame.
    private void
    addInitializedType(int abstractType)
    Adds an abstract type to the list of types on which a constructor is invoked in the basic block.
    (package private) final void
    copyFrom(Frame frame)
    Sets this frame to the value of the given frame.
    (package private) void
    execute(int opcode, int arg, Symbol argSymbol, SymbolTable symbolTable)
    Simulates the action of the given instruction on the output stack frame.
    (package private) static int
    Returns the abstract type corresponding to the given public API frame element type.
    private static int
    getAbstractTypeFromDescriptor(SymbolTable symbolTable, String buffer, int offset)
    Returns the abstract type corresponding to the given type descriptor.
    (package private) static int
    Returns the abstract type corresponding to the internal name of a class.
    private int
    getConcreteOutputType(int abstractOutputType, int numStack)
    Computes the concrete output type corresponding to a given abstract output type.
    private int
    getInitializedType(SymbolTable symbolTable, int abstractType)
    Returns the "initialized" abstract type corresponding to the given abstract type.
    (package private) final int
     
    private int
    getLocal(int localIndex)
    Returns the abstract type stored at the given local variable index in the output frame.
    private static boolean
    merge(SymbolTable symbolTable, int sourceType, int[] dstTypes, int dstIndex)
    Merges the type at the given index in the given abstract type array with the given type.
    (package private) final boolean
    merge(SymbolTable symbolTable, Frame dstFrame, int catchTypeIndex)
    Merges the input frame of the given Frame with the input and output frames of this Frame.
    private int
    pop()
    Pops an abstract type from the output frame stack and returns its value.
    private void
    pop(int elements)
    Pops the given number of abstract types from the output frame stack.
    private void
    pop(String descriptor)
    Pops as many abstract types from the output frame stack as described by the given descriptor.
    private void
    push(int abstractType)
    Pushes the given abstract type on the output frame stack.
    private void
    push(SymbolTable symbolTable, String descriptor)
    Pushes the abstract type corresponding to the given descriptor on the output frame stack.
    (package private) static void
    putAbstractType(SymbolTable symbolTable, int abstractType, ByteVector output)
    Put the given abstract type in the given ByteVector, using the JVMS verification_type_info format used in StackMapTable attributes.
    (package private) final void
    setInputFrameFromApiFormat(SymbolTable symbolTable, int numLocal, Object[] local, int numStack, Object[] stack)
    Sets the input frame from the given public API frame description.
    (package private) final void
    setInputFrameFromDescriptor(SymbolTable symbolTable, int access, String descriptor, int maxLocals)
    Sets the input frame from the given method description.
    private void
    setLocal(int localIndex, int abstractType)
    Replaces the abstract type stored at the given local variable index in the output frame.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • SAME_FRAME

      static final int SAME_FRAME
      See Also:
    • SAME_LOCALS_1_STACK_ITEM_FRAME

      static final int SAME_LOCALS_1_STACK_ITEM_FRAME
      See Also:
    • RESERVED

      static final int RESERVED
      See Also:
    • SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED

      static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
      See Also:
    • CHOP_FRAME

      static final int CHOP_FRAME
      See Also:
    • SAME_FRAME_EXTENDED

      static final int SAME_FRAME_EXTENDED
      See Also:
    • APPEND_FRAME

      static final int APPEND_FRAME
      See Also:
    • FULL_FRAME

      static final int FULL_FRAME
      See Also:
    • ITEM_TOP

      static final int ITEM_TOP
      See Also:
    • ITEM_INTEGER

      static final int ITEM_INTEGER
      See Also:
    • ITEM_FLOAT

      static final int ITEM_FLOAT
      See Also:
    • ITEM_DOUBLE

      static final int ITEM_DOUBLE
      See Also:
    • ITEM_LONG

      static final int ITEM_LONG
      See Also:
    • ITEM_NULL

      static final int ITEM_NULL
      See Also:
    • ITEM_UNINITIALIZED_THIS

      static final int ITEM_UNINITIALIZED_THIS
      See Also:
    • ITEM_OBJECT

      static final int ITEM_OBJECT
      See Also:
    • ITEM_UNINITIALIZED

      static final int ITEM_UNINITIALIZED
      See Also:
    • ITEM_ASM_BOOLEAN

      private static final int ITEM_ASM_BOOLEAN
      See Also:
    • ITEM_ASM_BYTE

      private static final int ITEM_ASM_BYTE
      See Also:
    • ITEM_ASM_CHAR

      private static final int ITEM_ASM_CHAR
      See Also:
    • ITEM_ASM_SHORT

      private static final int ITEM_ASM_SHORT
      See Also:
    • DIM_SIZE

      private static final int DIM_SIZE
      See Also:
    • KIND_SIZE

      private static final int KIND_SIZE
      See Also:
    • FLAGS_SIZE

      private static final int FLAGS_SIZE
      See Also:
    • VALUE_SIZE

      private static final int VALUE_SIZE
      See Also:
    • DIM_SHIFT

      private static final int DIM_SHIFT
      See Also:
    • KIND_SHIFT

      private static final int KIND_SHIFT
      See Also:
    • FLAGS_SHIFT

      private static final int FLAGS_SHIFT
      See Also:
    • DIM_MASK

      private static final int DIM_MASK
      See Also:
    • KIND_MASK

      private static final int KIND_MASK
      See Also:
    • VALUE_MASK

      private static final int VALUE_MASK
      See Also:
    • ARRAY_OF

      private static final int ARRAY_OF
      The constant to be added to an abstract type to get one with one more array dimension.
      See Also:
    • ELEMENT_OF

      private static final int ELEMENT_OF
      The constant to be added to an abstract type to get one with one less array dimension.
      See Also:
    • CONSTANT_KIND

      private static final int CONSTANT_KIND
      See Also:
    • REFERENCE_KIND

      private static final int REFERENCE_KIND
      See Also:
    • UNINITIALIZED_KIND

      private static final int UNINITIALIZED_KIND
      See Also:
    • FORWARD_UNINITIALIZED_KIND

      private static final int FORWARD_UNINITIALIZED_KIND
      See Also:
    • LOCAL_KIND

      private static final int LOCAL_KIND
      See Also:
    • STACK_KIND

      private static final int STACK_KIND
      See Also:
    • TOP_IF_LONG_OR_DOUBLE_FLAG

      private static final int TOP_IF_LONG_OR_DOUBLE_FLAG
      A flag used for LOCAL_KIND and STACK_KIND abstract types, indicating that if the resolved, concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been partially overridden with an xSTORE instruction).
      See Also:
    • TOP

      private static final int TOP
      See Also:
    • BOOLEAN

      private static final int BOOLEAN
      See Also:
    • BYTE

      private static final int BYTE
      See Also:
    • CHAR

      private static final int CHAR
      See Also:
    • SHORT

      private static final int SHORT
      See Also:
    • INTEGER

      private static final int INTEGER
      See Also:
    • FLOAT

      private static final int FLOAT
      See Also:
    • LONG

      private static final int LONG
      See Also:
    • DOUBLE

      private static final int DOUBLE
      See Also:
    • NULL

      private static final int NULL
      See Also:
    • UNINITIALIZED_THIS

      private static final int UNINITIALIZED_THIS
      See Also:
    • owner

      Label owner
      The basic block to which these input and output stack map frames correspond.
    • inputLocals

      private int[] inputLocals
      The input stack map frame locals. This is an array of abstract types.
    • inputStack

      private int[] inputStack
      The input stack map frame stack. This is an array of abstract types.
    • outputLocals

      private int[] outputLocals
      The output stack map frame locals. This is an array of abstract types.
    • outputStack

      private int[] outputStack
      The output stack map frame stack. This is an array of abstract types.
    • outputStackStart

      private short outputStackStart
      The start of the output stack, relatively to the input stack. This offset is always negative or null. A null offset means that the output stack must be appended to the input stack. A -n offset means that the first n output stack elements must replace the top n input stack elements, and that the other elements must be appended to the input stack.
    • outputStackTop

      private short outputStackTop
      The index of the top stack element in outputStack.
    • initializationCount

      private int initializationCount
      The number of types that are initialized in the basic block. See initializations.
    • initializations

      private int[] initializations
      The abstract types that are initialized in the basic block. A constructor invocation on an UNINITIALIZED, FORWARD_UNINITIALIZED or UNINITIALIZED_THIS abstract type must replace every occurrence of this type in the local variables and in the operand stack. This cannot be done during the first step of the algorithm since, during this step, the local variables and the operand stack types are still abstract. It is therefore necessary to store the abstract types of the constructors which are invoked in the basic block, in order to do this replacement during the second step of the algorithm, where the frames are fully computed. Note that this array can contain abstract types that are relative to the input locals or to the input stack.
  • Constructor Details

    • Frame

      Frame(Label owner)
      Constructs a new Frame.
      Parameters:
      owner - the basic block to which these input and output stack map frames correspond.
  • Method Details

    • copyFrom

      final void copyFrom(Frame frame)
      Sets this frame to the value of the given frame.

      WARNING: after this method is called the two frames share the same data structures. It is recommended to discard the given frame to avoid unexpected side effects.

      Parameters:
      frame - The new frame value.
    • getAbstractTypeFromApiFormat

      static int getAbstractTypeFromApiFormat(SymbolTable symbolTable, Object type)
      Returns the abstract type corresponding to the given public API frame element type.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      type - a frame element type described using the same format as in MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[]), i.e. either Opcodes.TOP, Opcodes.INTEGER, Opcodes.FLOAT, Opcodes.LONG, Opcodes.DOUBLE, Opcodes.NULL, or Opcodes.UNINITIALIZED_THIS, or the internal name of a class, or a Label designating a NEW instruction (for uninitialized types).
      Returns:
      the abstract type corresponding to the given frame element type.
    • getAbstractTypeFromInternalName

      static int getAbstractTypeFromInternalName(SymbolTable symbolTable, String internalName)
      Returns the abstract type corresponding to the internal name of a class.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      internalName - the internal name of a class. This must not be an array type descriptor.
      Returns:
      the abstract type value corresponding to the given internal name.
    • getAbstractTypeFromDescriptor

      private static int getAbstractTypeFromDescriptor(SymbolTable symbolTable, String buffer, int offset)
      Returns the abstract type corresponding to the given type descriptor.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      buffer - a string ending with a type descriptor.
      offset - the start offset of the type descriptor in buffer.
      Returns:
      the abstract type corresponding to the given type descriptor.
    • setInputFrameFromDescriptor

      final void setInputFrameFromDescriptor(SymbolTable symbolTable, int access, String descriptor, int maxLocals)
      Sets the input frame from the given method description. This method is used to initialize the first frame of a method, which is implicit (i.e. not stored explicitly in the StackMapTable attribute).
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      access - the method's access flags.
      descriptor - the method descriptor.
      maxLocals - the maximum number of local variables of the method.
    • setInputFrameFromApiFormat

      final void setInputFrameFromApiFormat(SymbolTable symbolTable, int numLocal, Object[] local, int numStack, Object[] stack)
      Sets the input frame from the given public API frame description.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      numLocal - the number of local variables.
      local - the local variable types, described using the same format as in MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[]).
      numStack - the number of operand stack elements.
      stack - the operand stack types, described using the same format as in MethodVisitor.visitFrame(int, int, java.lang.Object[], int, java.lang.Object[]).
    • getInputStackSize

      final int getInputStackSize()
    • getLocal

      private int getLocal(int localIndex)
      Returns the abstract type stored at the given local variable index in the output frame.
      Parameters:
      localIndex - the index of the local variable whose value must be returned.
      Returns:
      the abstract type stored at the given local variable index in the output frame.
    • setLocal

      private void setLocal(int localIndex, int abstractType)
      Replaces the abstract type stored at the given local variable index in the output frame.
      Parameters:
      localIndex - the index of the output frame local variable that must be set.
      abstractType - the value that must be set.
    • push

      private void push(int abstractType)
      Pushes the given abstract type on the output frame stack.
      Parameters:
      abstractType - an abstract type.
    • push

      private void push(SymbolTable symbolTable, String descriptor)
      Pushes the abstract type corresponding to the given descriptor on the output frame stack.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      descriptor - a type or method descriptor (in which case its return type is pushed).
    • pop

      private int pop()
      Pops an abstract type from the output frame stack and returns its value.
      Returns:
      the abstract type that has been popped from the output frame stack.
    • pop

      private void pop(int elements)
      Pops the given number of abstract types from the output frame stack.
      Parameters:
      elements - the number of abstract types that must be popped.
    • pop

      private void pop(String descriptor)
      Pops as many abstract types from the output frame stack as described by the given descriptor.
      Parameters:
      descriptor - a type or method descriptor (in which case its argument types are popped).
    • addInitializedType

      private void addInitializedType(int abstractType)
      Adds an abstract type to the list of types on which a constructor is invoked in the basic block.
      Parameters:
      abstractType - an abstract type on a which a constructor is invoked.
    • getInitializedType

      private int getInitializedType(SymbolTable symbolTable, int abstractType)
      Returns the "initialized" abstract type corresponding to the given abstract type.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      abstractType - an abstract type.
      Returns:
      the REFERENCE_KIND abstract type corresponding to abstractType if it is UNINITIALIZED_THIS or an UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND abstract type for one of the types on which a constructor is invoked in the basic block. Otherwise returns abstractType.
    • execute

      void execute(int opcode, int arg, Symbol argSymbol, SymbolTable symbolTable)
      Simulates the action of the given instruction on the output stack frame.
      Parameters:
      opcode - the opcode of the instruction.
      arg - the numeric operand of the instruction, if any.
      argSymbol - the Symbol operand of the instruction, if any.
      symbolTable - the type table to use to lookup and store type Symbol.
    • getConcreteOutputType

      private int getConcreteOutputType(int abstractOutputType, int numStack)
      Computes the concrete output type corresponding to a given abstract output type.
      Parameters:
      abstractOutputType - an abstract output type.
      numStack - the size of the input stack, used to resolve abstract output types of STACK_KIND kind.
      Returns:
      the concrete output type corresponding to 'abstractOutputType'.
    • merge

      final boolean merge(SymbolTable symbolTable, Frame dstFrame, int catchTypeIndex)
      Merges the input frame of the given Frame with the input and output frames of this Frame. Returns true if the given frame has been changed by this operation (the input and output frames of this Frame are never changed).
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      dstFrame - the Frame whose input frame must be updated. This should be the frame of a successor, in the control flow graph, of the basic block corresponding to this frame.
      catchTypeIndex - if 'frame' corresponds to an exception handler basic block, the type table index of the caught exception type, otherwise 0.
      Returns:
      true if the input frame of 'frame' has been changed by this operation.
    • merge

      private static boolean merge(SymbolTable symbolTable, int sourceType, int[] dstTypes, int dstIndex)
      Merges the type at the given index in the given abstract type array with the given type. Returns true if the type array has been modified by this operation.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      sourceType - the abstract type with which the abstract type array element must be merged. This type should be of CONSTANT_KIND, REFERENCE_KIND, UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND kind, with positive or null array dimensions.
      dstTypes - an array of abstract types. These types should be of CONSTANT_KIND, REFERENCE_KIND, UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND kind, with positive or null array dimensions.
      dstIndex - the index of the type that must be merged in dstTypes.
      Returns:
      true if the type array has been modified by this operation.
    • accept

      final void accept(MethodWriter methodWriter)
      Makes the given MethodWriter visit the input frame of this Frame. The visit is done with the MethodWriter.visitFrameStart(int, int, int), MethodWriter.visitAbstractType(int, int) and MethodWriter.visitFrameEnd() methods.
      Parameters:
      methodWriter - the MethodWriter that should visit the input frame of this Frame.
    • putAbstractType

      static void putAbstractType(SymbolTable symbolTable, int abstractType, ByteVector output)
      Put the given abstract type in the given ByteVector, using the JVMS verification_type_info format used in StackMapTable attributes.
      Parameters:
      symbolTable - the type table to use to lookup and store type Symbol.
      abstractType - an abstract type, restricted to CONSTANT_KIND, REFERENCE_KIND, UNINITIALIZED_KIND or FORWARD_UNINITIALIZED_KIND types.
      output - where the abstract type must be put.
      See Also: