/// <summary> /// Puts the Runtime[In]Visible[Type]Annotations attributes containing the given annotations and /// all their <i>predecessors</i> (see /// <see cref="previousAnnotation" /> /// in the given ByteVector. /// Annotations are put in the same order they have been visited. /// </summary> /// <param name="symbolTable"> /// where the constants used in the AnnotationWriter instances are stored. /// </param> /// <param name="lastRuntimeVisibleAnnotation"> /// The last runtime visible annotation of a field, method or /// class. The previous ones can be accessed with the /// <see cref="previousAnnotation" /> /// field. May be /// <literal>null</literal> /// . /// </param> /// <param name="lastRuntimeInvisibleAnnotation"> /// The last runtime invisible annotation of this a field, /// method or class. The previous ones can be accessed with the /// <see cref="previousAnnotation" /> /// field. May be /// <literal>null</literal> /// . /// </param> /// <param name="lastRuntimeVisibleTypeAnnotation"> /// The last runtime visible type annotation of this a /// field, method or class. The previous ones can be accessed with the /// <see cref="previousAnnotation" /> /// field. May be /// <literal>null</literal> /// . /// </param> /// <param name="lastRuntimeInvisibleTypeAnnotation"> /// The last runtime invisible type annotation of a /// field, method or class field. The previous ones can be accessed with the /// <see cref="previousAnnotation" /> /// field. May be /// <literal>null</literal> /// . /// </param> /// <param name="output">where the attributes must be put.</param> internal static void PutAnnotations(SymbolTable symbolTable, AnnotationWriter lastRuntimeVisibleAnnotation , AnnotationWriter lastRuntimeInvisibleAnnotation, AnnotationWriter lastRuntimeVisibleTypeAnnotation , AnnotationWriter lastRuntimeInvisibleTypeAnnotation, ByteVector output) { if (lastRuntimeVisibleAnnotation != null) { lastRuntimeVisibleAnnotation.PutAnnotations(symbolTable.AddConstantUtf8(Constants .Runtime_Visible_Annotations), output); } if (lastRuntimeInvisibleAnnotation != null) { lastRuntimeInvisibleAnnotation.PutAnnotations(symbolTable.AddConstantUtf8(Constants .Runtime_Invisible_Annotations), output); } if (lastRuntimeVisibleTypeAnnotation != null) { lastRuntimeVisibleTypeAnnotation.PutAnnotations(symbolTable.AddConstantUtf8(Constants .Runtime_Visible_Type_Annotations), output); } if (lastRuntimeInvisibleTypeAnnotation != null) { lastRuntimeInvisibleTypeAnnotation.PutAnnotations(symbolTable.AddConstantUtf8(Constants .Runtime_Invisible_Type_Annotations), output); } }
/// <summary> /// Returns the total size in bytes of all the attributes that correspond to the given field, /// method or class access flags and signature. /// </summary> /// <remarks> /// Returns the total size in bytes of all the attributes that correspond to the given field, /// method or class access flags and signature. This size includes the 6 header bytes /// (attribute_name_index and attribute_length) per attribute. Also adds the attribute type names /// to the constant pool. /// </remarks> /// <param name="symbolTable"> /// where the constants used in the attributes must be stored. /// </param> /// <param name="accessFlags">some field, method or class access flags.</param> /// <param name="signatureIndex"> /// the constant pool index of a field, method of class signature. /// </param> /// <returns> /// the size of all the attributes in bytes. This size includes the size of the attribute /// headers. /// </returns> internal static int ComputeAttributesSize(SymbolTable symbolTable, AccessFlags accessFlags , int signatureIndex) { var size = 0; // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. if (accessFlags.HasFlagFast(AccessFlags.Synthetic) && symbolTable.GetMajorVersion () < OpcodesConstants.V1_5) { // Synthetic attributes always use 6 bytes. symbolTable.AddConstantUtf8(Constants.Synthetic); size += 6; } if (signatureIndex != 0) { // Signature attributes always use 8 bytes. symbolTable.AddConstantUtf8(Constants.Signature); size += 8; } // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead. if (accessFlags.HasFlagFast(AccessFlags.Deprecated)) { // Deprecated attributes always use 6 bytes. symbolTable.AddConstantUtf8(Constants.Deprecated); size += 6; } return(size); }
/// <summary> /// Constructs a new /// <see cref="RecordComponentWriter" /> /// . /// </summary> /// <param name="symbolTable"> /// where the constants used in this RecordComponentWriter must be stored. /// </param> /// <param name="accessFlags"> /// the record component access flags, only synthetic and/or deprecated. /// </param> /// <param name="name">the record component name.</param> /// <param name="descriptor"> /// the record component descriptor (see /// <see cref="Type" /> /// ). /// </param> /// <param name="signature"> /// the record component signature. May be /// <literal>null</literal> /// . /// </param> internal RecordComponentWriter(SymbolTable symbolTable, AccessFlags accessFlags, string name , string descriptor, string signature) : base(VisitorAsmApiVersion.Asm7) { // Note: fields are ordered as in the component_info structure, and those related to attributes // are ordered as in Section TODO of the JVMS. // The field accessFlag doesn't exist in the component_info structure but is used to carry // ACC_DEPRECATED which is represented by an attribute in the structure and as an access flag by // ASM. /* latest api = */ this.symbolTable = symbolTable; this.accessFlags = accessFlags; nameIndex = symbolTable.AddConstantUtf8(name); descriptorIndex = symbolTable.AddConstantUtf8(descriptor); if (signature != null) { signatureIndex = symbolTable.AddConstantUtf8(signature); } }
/// <summary> /// Puts all the attributes that correspond to the given field, method or class access flags and /// signature, in the given byte vector. /// </summary> /// <remarks> /// Puts all the attributes that correspond to the given field, method or class access flags and /// signature, in the given byte vector. This includes the 6 header bytes (attribute_name_index and /// attribute_length) per attribute. /// </remarks> /// <param name="symbolTable"> /// where the constants used in the attributes must be stored. /// </param> /// <param name="accessFlags">some field, method or class access flags.</param> /// <param name="signatureIndex"> /// the constant pool index of a field, method of class signature. /// </param> /// <param name="output">where the attributes must be written.</param> internal static void PutAttributes(SymbolTable symbolTable, AccessFlags accessFlags, int signatureIndex, ByteVector output) { // Before Java 1.5, synthetic fields are represented with a Synthetic attribute. if (accessFlags.HasFlagFast(AccessFlags.Synthetic) && symbolTable.GetMajorVersion () < OpcodesConstants.V1_5) { output.PutShort(symbolTable.AddConstantUtf8(Constants.Synthetic)).PutInt(0); } if (signatureIndex != 0) { output.PutShort(symbolTable.AddConstantUtf8(Constants.Signature)).PutInt(2).PutShort (signatureIndex); } if (accessFlags.HasFlagFast(AccessFlags.Deprecated)) { output.PutShort(symbolTable.AddConstantUtf8(Constants.Deprecated)).PutInt(0); } }
/// <summary> /// Creates a new /// <see cref="AnnotationWriter" /> /// using named values. /// </summary> /// <param name="symbolTable"> /// where the constants used in this AnnotationWriter must be stored. /// </param> /// <param name="descriptor">the class descriptor of the annotation class.</param> /// <param name="previousAnnotation"> /// the previously visited annotation of the /// Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or /// <literal>null</literal> /// in other cases (e.g. nested or array annotations). /// </param> /// <returns> /// a new /// <see cref="AnnotationWriter" /> /// for the given annotation descriptor. /// </returns> internal static AnnotationWriter Create(SymbolTable symbolTable, string descriptor , AnnotationWriter previousAnnotation) { // Create a ByteVector to hold an 'annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16. var annotation = new ByteVector(); // Write type_index and reserve space for num_element_value_pairs. annotation.PutShort(symbolTable.AddConstantUtf8(descriptor)).PutShort(0); return(new AnnotationWriter(symbolTable, true, annotation, previousAnnotation)); }
// Nothing to do. // ----------------------------------------------------------------------------------------------- // Utility methods // ----------------------------------------------------------------------------------------------- /// <summary> /// Returns the size of the field_info JVMS structure generated by this FieldWriter. /// </summary> /// <remarks> /// Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the /// names of the attributes of this field in the constant pool. /// </remarks> /// <returns>the size in bytes of the field_info JVMS structure.</returns> internal int ComputeFieldInfoSize() { // The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes. var size = 8; // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. if (constantValueIndex != 0) { // ConstantValue attributes always use 8 bytes. symbolTable.AddConstantUtf8(Constants.Constant_Value); size += 8; } size += Attribute.ComputeAttributesSize(symbolTable, accessFlags, signatureIndex); size += AnnotationWriter.ComputeAnnotationsSize(lastRuntimeVisibleAnnotation, lastRuntimeInvisibleAnnotation , lastRuntimeVisibleTypeAnnotation, lastRuntimeInvisibleTypeAnnotation); if (firstAttribute != null) { size += firstAttribute.ComputeAttributesSize(symbolTable); } return(size); }
/// <summary> /// Constructs a new /// <see cref="FieldWriter" /> /// . /// </summary> /// <param name="symbolTable"> /// where the constants used in this FieldWriter must be stored. /// </param> /// <param name="access"> /// the field's access flags (see /// <see cref="Opcodes" /> /// ). /// </param> /// <param name="name">the field's name.</param> /// <param name="descriptor"> /// the field's descriptor (see /// <see cref="Type" /> /// ). /// </param> /// <param name="signature"> /// the field's signature. May be /// <literal>null</literal> /// . /// </param> /// <param name="constantValue"> /// the field's constant value. May be /// <literal>null</literal> /// . /// </param> internal FieldWriter(SymbolTable symbolTable, AccessFlags access, string name, string descriptor , string signature, object constantValue) : base(VisitorAsmApiVersion.Asm7) { // Note: fields are ordered as in the field_info structure, and those related to attributes are // ordered as in Section 4.7 of the JVMS. // ----------------------------------------------------------------------------------------------- // Constructor // ----------------------------------------------------------------------------------------------- /* latest api = */ this.symbolTable = symbolTable; accessFlags = access; nameIndex = symbolTable.AddConstantUtf8(name); descriptorIndex = symbolTable.AddConstantUtf8(descriptor); if (signature != null) { signatureIndex = symbolTable.AddConstantUtf8(signature); } if (constantValue != null) { constantValueIndex = symbolTable.AddConstant(constantValue).index; } }
/* useNamedValues = */ /// <summary> /// Creates a new /// <see cref="AnnotationWriter" /> /// using named values. /// </summary> /// <param name="symbolTable"> /// where the constants used in this AnnotationWriter must be stored. /// </param> /// <param name="typeRef"> /// a reference to the annotated type. The sort of this type reference must be /// <see cref="TypeReference.Class_Type_Parameter" /> /// , /// <see cref="TypeReference.Class_Type_Parameter_Bound" /> /// or /// <see cref="TypeReference.Class_Extends" /> /// . See /// <see cref="TypeReference" /> /// . /// </param> /// <param name="typePath"> /// the path to the annotated type argument, wildcard bound, array element type, or /// static inner type within 'typeRef'. May be /// <literal>null</literal> /// if the annotation targets /// 'typeRef' as a whole. /// </param> /// <param name="descriptor">the class descriptor of the annotation class.</param> /// <param name="previousAnnotation"> /// the previously visited annotation of the /// Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or /// <literal>null</literal> /// in other cases (e.g. nested or array annotations). /// </param> /// <returns> /// a new /// <see cref="AnnotationWriter" /> /// for the given type annotation reference and descriptor. /// </returns> internal static AnnotationWriter Create(SymbolTable symbolTable, int typeRef, TypePath typePath, string descriptor, AnnotationWriter previousAnnotation) { // Create a ByteVector to hold a 'type_annotation' JVMS structure. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20. var typeAnnotation = new ByteVector(); // Write target_type, target_info, and target_path. TypeReference.PutTarget(typeRef, typeAnnotation); TypePath.Put(typePath, typeAnnotation); // Write type_index and reserve space for num_element_value_pairs. typeAnnotation.PutShort(symbolTable.AddConstantUtf8(descriptor)).PutShort(0); return(new AnnotationWriter(symbolTable, true, typeAnnotation, previousAnnotation )); }
/// <summary> /// Returns the total size in bytes of all the attributes in the attribute list that begins with /// this attribute. /// </summary> /// <remarks> /// Returns the total size in bytes of all the attributes in the attribute list that begins with /// this attribute. This size includes the 6 header bytes (attribute_name_index and /// attribute_length) per attribute. Also adds the attribute type names to the constant pool. /// </remarks> /// <param name="symbolTable"> /// where the constants used in the attributes must be stored. /// </param> /// <param name="code"> /// the bytecode of the method corresponding to these Code attributes, or /// <literal>null</literal> /// if they are not Code attributes. Corresponds to the 'code' field of the Code /// attribute. /// </param> /// <param name="codeLength"> /// the length of the bytecode of the method corresponding to these code /// attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of /// the Code attribute. /// </param> /// <param name="maxStack"> /// the maximum stack size of the method corresponding to these Code attributes, or /// -1 if they are not Code attributes. /// </param> /// <param name="maxLocals"> /// the maximum number of local variables of the method corresponding to these /// Code attributes, or -1 if they are not Code attribute. /// </param> /// <returns> /// the size of all the attributes in this attribute list. This size includes the size of /// the attribute headers. /// </returns> internal int ComputeAttributesSize(SymbolTable symbolTable, byte[] code, int codeLength , int maxStack, int maxLocals) { var classWriter = symbolTable.classWriter; var size = 0; var attribute = this; while (attribute != null) { symbolTable.AddConstantUtf8(attribute.type); size += 6 + attribute.Write(classWriter, code, codeLength, maxStack, maxLocals).length; attribute = attribute.nextAttribute; } return(size); }
/// <summary> /// Puts all the attributes of the attribute list that begins with this attribute, in the given /// byte vector. /// </summary> /// <remarks> /// Puts all the attributes of the attribute list that begins with this attribute, in the given /// byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per /// attribute. /// </remarks> /// <param name="symbolTable"> /// where the constants used in the attributes must be stored. /// </param> /// <param name="code"> /// the bytecode of the method corresponding to these Code attributes, or /// <literal>null</literal> /// if they are not Code attributes. Corresponds to the 'code' field of the Code /// attribute. /// </param> /// <param name="codeLength"> /// the length of the bytecode of the method corresponding to these code /// attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of /// the Code attribute. /// </param> /// <param name="maxStack"> /// the maximum stack size of the method corresponding to these Code attributes, or /// -1 if they are not Code attributes. /// </param> /// <param name="maxLocals"> /// the maximum number of local variables of the method corresponding to these /// Code attributes, or -1 if they are not Code attribute. /// </param> /// <param name="output">where the attributes must be written.</param> internal void PutAttributes(SymbolTable symbolTable, byte[] code, int codeLength, int maxStack, int maxLocals, ByteVector output) { var classWriter = symbolTable.classWriter; var attribute = this; while (attribute != null) { var attributeContent = attribute.Write(classWriter, code, codeLength, maxStack , maxLocals); // Put attribute_name_index and attribute_length. output.PutShort(symbolTable.AddConstantUtf8(attribute.type)).PutInt(attributeContent .length); output.PutByteArray(attributeContent.data, 0, attributeContent.length); attribute = attribute.nextAttribute; } }
/* useNamedValues = */ // ----------------------------------------------------------------------------------------------- // Implementation of the AnnotationVisitor abstract class // ----------------------------------------------------------------------------------------------- public override void Visit(string name, object value) { // Case of an element_value with a const_value_index, class_info_index or array_index field. // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1. ++numElementValuePairs; if (useNamedValues) { annotation.PutShort(symbolTable.AddConstantUtf8(name)); } if (value is string) { annotation.Put12('s', symbolTable.AddConstantUtf8((string)value)); } else if (value is byte) { annotation.Put12('B', symbolTable.AddConstantInteger((byte)value).index); } else if (value is bool) { var booleanValue = (bool)value ? 1 : 0; annotation.Put12('Z', symbolTable.AddConstantInteger(booleanValue).index); } else if (value is char) { annotation.Put12('C', symbolTable.AddConstantInteger((char)value).index); } else if (value is short) { annotation.Put12('S', symbolTable.AddConstantInteger((short)value).index); } else if (value is Type) { annotation.Put12('c', symbolTable.AddConstantUtf8(((Type)value).GetDescriptor())); } else if (value is byte[]) { var byteArray = (byte[])value; annotation.Put12('[', byteArray.Length); foreach (var byteValue in byteArray) { annotation.Put12('B', symbolTable.AddConstantInteger(byteValue).index); } } else if (value is bool[]) { var booleanArray = (bool[])value; annotation.Put12('[', booleanArray.Length); foreach (var booleanValue in booleanArray) { annotation.Put12('Z', symbolTable.AddConstantInteger(booleanValue ? 1 : 0).index); } } else if (value is short[]) { var shortArray = (short[])value; annotation.Put12('[', shortArray.Length); foreach (var shortValue in shortArray) { annotation.Put12('S', symbolTable.AddConstantInteger(shortValue).index); } } else if (value is char[]) { var charArray = (char[])value; annotation.Put12('[', charArray.Length); foreach (var charValue in charArray) { annotation.Put12('C', symbolTable.AddConstantInteger(charValue).index); } } else if (value is int[]) { var intArray = (int[])value; annotation.Put12('[', intArray.Length); foreach (var intValue in intArray) { annotation.Put12('I', symbolTable.AddConstantInteger(intValue).index); } } else if (value is long[]) { var longArray = (long[])value; annotation.Put12('[', longArray.Length); foreach (var longValue in longArray) { annotation.Put12('J', symbolTable.AddConstantLong(longValue).index); } } else if (value is float[]) { var floatArray = (float[])value; annotation.Put12('[', floatArray.Length); foreach (var floatValue in floatArray) { annotation.Put12('F', symbolTable.AddConstantFloat(floatValue).index); } } else if (value is double[]) { var doubleArray = (double[])value; annotation.Put12('[', doubleArray.Length); foreach (var doubleValue in doubleArray) { annotation.Put12('D', symbolTable.AddConstantDouble(doubleValue).index); } } else { var symbol = symbolTable.AddConstant(value); annotation.Put12(".s.IFJDCS"[symbol.tag], symbol.index); } }
public override void VisitRequire(string module, AccessFlags access, string version) { requires.PutShort(symbolTable.AddConstantModule(module).index).PutShort((int)access).PutShort (version == null ? 0 : symbolTable.AddConstantUtf8(version)); requiresCount++; }