/* |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
/* |
|
* This file is available under and governed by the GNU General Public |
|
* License version 2 only, as published by the Free Software Foundation. |
|
* However, the following notice accompanied the original version of this |
|
* file: |
|
* |
|
* ASM: a very small and fast Java bytecode manipulation framework |
|
* Copyright (c) 2000-2011 INRIA, France Telecom |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* 3. Neither the name of the copyright holders nor the names of its |
|
* contributors may be used to endorse or promote products derived from |
|
* this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
* THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
package jdk.internal.org.objectweb.asm; |
|
/** |
|
* An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation' |
|
* structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter |
|
* instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations |
|
* attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such |
|
* lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes. |
|
* |
|
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS |
|
* 4.7.16</a> |
|
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS |
|
* 4.7.20</a> |
|
* @author Eric Bruneton |
|
* @author Eugene Kuleshov |
|
*/ |
|
final class AnnotationWriter extends AnnotationVisitor { |
|
/** Where the constants used in this AnnotationWriter must be stored. */ |
|
private final SymbolTable symbolTable; |
|
/** |
|
* Whether values are named or not. AnnotationWriter instances used for annotation default and |
|
* annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each |
|
* value, instead of an element_name_index followed by an element_value). |
|
*/ |
|
private final boolean useNamedValues; |
|
/** |
|
* The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values |
|
* visited so far. All the fields of these structures, except the last one - the |
|
* element_value_pairs array, must be set before this ByteVector is passed to the constructor |
|
* (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link |
|
* #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit() |
|
* methods. |
|
* |
|
* <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a |
|
* single element_value by definition), this ByteVector is initially empty when passed to the |
|
* constructor, and {@link #numElementValuePairsOffset} is set to -1. |
|
*/ |
|
private final ByteVector annotation; |
|
/** |
|
* The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for |
|
* the case of AnnotationDefault attributes). |
|
*/ |
|
private final int numElementValuePairsOffset; |
|
/** The number of element value pairs visited so far. */ |
|
private int numElementValuePairs; |
|
/** |
|
* The previous AnnotationWriter. This field is used to store the list of annotations of a |
|
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations |
|
* (annotation values of annotation type), or for AnnotationDefault attributes. |
|
*/ |
|
private final AnnotationWriter previousAnnotation; |
|
/** |
|
* The next AnnotationWriter. This field is used to store the list of annotations of a |
|
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations |
|
* (annotation values of annotation type), or for AnnotationDefault attributes. |
|
*/ |
|
private AnnotationWriter nextAnnotation; |
|
// ----------------------------------------------------------------------------------------------- |
|
// Constructors and factories |
|
// ----------------------------------------------------------------------------------------------- |
|
/** |
|
* Constructs a new {@link AnnotationWriter}. |
|
* |
|
* @param symbolTable where the constants used in this AnnotationWriter must be stored. |
|
* @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays |
|
* use unnamed values. |
|
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to |
|
* the visited content must be stored. This ByteVector must already contain all the fields of |
|
* the structure except the last one (the element_value_pairs array). |
|
* @param previousAnnotation the previously visited annotation of the |
|
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or |
|
* {@literal null} in other cases (e.g. nested or array annotations). |
|
*/ |
|
AnnotationWriter( |
|
final SymbolTable symbolTable, |
|
final boolean useNamedValues, |
|
final ByteVector annotation, |
|
final AnnotationWriter previousAnnotation) { |
|
super(/* latest api = */ Opcodes.ASM8); |
|
this.symbolTable = symbolTable; |
|
this.useNamedValues = useNamedValues; |
|
this.annotation = annotation; |
|
// By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'. |
|
this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2; |
|
this.previousAnnotation = previousAnnotation; |
|
if (previousAnnotation != null) { |
|
previousAnnotation.nextAnnotation = this; |
|
} |
|
} |
|
/** |
|
* Creates a new {@link AnnotationWriter} using named values. |
|
* |
|
* @param symbolTable where the constants used in this AnnotationWriter must be stored. |
|
* @param descriptor the class descriptor of the annotation class. |
|
* @param previousAnnotation the previously visited annotation of the |
|
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or |
|
* {@literal null} in other cases (e.g. nested or array annotations). |
|
* @return a new {@link AnnotationWriter} for the given annotation descriptor. |
|
*/ |
|
static AnnotationWriter create( |
|
final SymbolTable symbolTable, |
|
final String descriptor, |
|
final 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. |
|
ByteVector 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, /* useNamedValues = */ true, annotation, previousAnnotation); |
|
} |
|
/** |
|
* Creates a new {@link AnnotationWriter} using named values. |
|
* |
|
* @param symbolTable where the constants used in this AnnotationWriter must be stored. |
|
* @param typeRef a reference to the annotated type. The sort of this type reference must be |
|
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link |
|
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See |
|
* {@link TypeReference}. |
|
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or |
|
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets |
|
* 'typeRef' as a whole. |
|
* @param descriptor the class descriptor of the annotation class. |
|
* @param previousAnnotation the previously visited annotation of the |
|
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or |
|
* {@literal null} in other cases (e.g. nested or array annotations). |
|
* @return a new {@link AnnotationWriter} for the given type annotation reference and descriptor. |
|
*/ |
|
static AnnotationWriter create( |
|
final SymbolTable symbolTable, |
|
final int typeRef, |
|
final TypePath typePath, |
|
final String descriptor, |
|
final 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. |
|
ByteVector 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, /* useNamedValues = */ true, typeAnnotation, previousAnnotation); |
|
} |
|
// ----------------------------------------------------------------------------------------------- |
|
// Implementation of the AnnotationVisitor abstract class |
|
// ----------------------------------------------------------------------------------------------- |
|
@Override |
|
public void visit(final String name, final 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 instanceof String) { |
|
annotation.put12('s', symbolTable.addConstantUtf8((String) value)); |
|
} else if (value instanceof Byte) { |
|
annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index); |
|
} else if (value instanceof Boolean) { |
|
int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0; |
|
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index); |
|
} else if (value instanceof Character) { |
|
annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index); |
|
} else if (value instanceof Short) { |
|
annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index); |
|
} else if (value instanceof Type) { |
|
annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor())); |
|
} else if (value instanceof byte[]) { |
|
byte[] byteArray = (byte[]) value; |
|
annotation.put12('[', byteArray.length); |
|
for (byte byteValue : byteArray) { |
|
annotation.put12('B', symbolTable.addConstantInteger(byteValue).index); |
|
} |
|
} else if (value instanceof boolean[]) { |
|
boolean[] booleanArray = (boolean[]) value; |
|
annotation.put12('[', booleanArray.length); |
|
for (boolean booleanValue : booleanArray) { |
|
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index); |
|
} |
|
} else if (value instanceof short[]) { |
|
short[] shortArray = (short[]) value; |
|
annotation.put12('[', shortArray.length); |
|
for (short shortValue : shortArray) { |
|
annotation.put12('S', symbolTable.addConstantInteger(shortValue).index); |
|
} |
|
} else if (value instanceof char[]) { |
|
char[] charArray = (char[]) value; |
|
annotation.put12('[', charArray.length); |
|
for (char charValue : charArray) { |
|
annotation.put12('C', symbolTable.addConstantInteger(charValue).index); |
|
} |
|
} else if (value instanceof int[]) { |
|
int[] intArray = (int[]) value; |
|
annotation.put12('[', intArray.length); |
|
for (int intValue : intArray) { |
|
annotation.put12('I', symbolTable.addConstantInteger(intValue).index); |
|
} |
|
} else if (value instanceof long[]) { |
|
long[] longArray = (long[]) value; |
|
annotation.put12('[', longArray.length); |
|
for (long longValue : longArray) { |
|
annotation.put12('J', symbolTable.addConstantLong(longValue).index); |
|
} |
|
} else if (value instanceof float[]) { |
|
float[] floatArray = (float[]) value; |
|
annotation.put12('[', floatArray.length); |
|
for (float floatValue : floatArray) { |
|
annotation.put12('F', symbolTable.addConstantFloat(floatValue).index); |
|
} |
|
} else if (value instanceof double[]) { |
|
double[] doubleArray = (double[]) value; |
|
annotation.put12('[', doubleArray.length); |
|
for (double doubleValue : doubleArray) { |
|
annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index); |
|
} |
|
} else { |
|
Symbol symbol = symbolTable.addConstant(value); |
|
annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index); |
|
} |
|
} |
|
@Override |
|
public void visitEnum(final String name, final String descriptor, final String value) { |
|
// Case of an element_value with an enum_const_value 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)); |
|
} |
|
annotation |
|
.put12('e', symbolTable.addConstantUtf8(descriptor)) |
|
.putShort(symbolTable.addConstantUtf8(value)); |
|
} |
|
@Override |
|
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) { |
|
// Case of an element_value with an annotation_value 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)); |
|
} |
|
// Write tag and type_index, and reserve 2 bytes for num_element_value_pairs. |
|
annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); |
|
return new AnnotationWriter(symbolTable, /* useNamedValues = */ true, annotation, null); |
|
} |
|
@Override |
|
public AnnotationVisitor visitArray(final String name) { |
|
// Case of an element_value with an array_value field. |
|
// 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)); |
|
} |
|
// Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the |
|
// end of an element_value of array type is similar to the end of an 'annotation' structure: an |
|
// unsigned short num_values followed by num_values element_value, versus an unsigned short |
|
// num_element_value_pairs, followed by num_element_value_pairs { element_name_index, |
|
// element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to |
|
// visit the array elements. Its num_element_value_pairs will correspond to the number of array |
|
// elements and will be stored in what is in fact num_values. |
|
annotation.put12('[', 0); |
|
return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null); |
|
} |
|
@Override |
|
public void visitEnd() { |
|
if (numElementValuePairsOffset != -1) { |
|
byte[] data = annotation.data; |
|
data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8); |
|
data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs; |
|
} |
|
} |
|
// ----------------------------------------------------------------------------------------------- |
|
// Utility methods |
|
// ----------------------------------------------------------------------------------------------- |
|
/** |
|
* Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation |
|
* and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name |
|
* to the constant pool of the class (if not null). |
|
* |
|
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or {@literal null}. |
|
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this |
|
* annotation and all its predecessors. This includes the size of the attribute_name_index and |
|
* attribute_length fields. |
|
*/ |
|
int computeAnnotationsSize(final String attributeName) { |
|
if (attributeName != null) { |
|
symbolTable.addConstantUtf8(attributeName); |
|
} |
|
// The attribute_name_index, attribute_length and num_annotations fields use 8 bytes. |
|
int attributeSize = 8; |
|
AnnotationWriter annotationWriter = this; |
|
while (annotationWriter != null) { |
|
attributeSize += annotationWriter.annotation.length; |
|
annotationWriter = annotationWriter.previousAnnotation; |
|
} |
|
return attributeSize; |
|
} |
|
/** |
|
* Returns the size of the Runtime[In]Visible[Type]Annotations attributes containing the given |
|
* annotations and all their <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the |
|
* attribute names to the constant pool of the class (if not null). |
|
* |
|
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or |
|
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be |
|
* {@literal null}. |
|
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field, |
|
* method or class. The previous ones can be accessed with the {@link #previousAnnotation} |
|
* field. May be {@literal null}. |
|
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a |
|
* field, method or class. The previous ones can be accessed with the {@link |
|
* #previousAnnotation} field. May be {@literal null}. |
|
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a |
|
* field, method or class field. The previous ones can be accessed with the {@link |
|
* #previousAnnotation} field. May be {@literal null}. |
|
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing the |
|
* given annotations and all their predecessors. This includes the size of the |
|
* attribute_name_index and attribute_length fields. |
|
*/ |
|
static int computeAnnotationsSize( |
|
final AnnotationWriter lastRuntimeVisibleAnnotation, |
|
final AnnotationWriter lastRuntimeInvisibleAnnotation, |
|
final AnnotationWriter lastRuntimeVisibleTypeAnnotation, |
|
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation) { |
|
int size = 0; |
|
if (lastRuntimeVisibleAnnotation != null) { |
|
size += |
|
lastRuntimeVisibleAnnotation.computeAnnotationsSize( |
|
Constants.RUNTIME_VISIBLE_ANNOTATIONS); |
|
} |
|
if (lastRuntimeInvisibleAnnotation != null) { |
|
size += |
|
lastRuntimeInvisibleAnnotation.computeAnnotationsSize( |
|
Constants.RUNTIME_INVISIBLE_ANNOTATIONS); |
|
} |
|
if (lastRuntimeVisibleTypeAnnotation != null) { |
|
size += |
|
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize( |
|
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS); |
|
} |
|
if (lastRuntimeInvisibleTypeAnnotation != null) { |
|
size += |
|
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize( |
|
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS); |
|
} |
|
return size; |
|
} |
|
/** |
|
* Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its |
|
* <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are |
|
* put in the same order they have been visited. |
|
* |
|
* @param attributeNameIndex the constant pool index of the attribute name (one of |
|
* "Runtime[In]Visible[Type]Annotations"). |
|
* @param output where the attribute must be put. |
|
*/ |
|
void putAnnotations(final int attributeNameIndex, final ByteVector output) { |
|
int attributeLength = 2; // For num_annotations. |
|
int numAnnotations = 0; |
|
AnnotationWriter annotationWriter = this; |
|
AnnotationWriter firstAnnotation = null; |
|
while (annotationWriter != null) { |
|
// In case the user forgot to call visitEnd(). |
|
annotationWriter.visitEnd(); |
|
attributeLength += annotationWriter.annotation.length; |
|
numAnnotations++; |
|
firstAnnotation = annotationWriter; |
|
annotationWriter = annotationWriter.previousAnnotation; |
|
} |
|
output.putShort(attributeNameIndex); |
|
output.putInt(attributeLength); |
|
output.putShort(numAnnotations); |
|
annotationWriter = firstAnnotation; |
|
while (annotationWriter != null) { |
|
output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length); |
|
annotationWriter = annotationWriter.nextAnnotation; |
|
} |
|
} |
|
/** |
|
* Puts the Runtime[In]Visible[Type]Annotations attributes containing the given annotations and |
|
* all their <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. |
|
* Annotations are put in the same order they have been visited. |
|
* |
|
* @param symbolTable where the constants used in the AnnotationWriter instances are stored. |
|
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or |
|
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be |
|
* {@literal null}. |
|
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field, |
|
* method or class. The previous ones can be accessed with the {@link #previousAnnotation} |
|
* field. May be {@literal null}. |
|
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a |
|
* field, method or class. The previous ones can be accessed with the {@link |
|
* #previousAnnotation} field. May be {@literal null}. |
|
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a |
|
* field, method or class field. The previous ones can be accessed with the {@link |
|
* #previousAnnotation} field. May be {@literal null}. |
|
* @param output where the attributes must be put. |
|
*/ |
|
static void putAnnotations( |
|
final SymbolTable symbolTable, |
|
final AnnotationWriter lastRuntimeVisibleAnnotation, |
|
final AnnotationWriter lastRuntimeInvisibleAnnotation, |
|
final AnnotationWriter lastRuntimeVisibleTypeAnnotation, |
|
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation, |
|
final 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); |
|
} |
|
} |
|
/** |
|
* Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the |
|
* annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the |
|
* constant pool of the class. |
|
* |
|
* @param attributeName one of "Runtime[In]VisibleParameterAnnotations". |
|
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i> |
|
* element). |
|
* @param annotableParameterCount the number of elements in annotationWriters to take into account |
|
* (elements [0..annotableParameterCount[ are taken into account). |
|
* @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding |
|
* to the given sub-array of AnnotationWriter lists. This includes the size of the |
|
* attribute_name_index and attribute_length fields. |
|
*/ |
|
static int computeParameterAnnotationsSize( |
|
final String attributeName, |
|
final AnnotationWriter[] annotationWriters, |
|
final int annotableParameterCount) { |
|
// Note: attributeName is added to the constant pool by the call to computeAnnotationsSize |
|
// below. This assumes that there is at least one non-null element in the annotationWriters |
|
// sub-array (which is ensured by the lazy instantiation of this array in MethodWriter). |
|
// The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each |
|
// element of the parameter_annotations array uses 2 bytes for its num_annotations field. |
|
int attributeSize = 7 + 2 * annotableParameterCount; |
|
for (int i = 0; i < annotableParameterCount; ++i) { |
|
AnnotationWriter annotationWriter = annotationWriters[i]; |
|
attributeSize += |
|
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8; |
|
} |
|
return attributeSize; |
|
} |
|
/** |
|
* Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists |
|
* from the given AnnotationWriter sub-array in the given ByteVector. |
|
* |
|
* @param attributeNameIndex constant pool index of the attribute name (one of |
|
* Runtime[In]VisibleParameterAnnotations). |
|
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i> |
|
* element). |
|
* @param annotableParameterCount the number of elements in annotationWriters to put (elements |
|
* [0..annotableParameterCount[ are put). |
|
* @param output where the attribute must be put. |
|
*/ |
|
static void putParameterAnnotations( |
|
final int attributeNameIndex, |
|
final AnnotationWriter[] annotationWriters, |
|
final int annotableParameterCount, |
|
final ByteVector output) { |
|
// The num_parameters field uses 1 byte, and each element of the parameter_annotations array |
|
// uses 2 bytes for its num_annotations field. |
|
int attributeLength = 1 + 2 * annotableParameterCount; |
|
for (int i = 0; i < annotableParameterCount; ++i) { |
|
AnnotationWriter annotationWriter = annotationWriters[i]; |
|
attributeLength += |
|
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8; |
|
} |
|
output.putShort(attributeNameIndex); |
|
output.putInt(attributeLength); |
|
output.putByte(annotableParameterCount); |
|
for (int i = 0; i < annotableParameterCount; ++i) { |
|
AnnotationWriter annotationWriter = annotationWriters[i]; |
|
AnnotationWriter firstAnnotation = null; |
|
int numAnnotations = 0; |
|
while (annotationWriter != null) { |
|
// In case user the forgot to call visitEnd(). |
|
annotationWriter.visitEnd(); |
|
numAnnotations++; |
|
firstAnnotation = annotationWriter; |
|
annotationWriter = annotationWriter.previousAnnotation; |
|
} |
|
output.putShort(numAnnotations); |
|
annotationWriter = firstAnnotation; |
|
while (annotationWriter != null) { |
|
output.putByteArray( |
|
annotationWriter.annotation.data, 0, annotationWriter.annotation.length); |
|
annotationWriter = annotationWriter.nextAnnotation; |
|
} |
|
} |
|
} |
|
} |