Class Frame

  • Direct Known Subclasses:
    CurrentFrame

    class Frame
    extends java.lang.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 or 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).

    • Constructor Summary

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

      All Methods Static Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      (package private) 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) 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 getAbstractTypeFromApiFormat​(SymbolTable symbolTable, java.lang.Object type)
      Returns the abstract type corresponding to the given public API frame element type.
      private static int getAbstractTypeFromDescriptor​(SymbolTable symbolTable, java.lang.String buffer, int offset)
      Returns the abstract type corresponding to the given type descriptor.
      (package private) static int getAbstractTypeFromInternalName​(SymbolTable symbolTable, java.lang.String internalName)
      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) int getInputStackSize()  
      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) 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​(java.lang.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, java.lang.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) void setInputFrameFromApiFormat​(SymbolTable symbolTable, int numLocal, java.lang.Object[] local, int numStack, java.lang.Object[] stack)
      Sets the input frame from the given public API frame description.
      (package private) void setInputFrameFromDescriptor​(SymbolTable symbolTable, int access, java.lang.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 Detail

      • SAME_LOCALS_1_STACK_ITEM_FRAME

        static final int SAME_LOCALS_1_STACK_ITEM_FRAME
        See Also:
        Constant Field Values
      • SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED

        static final int SAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED
        See Also:
        Constant Field Values
      • 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:
        Constant Field Values
      • 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 Field Values
      • 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:
        Constant Field Values
      • 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 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 Detail

      • Frame

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

      • 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.
      • getAbstractTypeFromInternalName

        static int getAbstractTypeFromInternalName​(SymbolTable symbolTable,
                                                   java.lang.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,
                                                         java.lang.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,
                                               java.lang.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.
      • 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,
                          java.lang.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​(java.lang.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 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 or UNINITIALIZED_KIND kind, with positive or null array dimensions.
        dstTypes - an array of abstract types. These types should be of CONSTANT_KIND, REFERENCE_KIND or 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.
      • 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 or UNINITIALIZED_KIND types.
        output - where the abstract type must be put.
        See Also:
        JVMS 4.7.4