All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tangosol.dev.assembler.TypeAnnotation Maven / Gradle / Ivy

There is a newer version: 24.03
Show newest version
/*
 * Copyright (c) 2000, 2020, Oracle and/or its affiliates.
 *
 * Licensed under the Universal Permissive License v 1.0 as shown at
 * http://oss.oracle.com/licenses/upl.
 */


package com.tangosol.dev.assembler;


import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Arrays;

/**
 * TypeAnnotation represents a Java Virtual Machine {@code type_annotation}
 * structure as used by 'RuntimeVisibleTypeAnnotations_attribute' and
 * 'RuntimeInvisibleTypeAnnotations_attribute'.
 * 

* The TypeAnnotation structure is defined by the JVM 8 Spec as: *

 *     TypeAnnotation
 *         {
 *         u1 target_type;
 *         union
 *             {
 *             type_parameter_target;
 *             supertype_target;
 *             type_parameter_bound_target;
 *             empty_target;
 *             method_formal_parameter_target;
 *             throws_target;
 *             localvar_target;
 *             catch_target;
 *             offset_target;
 *             type_argument_target;
 *             } target_info;
 *         type_path target_path;
 *         u2        type_index;
 *         u2        num_element_value_pairs;
 *             {
 *             u2            element_name_index;
 *             element_value value;
 *             } element_value_pairs[num_element_value_pairs];
 *         }
 * 
* * @author hr 2014.05.22 */ public class TypeAnnotation extends Annotation { // ----- VMStructure operations ----------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { // typed_annotation's additional structure is before the standard // annotation, hence the call to super last m_target = AbstractTarget.loadTarget(stream, pool); (m_typePath = new TypePath()).disassemble(stream, pool); super.disassemble(stream, pool); } @Override protected void preassemble(ConstantPool pool) { super.preassemble(pool); } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { // typed_annotation's additional structure is before the standard // annotation, hence the call to super last m_target.assemble(stream, pool); // target_type & target_info m_typePath.assemble(stream, pool); // target_path super.assemble(stream, pool); } // ----- Annotation operations ------------------------------------------ @Override public int getSize() { return m_target.getSize() + m_typePath.getSize() + super.getSize(); } // ----- inner class: AbstractTarget ------------------------------------ /** * A base type for all targets for TypeAnnotations. */ public abstract static class AbstractTarget extends VMStructure implements Constants { // ----- constructors ----------------------------------------------- /** * Construct the base type for all targets used by {@link TypeAnnotation}. * * @param bType byte representing target_type */ protected AbstractTarget(byte bType) { m_bType = bType; } // ----- abstract methods ------------------------------------------- /** * Return the number of bytes consumed by this structure when serialized. * * @return the number of bytes consumed by this structure when serialized */ protected int getSize() { return 1; } // ----- constant helpers ------------------------------------------- /** * Return a newly constructed {@link AbstractTarget} based on the next * byte in the provided steam. The byte should correspond to one of * the bytes in the {@code TARGET_*} constants of this class. * * @param stream the stream to read from * @param pool the constant pool to look up references * * @return an appropriate AbstractTarget * * @throws IOException if reading from the stream errors */ public static AbstractTarget loadTarget(DataInput stream, ConstantPool pool) throws IOException { byte bType = stream.readByte(); AbstractTarget target; switch (bType) { case TARGET_CLASS: case TARGET_METHOD: // type_parameter_target target = new TypeParameterTarget(bType); break; case TARGET_EXT_IMPL: // supertype_target target = new SuperTypeTarget(bType); break; case TARGET_PARAM_BOUND_CLASS: case TARGET_PARAM_BOUND_METHOD: // type_parameter_bound_target target = new TypeParameterBoundTarget(bType); break; case TARGET_FIELD: case TARGET_METHOD_RETURN: case TARGET_METHOD_RECEIVER: // empty_target target = new EmptyTarget(bType); break; case TARGET_METHOD_PARAM: // formal_parameter_target target = new FormalParameterTarget(bType); break; case TARGET_METHOD_THROWS: // throws_target target = new ThrowsTarget(bType); break; case TARGET_CODE_LOCAL_VAR: case TARGET_CODE_RESOURCE_VAR: // localvar_target target = new LocalVariableTarget(bType); break; case TARGET_CODE_EXCEPTION_PARAM: // catch_target target = new CatchTarget(bType); break; case TARGET_CODE_INSTANCEOF: case TARGET_CODE_NEW: case TARGET_CODE_METHOD_REF_NEW: case TARGET_CODE_METHOD_REF: // offset_target target = new OffsetTarget(bType); break; case TARGET_CODE_CAST: case TARGET_CODE_CONSTRUCTOR: case TARGET_CODE_METHOD: case TARGET_CODE_METHOD_REF_NEW_ARG: case TARGET_CODE_METHOD_REF_ARG: // type_argument_target target = new TypeArgumentTarget(bType); break; default: throw new IllegalStateException("Unexpected target type: " + String.format("%X", bType)); } target.disassemble(stream, pool); return target; } // ----- VMStructure operations ------------------------------------- /** * The assembly process assembles and writes the structure to the passed * output stream, resolving any dependencies using the passed constant * pool. * * @param stream the stream implementing java.io.DataOutput to which to * write the assembled VM structure * @param pool the constant pool for the class which by this point * contains the entire set of constants required to build * this VM structure */ protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { stream.writeByte(m_bType); } // ----- non-code target type constants ----------------------------- /** * Kind of Target: Type Parameter declaration of generic class or interface. */ public static final byte TARGET_CLASS = 0x00; /** * Kind of Target: Type Parameter declaration of generic method or constructor. */ public static final byte TARGET_METHOD = 0x01; /** * Kind of Target: Type in extends clause of class or interface declaration * or in implements clause of interface declaration. */ public static final byte TARGET_EXT_IMPL = 0x10; /** * Kind of Target: Type in bound of type parameter declaration of * generic class or interface. */ public static final byte TARGET_PARAM_BOUND_CLASS = 0x11; /** * Kind of Target: Type in bound of type parameter declaration of * generic method or constructor. */ public static final byte TARGET_PARAM_BOUND_METHOD = 0x12; /** * Kind of Target: Type in field declaration. */ public static final byte TARGET_FIELD = 0x13; /** * Kind of Target: Return type of methods or newly constructed object. */ public static final byte TARGET_METHOD_RETURN = 0x14; /** * Kind of Target: Receiver type of method or constructor. */ public static final byte TARGET_METHOD_RECEIVER = 0x15; /** * Kind of Target: Type in the formal parameter declaration of * method, constructor, or lambda expression. */ public static final byte TARGET_METHOD_PARAM = 0x16; /** * Kind of Target: Type in throws clause of method or constructor. */ public static final byte TARGET_METHOD_THROWS = 0x17; // ----- code target type constants --------------------------------- /** * Kind of Target: Type in local variable declaration. */ public static final byte TARGET_CODE_LOCAL_VAR = 0x40; /** * Kind of Target: Type in resource variable declaration. */ public static final byte TARGET_CODE_RESOURCE_VAR = 0x41; /** * Kind of Target: Type in exception parameter declaration. */ public static final byte TARGET_CODE_EXCEPTION_PARAM = 0x42; /** * Kind of Target: Type in instanceof expression. */ public static final byte TARGET_CODE_INSTANCEOF = 0x43; /** * Kind of Target: Type in new declaration. */ public static final byte TARGET_CODE_NEW = 0x44; /** * Kind of Target: Type in method reference expression using ::new. */ public static final byte TARGET_CODE_METHOD_REF_NEW = 0x45; /** * Kind of Target: Type in method reference expression using ::Identifier. */ public static final byte TARGET_CODE_METHOD_REF = 0x46; /** * Kind of Target: Type in cast expression. */ public static final byte TARGET_CODE_CAST = 0x47; /** * Kind of Target: Type argument for generic constructor in new expression * or explicit constructor invocation statement. */ public static final byte TARGET_CODE_CONSTRUCTOR = 0x48; /** * Kind of Target: Type argument for generic method in method invocation * expression. */ public static final byte TARGET_CODE_METHOD = 0x49; /** * Kind of Target: Type argument for generic constructor in method * reference expression using ::new. */ public static final byte TARGET_CODE_METHOD_REF_NEW_ARG = 0x4A; /** * Kind of Target: Type argument for generic method in method reference * expression using ::Identifier. */ public static final byte TARGET_CODE_METHOD_REF_ARG = 0x4B; // ----- data members ----------------------------------------------- /** * The target_type value for this target. */ protected byte m_bType; } // ----- data structures for class / method / field targets ------------- // ----- inner class: TypeParameterTarget ------------------------------- /** * TypeAnnotations with a TypeParameterTarget target the annotation to a * generic class, interface, method or constructor. * * @see #TARGET_CLASS * @see #TARGET_METHOD */ protected static class TypeParameterTarget extends AbstractTarget { /** * Construct TypeParameterTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x00 or 0x01) */ protected TypeParameterTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iTypeParameter = stream.readUnsignedByte(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeByte(m_iTypeParameter); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 1; } // ----- accessors -------------------------------------------------- /** * Return the type parameter index to the types in the relevant class, * interface, method or constructor. * * @return the type parameter index to the types in the relevant class, * interface, method or constructor */ public int getTypeParameterIndex() { return m_iTypeParameter; } /** * Set the type parameter index to the types in the relevant class, * interface, method or constructor. The index must be in the range 0-255. * * @param iTypeParameter the type parameter index to the types in the * relevant class, interface, method or constructor * * @throws IllegalArgumentException if iTypeParameter is not within range */ public void setTypeParameterIndex(int iTypeParameter) { if ((iTypeParameter & ~0xFF) != 0) { throw new IllegalArgumentException("Type Parameter index must be in the range 0-255"); } m_iTypeParameter = iTypeParameter; } // ----- data members ----------------------------------------------- /** * An index into the class, interface, method, or constructors generic * type parameters. */ protected int m_iTypeParameter; } // ----- inner class: SuperTypeTarget ----------------------------------- /** * TypeAnnotations with a SuperTypeTarget, target the annotation to the * extends or implements clause of a class or interface. * * @see #TARGET_EXT_IMPL */ protected static class SuperTypeTarget extends AbstractTarget { /** * Construct SuperTypeTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x10) */ protected SuperTypeTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iSuperType = stream.readUnsignedShort(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeShort(m_iSuperType); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2; } // ----- accessors -------------------------------------------------- /** * Return the super type index for the relevant class or interface. * * @return the super type index for the relevant class or interface */ public int getSuperParameterIndex() { return m_iSuperType; } /** * Set the super type index for the the relevant class or interface. * The index must be in the range 0-65535. * * @param iSuperType the super type index of the relevant class or interface * * @throws IllegalArgumentException if iSuperType is not within range */ public void setSuperTypeIndex(int iSuperType) { if ((iSuperType & ~0xFFFF) != 0) { throw new IllegalArgumentException("Super Type (extends or implements) " + "index must be in the range 0-65535"); } m_iSuperType = iSuperType; } // ----- data members ----------------------------------------------- /** * An index into the class or interface's extends or implements declaration. */ protected int m_iSuperType; } // ----- inner class: TypeParameterBoundTarget -------------------------- /** * TypeAnnotations with a TypeParameterBoundTarget, target the annotation * to a type parameter in either the generic class, interface, method or * constructor. * * @see #TARGET_PARAM_BOUND_CLASS * @see #TARGET_PARAM_BOUND_METHOD */ protected static class TypeParameterBoundTarget extends TypeParameterTarget { /** * Construct TypeParameterBoundTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x11 or 0x12) */ protected TypeParameterBoundTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { super.disassemble(stream, pool); m_iBound = stream.readUnsignedByte(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeByte(m_iBound); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2; } // ----- accessors -------------------------------------------------- /** * Return the bound index to the types in the relevant class, interface, * method or constructor. * * @return the bound index to the types in the relevant class, interface, * method or constructor */ public int getBoundIndex() { return m_iBound; } /** * Set the bound index to the types in the relevant class, interface, * method or constructor. The index must be in the range 0-255. * * @param iBound the bound index to the types in the relevant class, * interface, method or constructor * * @throws IllegalArgumentException if iBound is not within range */ public void setBoundIndex(int iBound) { if ((iBound & ~0xFF) != 0) { throw new IllegalArgumentException("Bound index must be in the range 0-255"); } m_iBound = iBound; } // ----- data members ----------------------------------------------- /** * An index into the class, interface, method, or constructors generic * type parameters. */ protected int m_iBound; } // ----- inner class: EmptyTarget --------------------------------------- /** * TypeAnnotations with an EmptyTarget, target the annotation to the * info object (class, method, or field) where either the {@link * RuntimeVisibleTypeAnnotationsAttribute} or {@link RuntimeInvisibleTypeAnnotationsAttribute} * attribute resides, thus no ancillary targeting information is required. * * @see #TARGET_FIELD * @see #TARGET_METHOD_RETURN * @see #TARGET_METHOD_RECEIVER */ protected static class EmptyTarget extends AbstractTarget { /** * Construct an EmptyTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x13, 0x14, 0x15) */ protected EmptyTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); } } // ----- inner class: FormalParameterTarget ----------------------------- /** * TypeAnnotations with a FormalParameterTarget target the annotation to * the type in a formal parameter declaration of a method, constructor, or * lambda expression. * * @see #TARGET_METHOD_PARAM */ protected static class FormalParameterTarget extends AbstractTarget { /** * Construct FormalParameterTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x16) */ protected FormalParameterTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iFormalTypeParam = stream.readUnsignedByte(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeByte(m_iFormalTypeParam); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 1; } // ----- accessors -------------------------------------------------- /** * Return the index to the formal type parameter in the relevant method, * constructor, or lambda expression. * * @return index to the formal type parameter in the relevant method, * constructor, or lambda expression */ public int getFormalTypeParamIndex() { return m_iFormalTypeParam; } /** * Set the index to the formal type parameter in the relevant method, * constructor, or lambda expression. The index must be in the range 0-255. * * @param iFormalTypeParam the index to the formal type parameter in * the relevant method, constructor, or lambda * expression * * @throws IllegalArgumentException if iFormalTypeParam is not within range */ public void setFormalTypeParamIndex(int iFormalTypeParam) { if ((iFormalTypeParam & ~0xFF) != 0) { throw new IllegalArgumentException("Type Parameter index must be in the range 0-255"); } m_iFormalTypeParam = iFormalTypeParam; } // ----- data members ----------------------------------------------- /** * An index to the formal type parameter in the relevant method, * constructor, or lambda expression. */ protected int m_iFormalTypeParam; } // ----- inner class: ThrowsTarget -------------------------------------- /** * TypeAnnotations with a ThrowsTarget, target the annotation to the * throws clause of a method or constructor declaration. * * @see #TARGET_METHOD_THROWS */ protected static class ThrowsTarget extends AbstractTarget { /** * Construct ThrowsTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x17) */ protected ThrowsTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iThrowsClause = stream.readUnsignedShort(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeShort(m_iThrowsClause); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2; } // ----- accessors -------------------------------------------------- /** * Return the throws clause index for the relevant method or constructor. * * @return the throws clause index for the relevant method or constructor */ public int getThrowsClauseIndex() { return m_iThrowsClause; } /** * Set the throws clause index for the the relevant method or constructor. * The index must be in the range 0-65535. * * @param iThrowsClause the throws clause index of the relevant method * or constructor * * @throws IllegalArgumentException if iThrowsClause is not within range */ public void setThrowsClauseIndex(int iThrowsClause) { if ((iThrowsClause & ~0xFFFF) != 0) { throw new IllegalArgumentException("Method or constructor throws clause " + "index must be in the range 0-65535"); } m_iThrowsClause = iThrowsClause; } // ----- data members ----------------------------------------------- /** * An index into the method or constructor's throws clause. */ protected int m_iThrowsClause; } // ----- data structures for code target -------------------------------- // ----- inner class: LocalVariableTarget ------------------------------- /** * TypeAnnotations with a LocalVariableTarget, target the annotation to * local variable declarations, including variables defined within both the * try-with-resources statement and the Code attribute of the method. *

* The associated {@link RuntimeVisibleTypeAnnotationsAttribute} or * {@link RuntimeInvisibleTypeAnnotationsAttribute} must be an attribute * of the {@link CodeAttribute}. * * @see #TARGET_CODE_LOCAL_VAR * @see #TARGET_CODE_RESOURCE_VAR */ protected static class LocalVariableTarget extends AbstractTarget { /** * Construct LocalVariableTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x40 or 0x41) */ protected LocalVariableTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { int cRange = m_cRange = stream.readUnsignedShort(); LiveRange rangePrev = null; for (int i = 0; i < cRange; ++i) { LiveRange range = new LiveRange(); range.disassemble(stream, pool); if (rangePrev == null) { m_firstRange = range; } else { rangePrev.m_next = range; } rangePrev = range; } } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); int cRange = m_cRange; stream.writeShort(cRange); for (LiveRange range = m_firstRange; range != null; range = range.m_next, --cRange) { range.assemble(stream, pool); } assert cRange == 0; } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2 + m_cRange * LiveRange.getSize(); } // ----- accessors -------------------------------------------------- /** * Add a 'live' range for the annotated local variable. * * @param of the offset into the code array where this variable * starts * @param cLength the number of consecutive elements in the code * array where this variable is live * @param iCurrentFrame an index into the local variables for the * current frame that represents this local variable */ public void addLiveRange(int of, int cLength, int iCurrentFrame) { LiveRange range = new LiveRange(); range.setVariableLiveRange(of, cLength); range.setCurrentFrameIndex(iCurrentFrame); if (m_firstRange == null) { m_firstRange = range; } else { LiveRange rangeLast = m_firstRange; while (rangeLast.m_next != null) { rangeLast = rangeLast.m_next; } rangeLast.m_next = range; } ++m_cRange; } // ----- inner class: LiveRange ------------------------------------- /** * A 'live' range represents a local variable's liveness within a code * array. */ public static class LiveRange extends VMStructure implements Constants { // ----- VMStructure operations --------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iStartPC = stream.readUnsignedShort(); m_cLength = stream.readUnsignedShort(); m_iCurrentFrame = stream.readUnsignedShort(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { stream.writeShort(m_iStartPC); stream.writeShort(m_cLength); stream.writeShort(m_iCurrentFrame); } // ----- accessors ---------------------------------------------- /** * Return an offset into the code array where this variable starts. * * @return an offset into the code array where this variable starts */ public int getCodeOffset() { return m_iStartPC; } /** * Return the number of elements in the code array that represent * this variable's liveness. * * @return the number of elements in the code array where this variable * is live */ public int getLength() { return m_cLength; } /** * Set the window of the code array where this variable is live. * * @param of the offset into the code array where this variable * starts * @param cLength the number of consecutive elements in the code * array where this variable is live */ public void setVariableLiveRange(int of, int cLength) { // we could validate against the code array m_iStartPC = of; m_cLength = cLength; } /** * Return an index into the local variables for the current frame * that represents this local variable. * * @return an index into the local variables for the current frame * that represents this local variable */ public int getCurrentFrameIndex() { return m_iCurrentFrame; } /** * Set the index into the local variables for the current frame * that represents this local variable. * * @param iCurrentFrame an index into the local variables for the * current frame that represents this local * variable */ public void setCurrentFrameIndex(int iCurrentFrame) { m_iCurrentFrame = iCurrentFrame; } /** * Return the number of bytes consumed by this structure when serialized. * * @return the number of bytes consumed by this structure when serialized */ protected static int getSize() { return 6; } // ----- data members ------------------------------------------- /** * An index into the code array (inclusive) where the variable starts. */ protected int m_iStartPC; /** * The number of consecutive elements in the code array where the * variable is 'live'. */ protected int m_cLength; /** * An index into the local variables for the current frame that * represents this annotated local variable. */ protected int m_iCurrentFrame; /** * Next linked LiveRange. */ protected LiveRange m_next; } // ----- data members ----------------------------------------------- /** * A count of the number of live ranges. */ protected int m_cRange; /** * An index into the method or constructor's throws clause. */ protected LiveRange m_firstRange; } // ----- inner class: CatchTarget --------------------------------------- /** * TypeAnnotations with a CatchTarget, target the annotation to the * ith type in an exception parameter declaration. * * @see #TARGET_CODE_EXCEPTION_PARAM */ protected static class CatchTarget extends AbstractTarget { /** * Construct CatchTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x42) */ protected CatchTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iExceptionTable = stream.readUnsignedShort(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeShort(m_iExceptionTable); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2; } // ----- accessors -------------------------------------------------- /** * Return an index into the {@code exception_table} of the Code attribute. * * @return an index into the {@code exception_table} of the Code attribute */ public int getExceptionTableIndex() { return m_iExceptionTable; } /** * Set an index into the {@code exception_table} of the Code attribute. * * @param iExceptionTable an index into the {@code exception_table} * of the Code attribute * * @throws IllegalArgumentException if iExceptionTable is not within range */ public void setExceptionTableIndex(int iExceptionTable) { if ((iExceptionTable & ~0xFFFF) != 0) { throw new IllegalArgumentException("Index into the exception_table " + "must be in the range 0-65535"); } m_iExceptionTable = iExceptionTable; } // ----- data members ----------------------------------------------- /** * An index into the {@code exception_table} of the Code attribute. */ protected int m_iExceptionTable; } // ----- inner class: OffsetTarget -------------------------------------- /** * TypeAnnotations with a OffsetTarget, target the annotation to the type * in an instanceof expression or a new expression, or * the type before the {@code ::} in a method reference expression. * * @see #TARGET_CODE_INSTANCEOF * @see #TARGET_CODE_NEW * @see #TARGET_CODE_METHOD_REF_NEW * @see #TARGET_CODE_METHOD_REF */ protected static class OffsetTarget extends AbstractTarget { /** * Construct OffsetTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x43, 0x44, 0x45 or 0x46) */ protected OffsetTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iCodeArray = stream.readUnsignedShort(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeShort(m_iCodeArray); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 2; } // ----- accessors -------------------------------------------------- /** * Return an index to an op in the code array of the Code attribute. * * @return an index to an op in the code array of the Code attribute */ public int getCodeArrayIndex() { return m_iCodeArray; } /** * Set the index to an op in the code array of the Code attribute. * * @param iCodeArray an index to an op in the code array of the Code * attribute * * @throws IllegalArgumentException if iCodeArray is not within range */ public void setCodeArrayIndex(int iCodeArray) { if ((iCodeArray & ~0xFFFF) != 0) { throw new IllegalArgumentException("Index into the code array " + "must be in the range 0-65535"); } m_iCodeArray = iCodeArray; } // ----- data members ----------------------------------------------- /** * An index to an op in the code array of the Code attribute. */ protected int m_iCodeArray; } // ----- inner class: TypeArgumentTarget -------------------------------- /** * TypeAnnotations with a TypeArgumentTarget, target the annotation to a * type in either a new expression, an explicit constructor invocation * statement, a method invocation expression, or a method reference expression. * * @see #TARGET_CODE_CAST * @see #TARGET_CODE_CONSTRUCTOR * @see #TARGET_CODE_METHOD * @see #TARGET_CODE_METHOD_REF_NEW_ARG * @see #TARGET_CODE_METHOD_REF_ARG */ protected static class TypeArgumentTarget extends AbstractTarget { /** * Construct TypeArgumentTarget used by {@link TypeAnnotation}. * * @param bType byte representing target_type (0x43, 0x44, 0x45 or 0x46) */ protected TypeArgumentTarget(byte bType) { super(bType); } // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { m_iCodeArray = stream.readUnsignedShort(); m_iTypeArgument = stream.readUnsignedByte(); } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { super.assemble(stream, pool); stream.writeShort(m_iCodeArray); stream.writeByte(m_iTypeArgument); } // ----- AbstractTarget operations ---------------------------------- @Override protected int getSize() { return super.getSize() + 3; } // ----- accessors -------------------------------------------------- /** * Return an index to an op in the code array of the Code attribute. * * @return an index to an op in the code array of the Code attribute */ public int getCodeArrayIndex() { return m_iCodeArray; } /** * Set the index to an op in the code array of the Code attribute. * * @param iCodeArray an index to an op in the code array of the Code * attribute * * @throws IllegalArgumentException if iCodeArray is not within range */ public void setCodeArrayIndex(int iCodeArray) { if ((iCodeArray & ~0xFFFF) != 0) { throw new IllegalArgumentException("Index into the code array " + "must be in the range 0-65535"); } m_iCodeArray = iCodeArray; } /** * Return an index to the type in a cast expression or an index into * an explicit type argument list. * * @return an index to the type in a cast expression or an index into * an explicit type argument list */ public int getTypeIndex() { return m_iTypeArgument; } /** * Set the index to the type in a cast expression or an index into * an explicit type argument list. * * @param iType the index into the type in a cast expression or an index * into an explicit type argument list * * @throws IllegalArgumentException if iType is not within range */ public void setTypeIndex(int iType) { if ((iType & ~0xFF) != 0) { throw new IllegalArgumentException("Index to the type in a cast expression " + " or explicit type argument list must be in the range 0-255"); } m_iTypeArgument = iType; } // ----- data members ----------------------------------------------- /** * An index to an op in the code array of the Code attribute. */ protected int m_iCodeArray; /** * Either an index into the type in a cast expression or an index into * an explicit type argument list. */ protected int m_iTypeArgument; } // ----- inner class: TypePath ------------------------------------------ /** * The TypePath structure allows locating when in a type declaration an * annotation resides. The structure as defined in the JVM 8 specification * is as follows: *


     *    type_path
     *        {
     *        u1 path_length;
     *            {
     *            u1 type_path_kind;
     *            u1 type_argument_index;
     *            } path[path_length];
     *       }
     * 
*/ protected static class TypePath extends VMStructure implements Constants { // ----- VMStructure operations ------------------------------------- @Override protected void disassemble(DataInput stream, ConstantPool pool) throws IOException { int cPath = m_cPath = stream.readUnsignedByte(); char[] acPath = m_achPath; if (cPath > 0) { acPath = m_achPath = new char[cPath]; } for (int i = 0; i < cPath; ++i) { acPath[i] = toChar(stream.readUnsignedByte(), stream.readUnsignedByte()); } } @Override protected void preassemble(ConstantPool pool) { } @Override protected void assemble(DataOutput stream, ConstantPool pool) throws IOException { int cPath = m_cPath; stream.writeByte(cPath); for (int i = 0; i < cPath; ++i) { stream.writeByte(getPathKind(i)); stream.writeByte(getArgumentIndex(i)); } } // ----- public methods --------------------------------------------- /** * Add a path (type_path_kind and type_argument_index) to this TypePath. * * @param nPathKind one of the PATH_KIND_* constants * @param iArgument an index into an argument list * @param iPath an index into the type_path array this path should * reside */ public void addPath(int nPathKind, int iArgument, int iPath) { if ((nPathKind & ~PATH_KIND_MASK) != 0) { throw new IllegalArgumentException("Invalid type_path_kind value: " + nPathKind); } if ((iArgument & ~0xFF) != 0) { throw new IllegalArgumentException("Invalid type_argument_index provided: " + iArgument); } int cPathUsed = size(); if (iPath == -1) { iPath = cPathUsed; } if (iPath >= m_achPath.length) { grow(); } if ((m_achPath[iPath] & 0xFF00) != NO_PATH) { if (m_achPath.length == cPathUsed) { // about to shift elements thus ensure sufficient slots exist grow(); } // shift elements to free-up the slot requested char[] acPath = m_achPath; for (int i = cPathUsed - 1; i >= iPath; --i) { acPath[i + 1] = acPath[i]; } } m_achPath[iPath] = toChar(nPathKind, iArgument); ++m_cPath; } /** * Remove a path from the TypePath. This may cause other paths to move * down a slot. * * @param iPath an index into the type_path array that should be removed */ public void removePath(int iPath) { int cPath = size(); if (iPath < 0) { iPath = cPath; } char[] achPath = m_achPath; for (int i = iPath; i < cPath; ++i) { achPath[i] = achPath[i + 1]; } achPath[cPath - 1] = NO_PATH; --m_cPath; } /** * Return the number of type paths present. * * @return the number of type paths present */ public int size() { return m_cPath; } /** * Return the type_path_kind for the specified path. The returned value * will be -1 if the path has not been defined or one of the PATH_KIND_* * constants. * * @param iPath an index into the type_path array * * @return the type_path_kind for the specified path or -1 */ public int getPathKind(int iPath) { char chPath = m_achPath[iPath]; return chPath == NO_PATH ? -1 : chPath >> 8; } /** * Return the type_argument_index for the specified path, or -1 if the * path does not exist. * * @param iPath an index into the type_path array * * @return the type_argument_index for the specified path, or -1 if the * path does not exist */ public int getArgumentIndex(int iPath) { char chPath = m_achPath[iPath]; return chPath == NO_PATH ? -1 : chPath & 0xFF; } // ----- helpers ---------------------------------------------------- /** * Return the number of bytes consumed by this structure when serialized. * * @return the number of bytes consumed by this structure when serialized */ protected int getSize() { return 1 + 2 * size(); } /** * Grow the internal data structure to accommodate more paths. */ protected void grow() { char[] acOld = m_achPath; int cPath = acOld.length; char[] acNew = new char[cPath + Math.min(Math.max(cPath >> 1, 4), 16)]; Arrays.fill(acNew, Math.max(cPath - 1, 0), acNew.length, NO_PATH); System.arraycopy(acOld, 0, acNew, 0, cPath); } /** * Create a char (unsigned short) representing two unsigned bytes * (type_path_kind and type_argument_index). * * @param nPathKind the type_path_kind value; one of the PATH_KIND_* * constants * @param iArgument the type_argument_index value for this path * * @return a char (unsigned short) representing two unsigned bytes * (type_path_kind and type_argument_index) */ protected static char toChar(int nPathKind, int iArgument) { return (char) (nPathKind << 8 | iArgument); } // ----- constants -------------------------------------------------- /** * Type Path Kind: Annotation is deeper in an array type. */ public static final byte PATH_KIND_ARRAY = 0x0; /** * Type Path Kind: Annotation is deeper in a nested type. */ public static final byte PATH_KIND_NESTED = 0x1; /** * Type Path Kind: Annotation is on the bound of a wildcard type argument * of a parameterized type. */ public static final byte PATH_KIND_BOUND = 0x2; /** * Type Path Kind: Annotation is on a type argument of a parametrized * type. */ public static final byte PATH_KIND_TYPE = 0x3; /** * Mask used to validate a legal path kind. */ private static final byte PATH_KIND_MASK = 0x3; /** * Default value to suggest no path. */ private static final char NO_PATH = (char) 0x8000; // ----- data members ----------------------------------------------- /** * The number of paths to locate where the annotation resides on the * type. */ protected int m_cPath; /** * A char array used to hold the type paths to locate where an annotation * resides on a type declaration. */ protected char[] m_achPath = new char[0]; } // ----- data members --------------------------------------------------- /** * The target this annotation has been placed on. */ protected AbstractTarget m_target; /** * The TypePath structure allows the part of the type annotated to be * located when the target is a type. */ protected TypePath m_typePath; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy