mvel/SOURCES/0-use-system-asm.patch
2021-09-09 22:34:24 +00:00

18206 lines
766 KiB
Diff

diff --git a/pom.xml b/pom.xml
index 5e37c24..9f04c58 100644
--- a/pom.xml
+++ b/pom.xml
@@ -260,6 +260,16 @@
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm</artifactId>
+ <version>5.0.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.ow2.asm</groupId>
+ <artifactId>asm-util</artifactId>
+ <version>5.0.4</version>
+ </dependency>
</dependencies>
<distributionManagement>
diff --git a/src/main/java/org/mvel2/asm/AnnotationVisitor.java b/src/main/java/org/mvel2/asm/AnnotationVisitor.java
deleted file mode 100644
index c706a8a..0000000
--- a/src/main/java/org/mvel2/asm/AnnotationVisitor.java
+++ /dev/null
@@ -1,145 +0,0 @@
-// 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 org.mvel2.asm;
-
-/**
- * A visitor to visit a Java annotation. The methods of this class must be called in the following
- * order: ( {@code visit} | {@code visitEnum} | {@code visitAnnotation} | {@code visitArray} )*
- * {@code visitEnd}.
- *
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public abstract class AnnotationVisitor {
-
- /**
- * The ASM API version implemented by this visitor. The value of this field must be one of {@link
- * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
- */
- protected final int api;
-
- /** The annotation visitor to which this visitor must delegate method calls. May be null. */
- protected AnnotationVisitor av;
-
- /**
- * Constructs a new {@link AnnotationVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link
- * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
- */
- public AnnotationVisitor(final int api) {
- this(api, null);
- }
-
- /**
- * Constructs a new {@link AnnotationVisitor}.
- *
- * @param api the ASM API version implemented by this visitor. Must be one of {@link
- * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
- * @param annotationVisitor the annotation visitor to which this visitor must delegate method
- * calls. May be null.
- */
- public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
- if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
- throw new IllegalArgumentException();
- }
- this.api = api;
- this.av = annotationVisitor;
- }
-
- /**
- * Visits a primitive value of the annotation.
- *
- * @param name the value name.
- * @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
- * Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
- * {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
- * value can also be an array of byte, boolean, short, char, int, long, float or double values
- * (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
- * but is more convenient).
- */
- public void visit(final String name, final Object value) {
- if (av != null) {
- av.visit(name, value);
- }
- }
-
- /**
- * Visits an enumeration value of the annotation.
- *
- * @param name the value name.
- * @param descriptor the class descriptor of the enumeration class.
- * @param value the actual enumeration value.
- */
- public void visitEnum(final String name, final String descriptor, final String value) {
- if (av != null) {
- av.visitEnum(name, descriptor, value);
- }
- }
-
- /**
- * Visits a nested annotation value of the annotation.
- *
- * @param name the value name.
- * @param descriptor the class descriptor of the nested annotation class.
- * @return a visitor to visit the actual nested annotation value, or {@literal null} if this
- * visitor is not interested in visiting this nested annotation. <i>The nested annotation
- * value must be fully visited before calling other methods on this annotation visitor</i>.
- */
- public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
- if (av != null) {
- return av.visitAnnotation(name, descriptor);
- }
- return null;
- }
-
- /**
- * Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
- * boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
- * visit}. This is what {@link ClassReader} does.
- *
- * @param name the value name.
- * @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
- * is not interested in visiting these values. The 'name' parameters passed to the methods of
- * this visitor are ignored. <i>All the array values must be visited before calling other
- * methods on this annotation visitor</i>.
- */
- public AnnotationVisitor visitArray(final String name) {
- if (av != null) {
- return av.visitArray(name);
- }
- return null;
- }
-
- /** Visits the end of the annotation. */
- public void visitEnd() {
- if (av != null) {
- av.visitEnd();
- }
- }
-}
diff --git a/src/main/java/org/mvel2/asm/AnnotationWriter.java b/src/main/java/org/mvel2/asm/AnnotationWriter.java
deleted file mode 100644
index 370135b..0000000
--- a/src/main/java/org/mvel2/asm/AnnotationWriter.java
+++ /dev/null
@@ -1,418 +0,0 @@
-// 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 org.mvel2.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
- // -----------------------------------------------------------------------------------------------
-
- /**
- * 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 null in
- * other cases (e.g. nested or array annotations).
- */
- AnnotationWriter(
- final SymbolTable symbolTable,
- final boolean useNamedValues,
- final ByteVector annotation,
- final AnnotationWriter previousAnnotation) {
- super(Opcodes.ASM7);
- 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;
- }
- }
-
- /**
- * Constructs a new {@link AnnotationWriter} using named values.
- *
- * @param symbolTable where the constants used in this AnnotationWriter must be stored.
- * @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 null in
- * other cases (e.g. nested or array annotations).
- */
- AnnotationWriter(
- final SymbolTable symbolTable,
- final ByteVector annotation,
- final AnnotationWriter previousAnnotation) {
- this(symbolTable, /* useNamedValues = */ true, annotation, 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, 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 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;
- }
-
- /**
- * 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;
- }
- }
-
- /**
- * 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;
- }
- }
- }
-}
diff --git a/src/main/java/org/mvel2/asm/Attribute.java b/src/main/java/org/mvel2/asm/Attribute.java
deleted file mode 100644
index 17de1c9..0000000
--- a/src/main/java/org/mvel2/asm/Attribute.java
+++ /dev/null
@@ -1,325 +0,0 @@
-// 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 org.mvel2.asm;
-
-/**
- * A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
- * Specification (JVMS).
- *
- * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
- * 4.7</a>
- * @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
- * 4.7.3</a>
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public class Attribute {
-
- /** The type of this attribute, also called its name in the JVMS. */
- public final String type;
-
- /**
- * The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
- * The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
- * included.
- */
- private byte[] content;
-
- /**
- * The next attribute in this attribute list (Attribute instances can be linked via this field to
- * store a list of class, field, method or code attributes). May be {@literal null}.
- */
- Attribute nextAttribute;
-
- /**
- * Constructs a new empty attribute.
- *
- * @param type the type of the attribute.
- */
- protected Attribute(final String type) {
- this.type = type;
- }
-
- /**
- * Returns {@literal true} if this type of attribute is unknown. This means that the attribute
- * content can't be parsed to extract constant pool references, labels, etc. Instead, the
- * attribute content is read as an opaque byte array, and written back as is. This can lead to
- * invalid attributes, if the content actually contains constant pool references, labels, or other
- * symbolic references that need to be updated when there are changes to the constant pool, the
- * method bytecode, etc. The default implementation of this method always returns {@literal true}.
- *
- * @return {@literal true} if this type of attribute is unknown.
- */
- public boolean isUnknown() {
- return true;
- }
-
- /**
- * Returns {@literal true} if this type of attribute is a code attribute.
- *
- * @return {@literal true} if this type of attribute is a code attribute.
- */
- public boolean isCodeAttribute() {
- return false;
- }
-
- /**
- * Returns the labels corresponding to this attribute.
- *
- * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
- * a code attribute that contains labels.
- */
- protected Label[] getLabels() {
- return new Label[0];
- }
-
- /**
- * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
- * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
- * ClassReader.
- *
- * @param classReader the class that contains the attribute to be read.
- * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
- * 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
- * account here.
- * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
- * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
- * 'charBuffer' parameter.
- * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
- * in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
- * attribute header bytes (attribute_name_index and attribute_length) are not taken into
- * account here.
- * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
- * is not a code attribute.
- * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
- */
- protected Attribute read(
- final ClassReader classReader,
- final int offset,
- final int length,
- final char[] charBuffer,
- final int codeAttributeOffset,
- final Label[] labels) {
- Attribute attribute = new Attribute(type);
- attribute.content = new byte[length];
- System.arraycopy(classReader.b, offset, attribute.content, 0, length);
- return attribute;
- }
-
- /**
- * Returns the byte array form of the content of this attribute. The 6 header bytes
- * (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
- * ByteVector.
- *
- * @param classWriter the class to which this attribute must be added. This parameter can be used
- * to add the items that corresponds to this attribute to the constant pool of this class.
- * @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
- * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
- * attribute.
- * @param codeLength the length of the bytecode of the method corresponding to this code
- * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
- * field of the Code attribute.
- * @param maxStack the maximum stack size of the method corresponding to this code attribute, or
- * -1 if this attribute is not a code attribute.
- * @param maxLocals the maximum number of local variables of the method corresponding to this code
- * attribute, or -1 if this attribute is not a code attribute.
- * @return the byte array form of this attribute.
- */
- protected ByteVector write(
- final ClassWriter classWriter,
- final byte[] code,
- final int codeLength,
- final int maxStack,
- final int maxLocals) {
- return new ByteVector(content);
- }
-
- /**
- * Returns the number of attributes of the attribute list that begins with this attribute.
- *
- * @return the number of attributes of the attribute list that begins with this attribute.
- */
- final int getAttributeCount() {
- int count = 0;
- Attribute attribute = this;
- while (attribute != null) {
- count += 1;
- attribute = attribute.nextAttribute;
- }
- return count;
- }
-
- /**
- * 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.
- *
- * @param symbolTable where the constants used in the attributes must be stored.
- * @return the size of all the attributes in this attribute list. This size includes the size of
- * the attribute headers.
- */
- final int computeAttributesSize(final SymbolTable symbolTable) {
- final byte[] code = null;
- final int codeLength = 0;
- final int maxStack = -1;
- final int maxLocals = -1;
- return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
- }
-
- /**
- * 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.
- *
- * @param symbolTable where the constants used in the attributes must be stored.
- * @param code the bytecode of the method corresponding to these code attributes, or {@literal
- * null} if they are not code attributes. Corresponds to the 'code' field of the Code
- * attribute.
- * @param 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 maxStack the maximum stack size of the method corresponding to these code attributes, or
- * -1 if they are not code attributes.
- * @param maxLocals the maximum number of local variables of the method corresponding to these
- * code attributes, or -1 if they are not code attribute.
- * @return the size of all the attributes in this attribute list. This size includes the size of
- * the attribute headers.
- */
- final int computeAttributesSize(
- final SymbolTable symbolTable,
- final byte[] code,
- final int codeLength,
- final int maxStack,
- final int maxLocals) {
- final ClassWriter classWriter = symbolTable.classWriter;
- int size = 0;
- Attribute attribute = this;
- while (attribute != null) {
- symbolTable.addConstantUtf8(attribute.type);
- size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
- attribute = attribute.nextAttribute;
- }
- return size;
- }
-
- /**
- * 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.
- *
- * @param symbolTable where the constants used in the attributes must be stored.
- * @param output where the attributes must be written.
- */
- final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
- final byte[] code = null;
- final int codeLength = 0;
- final int maxStack = -1;
- final int maxLocals = -1;
- putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
- }
-
- /**
- * 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.
- *
- * @param symbolTable where the constants used in the attributes must be stored.
- * @param code the bytecode of the method corresponding to these code attributes, or {@literal
- * null} if they are not code attributes. Corresponds to the 'code' field of the Code
- * attribute.
- * @param 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 maxStack the maximum stack size of the method corresponding to these code attributes, or
- * -1 if they are not code attributes.
- * @param maxLocals the maximum number of local variables of the method corresponding to these
- * code attributes, or -1 if they are not code attribute.
- * @param output where the attributes must be written.
- */
- final void putAttributes(
- final SymbolTable symbolTable,
- final byte[] code,
- final int codeLength,
- final int maxStack,
- final int maxLocals,
- final ByteVector output) {
- final ClassWriter classWriter = symbolTable.classWriter;
- Attribute attribute = this;
- while (attribute != null) {
- ByteVector 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;
- }
- }
-
- /** A set of attribute prototypes (attributes with the same type are considered equal). */
- static final class Set {
-
- private static final int SIZE_INCREMENT = 6;
-
- private int size;
- private Attribute[] data = new Attribute[SIZE_INCREMENT];
-
- void addAttributes(final Attribute attributeList) {
- Attribute attribute = attributeList;
- while (attribute != null) {
- if (!contains(attribute)) {
- add(attribute);
- }
- attribute = attribute.nextAttribute;
- }
- }
-
- Attribute[] toArray() {
- Attribute[] result = new Attribute[size];
- System.arraycopy(data, 0, result, 0, size);
- return result;
- }
-
- private boolean contains(final Attribute attribute) {
- for (int i = 0; i < size; ++i) {
- if (data[i].type.equals(attribute.type)) {
- return true;
- }
- }
- return false;
- }
-
- private void add(final Attribute attribute) {
- if (size >= data.length) {
- Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
- System.arraycopy(data, 0, newData, 0, size);
- data = newData;
- }
- data[size++] = attribute;
- }
- }
-}
diff --git a/src/main/java/org/mvel2/asm/ByteVector.java b/src/main/java/org/mvel2/asm/ByteVector.java
deleted file mode 100644
index da613be..0000000
--- a/src/main/java/org/mvel2/asm/ByteVector.java
+++ /dev/null
@@ -1,361 +0,0 @@
-// 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 org.mvel2.asm;
-
-/**
- * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
- * on top of a ByteArrayOutputStream, but is more efficient.
- *
- * @author Eric Bruneton
- */
-public class ByteVector {
-
- /** The content of this vector. Only the first {@link #length} bytes contain real data. */
- byte[] data;
-
- /** The actual number of bytes in this vector. */
- int length;
-
- /** Constructs a new {@link ByteVector} with a default initial capacity. */
- public ByteVector() {
- data = new byte[64];
- }
-
- /**
- * Constructs a new {@link ByteVector} with the given initial capacity.
- *
- * @param initialCapacity the initial capacity of the byte vector to be constructed.
- */
- public ByteVector(final int initialCapacity) {
- data = new byte[initialCapacity];
- }
-
- /**
- * Constructs a new {@link ByteVector} from the given initial data.
- *
- * @param data the initial data of the new byte vector.
- */
- ByteVector(final byte[] data) {
- this.data = data;
- this.length = data.length;
- }
-
- /**
- * Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param byteValue a byte.
- * @return this byte vector.
- */
- public ByteVector putByte(final int byteValue) {
- int currentLength = length;
- if (currentLength + 1 > data.length) {
- enlarge(1);
- }
- data[currentLength++] = (byte) byteValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param byteValue1 a byte.
- * @param byteValue2 another byte.
- * @return this byte vector.
- */
- final ByteVector put11(final int byteValue1, final int byteValue2) {
- int currentLength = length;
- if (currentLength + 2 > data.length) {
- enlarge(2);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) byteValue1;
- currentData[currentLength++] = (byte) byteValue2;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param shortValue a short.
- * @return this byte vector.
- */
- public ByteVector putShort(final int shortValue) {
- int currentLength = length;
- if (currentLength + 2 > data.length) {
- enlarge(2);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) (shortValue >>> 8);
- currentData[currentLength++] = (byte) shortValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
- * necessary.
- *
- * @param byteValue a byte.
- * @param shortValue a short.
- * @return this byte vector.
- */
- final ByteVector put12(final int byteValue, final int shortValue) {
- int currentLength = length;
- if (currentLength + 3 > data.length) {
- enlarge(3);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) byteValue;
- currentData[currentLength++] = (byte) (shortValue >>> 8);
- currentData[currentLength++] = (byte) shortValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
- * necessary.
- *
- * @param byteValue1 a byte.
- * @param byteValue2 another byte.
- * @param shortValue a short.
- * @return this byte vector.
- */
- final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
- int currentLength = length;
- if (currentLength + 4 > data.length) {
- enlarge(4);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) byteValue1;
- currentData[currentLength++] = (byte) byteValue2;
- currentData[currentLength++] = (byte) (shortValue >>> 8);
- currentData[currentLength++] = (byte) shortValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param intValue an int.
- * @return this byte vector.
- */
- public ByteVector putInt(final int intValue) {
- int currentLength = length;
- if (currentLength + 4 > data.length) {
- enlarge(4);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) (intValue >>> 24);
- currentData[currentLength++] = (byte) (intValue >>> 16);
- currentData[currentLength++] = (byte) (intValue >>> 8);
- currentData[currentLength++] = (byte) intValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
- * if necessary.
- *
- * @param byteValue a byte.
- * @param shortValue1 a short.
- * @param shortValue2 another short.
- * @return this byte vector.
- */
- final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
- int currentLength = length;
- if (currentLength + 5 > data.length) {
- enlarge(5);
- }
- byte[] currentData = data;
- currentData[currentLength++] = (byte) byteValue;
- currentData[currentLength++] = (byte) (shortValue1 >>> 8);
- currentData[currentLength++] = (byte) shortValue1;
- currentData[currentLength++] = (byte) (shortValue2 >>> 8);
- currentData[currentLength++] = (byte) shortValue2;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
- *
- * @param longValue a long.
- * @return this byte vector.
- */
- public ByteVector putLong(final long longValue) {
- int currentLength = length;
- if (currentLength + 8 > data.length) {
- enlarge(8);
- }
- byte[] currentData = data;
- int intValue = (int) (longValue >>> 32);
- currentData[currentLength++] = (byte) (intValue >>> 24);
- currentData[currentLength++] = (byte) (intValue >>> 16);
- currentData[currentLength++] = (byte) (intValue >>> 8);
- currentData[currentLength++] = (byte) intValue;
- intValue = (int) longValue;
- currentData[currentLength++] = (byte) (intValue >>> 24);
- currentData[currentLength++] = (byte) (intValue >>> 16);
- currentData[currentLength++] = (byte) (intValue >>> 8);
- currentData[currentLength++] = (byte) intValue;
- length = currentLength;
- return this;
- }
-
- /**
- * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
- * necessary.
- *
- * @param stringValue a String whose UTF8 encoded length must be less than 65536.
- * @return this byte vector.
- */
- // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
- public ByteVector putUTF8(final String stringValue) {
- int charLength = stringValue.length();
- if (charLength > 65535) {
- throw new IllegalArgumentException("UTF8 string too large");
- }
- int currentLength = length;
- if (currentLength + 2 + charLength > data.length) {
- enlarge(2 + charLength);
- }
- byte[] currentData = data;
- // Optimistic algorithm: instead of computing the byte length and then serializing the string
- // (which requires two loops), we assume the byte length is equal to char length (which is the
- // most frequent case), and we start serializing the string right away. During the
- // serialization, if we find that this assumption is wrong, we continue with the general method.
- currentData[currentLength++] = (byte) (charLength >>> 8);
- currentData[currentLength++] = (byte) charLength;
- for (int i = 0; i < charLength; ++i) {
- char charValue = stringValue.charAt(i);
- if (charValue >= '\u0001' && charValue <= '\u007F') {
- currentData[currentLength++] = (byte) charValue;
- } else {
- length = currentLength;
- return encodeUtf8(stringValue, i, 65535);
- }
- }
- length = currentLength;
- return this;
- }
-
- /**
- * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
- * necessary. The string length is encoded in two bytes before the encoded characters, if there is
- * space for that (i.e. if this.length - offset - 2 &gt;= 0).
- *
- * @param stringValue the String to encode.
- * @param offset the index of the first character to encode. The previous characters are supposed
- * to have already been encoded, using only one byte per character.
- * @param maxByteLength the maximum byte length of the encoded string, including the already
- * encoded characters.
- * @return this byte vector.
- */
- final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
- int charLength = stringValue.length();
- int byteLength = offset;
- for (int i = offset; i < charLength; ++i) {
- char charValue = stringValue.charAt(i);
- if (charValue >= 0x0001 && charValue <= 0x007F) {
- byteLength++;
- } else if (charValue <= 0x07FF) {
- byteLength += 2;
- } else {
- byteLength += 3;
- }
- }
- if (byteLength > maxByteLength) {
- throw new IllegalArgumentException("UTF8 string too large");
- }
- // Compute where 'byteLength' must be stored in 'data', and store it at this location.
- int byteLengthOffset = length - offset - 2;
- if (byteLengthOffset >= 0) {
- data[byteLengthOffset] = (byte) (byteLength >>> 8);
- data[byteLengthOffset + 1] = (byte) byteLength;
- }
- if (length + byteLength - offset > data.length) {
- enlarge(byteLength - offset);
- }
- int currentLength = length;
- for (int i = offset; i < charLength; ++i) {
- char charValue = stringValue.charAt(i);
- if (charValue >= 0x0001 && charValue <= 0x007F) {
- data[currentLength++] = (byte) charValue;
- } else if (charValue <= 0x07FF) {
- data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
- data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
- } else {
- data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
- data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
- data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
- }
- }
- length = currentLength;
- return this;
- }
-
- /**
- * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
- * necessary.
- *
- * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
- * bytes into this byte vector.
- * @param byteOffset index of the first byte of byteArrayValue that must be copied.
- * @param byteLength number of bytes of byteArrayValue that must be copied.
- * @return this byte vector.
- */
- public ByteVector putByteArray(
- final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
- if (length + byteLength > data.length) {
- enlarge(byteLength);
- }
- if (byteArrayValue != null) {
- System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
- }
- length += byteLength;
- return this;
- }
-
- /**
- * Enlarges this byte vector so that it can receive 'size' more bytes.
- *
- * @param size number of additional bytes that this byte vector should be able to receive.
- */
- private void enlarge(final int size) {
- int doubleCapacity = 2 * data.length;
- int minimalCapacity = length + size;
- byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
- System.arraycopy(data, 0, newData, 0, length);
- data = newData;
- }
-}
diff --git a/src/main/java/org/mvel2/asm/ClassReader.java b/src/main/java/org/mvel2/asm/ClassReader.java
deleted file mode 100644
index e6a4f54..0000000
--- a/src/main/java/org/mvel2/asm/ClassReader.java
+++ /dev/null
@@ -1,3603 +0,0 @@
-// 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 org.mvel2.asm;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * A parser to make a {@link ClassVisitor} visit a ClassFile structure, as defined in the Java
- * Virtual Machine Specification (JVMS). This class parses the ClassFile content and calls the
- * appropriate visit methods of a given {@link ClassVisitor} for each field, method and bytecode
- * instruction encountered.
- *
- * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html">JVMS 4</a>
- * @author Eric Bruneton
- * @author Eugene Kuleshov
- */
-public class ClassReader {
-
- /**
- * A flag to skip the Code attributes. If this flag is set the Code attributes are neither parsed
- * nor visited.
- */
- public static final int SKIP_CODE = 1;
-
- /**
- * A flag to skip the SourceFile, SourceDebugExtension, LocalVariableTable, LocalVariableTypeTable
- * and LineNumberTable attributes. If this flag is set these attributes are neither parsed nor
- * visited (i.e. {@link ClassVisitor#visitSource}, {@link MethodVisitor#visitLocalVariable} and
- * {@link MethodVisitor#visitLineNumber} are not called).
- */
- public static final int SKIP_DEBUG = 2;
-
- /**
- * A flag to skip the StackMap and StackMapTable attributes. If this flag is set these attributes
- * are neither parsed nor visited (i.e. {@link MethodVisitor#visitFrame} is not called). This flag
- * is useful when the {@link ClassWriter#COMPUTE_FRAMES} option is used: it avoids visiting frames
- * that will be ignored and recomputed from scratch.
- */
- public static final int SKIP_FRAMES = 4;
-
- /**
- * A flag to expand the stack map frames. By default stack map frames are visited in their
- * original format (i.e. "expanded" for classes whose version is less than V1_6, and "compressed"
- * for the other classes). If this flag is set, stack map frames are always visited in expanded
- * format (this option adds a decompression/compression step in ClassReader and ClassWriter which
- * degrades performance quite a lot).
- */
- public static final int EXPAND_FRAMES = 8;
-
- /**
- * A flag to expand the ASM specific instructions into an equivalent sequence of standard bytecode
- * instructions. When resolving a forward jump it may happen that the signed 2 bytes offset
- * reserved for it is not sufficient to store the bytecode offset. In this case the jump
- * instruction is replaced with a temporary ASM specific instruction using an unsigned 2 bytes
- * offset (see {@link Label#resolve}). This internal flag is used to re-read classes containing
- * such instructions, in order to replace them with standard instructions. In addition, when this
- * flag is used, goto_w and jsr_w are <i>not</i> converted into goto and jsr, to make sure that
- * infinite loops where a goto_w is replaced with a goto in ClassReader and converted back to a
- * goto_w in ClassWriter cannot occur.
- */
- static final int EXPAND_ASM_INSNS = 256;
-
- /** The size of the temporary byte array used to read class input streams chunk by chunk. */
- private static final int INPUT_STREAM_DATA_CHUNK_SIZE = 4096;
-
- /**
- * A byte array containing the JVMS ClassFile structure to be parsed. <i>The content of this array
- * must not be modified. This field is intended for {@link Attribute} sub classes, and is normally
- * not needed by class visitors.</i>
- *
- * <p>NOTE: the ClassFile structure can start at any offset within this array, i.e. it does not
- * necessarily start at offset 0. Use {@link #getItem} and {@link #header} to get correct
- * ClassFile element offsets within this byte array.
- */
- // DontCheck(MemberName): can't be renamed (for backward binary compatibility).
- public final byte[] b;
-
- /**
- * The offset in bytes, in {@link #b}, of each cp_info entry of the ClassFile's constant_pool
- * array, <i>plus one</i>. In other words, the offset of constant pool entry i is given by
- * cpInfoOffsets[i] - 1, i.e. its cp_info's tag field is given by b[cpInfoOffsets[i] - 1].
- */
- private final int[] cpInfoOffsets;
-
- /**
- * The String objects corresponding to the CONSTANT_Utf8 constant pool items. This cache avoids
- * multiple parsing of a given CONSTANT_Utf8 constant pool item.
- */
- private final String[] constantUtf8Values;
-
- /**
- * The ConstantDynamic objects corresponding to the CONSTANT_Dynamic constant pool items. This
- * cache avoids multiple parsing of a given CONSTANT_Dynamic constant pool item.
- */
- private final ConstantDynamic[] constantDynamicValues;
-
- /**
- * The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
- * BootstrapMethods attribute).
- *
- * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
- * 4.7.23</a>
- */
- private final int[] bootstrapMethodOffsets;
-
- /**
- * A conservative estimate of the maximum length of the strings contained in the constant pool of
- * the class.
- */
- private final int maxStringLength;
-
- /** The offset in bytes, in {@link #b}, of the ClassFile's access_flags field. */
- public final int header;
-
- // -----------------------------------------------------------------------------------------------
- // Constructors
- // -----------------------------------------------------------------------------------------------
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param classFile the JVMS ClassFile structure to be read.
- */
- public ClassReader(final byte[] classFile) {
- this(classFile, 0, classFile.length);
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
- * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
- * @param classFileLength the length in bytes of the ClassFile to be read.
- */
- public ClassReader(
- final byte[] classFileBuffer,
- final int classFileOffset,
- final int classFileLength) { // NOPMD(UnusedFormalParameter) used for backward compatibility.
- this(classFileBuffer, classFileOffset, /* checkClassVersion = */ true);
- }
-
- /**
- * Constructs a new {@link ClassReader} object. <i>This internal constructor must not be exposed
- * as a public API</i>.
- *
- * @param classFileBuffer a byte array containing the JVMS ClassFile structure to be read.
- * @param classFileOffset the offset in byteBuffer of the first byte of the ClassFile to be read.
- * @param checkClassVersion whether to check the class version or not.
- */
- ClassReader(
- final byte[] classFileBuffer, final int classFileOffset, final boolean checkClassVersion) {
- b = classFileBuffer;
- // Check the class' major_version. This field is after the magic and minor_version fields, which
- // use 4 and 2 bytes respectively.
- if (checkClassVersion && readShort(classFileOffset + 6) > Opcodes.V12) {
- throw new IllegalArgumentException(
- "Unsupported class file major version " + readShort(classFileOffset + 6));
- }
- // Create the constant pool arrays. The constant_pool_count field is after the magic,
- // minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
- int constantPoolCount = readUnsignedShort(classFileOffset + 8);
- cpInfoOffsets = new int[constantPoolCount];
- constantUtf8Values = new String[constantPoolCount];
- // Compute the offset of each constant pool entry, as well as a conservative estimate of the
- // maximum length of the constant pool strings. The first constant pool entry is after the
- // magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
- // bytes respectively.
- int currentCpInfoIndex = 1;
- int currentCpInfoOffset = classFileOffset + 10;
- int currentMaxStringLength = 0;
- boolean hasConstantDynamic = false;
- boolean hasConstantInvokeDynamic = false;
- // The offset of the other entries depend on the total size of all the previous entries.
- while (currentCpInfoIndex < constantPoolCount) {
- cpInfoOffsets[currentCpInfoIndex++] = currentCpInfoOffset + 1;
- int cpInfoSize;
- switch (classFileBuffer[currentCpInfoOffset]) {
- case Symbol.CONSTANT_FIELDREF_TAG:
- case Symbol.CONSTANT_METHODREF_TAG:
- case Symbol.CONSTANT_INTERFACE_METHODREF_TAG:
- case Symbol.CONSTANT_INTEGER_TAG:
- case Symbol.CONSTANT_FLOAT_TAG:
- case Symbol.CONSTANT_NAME_AND_TYPE_TAG:
- cpInfoSize = 5;
- break;
- case Symbol.CONSTANT_DYNAMIC_TAG:
- cpInfoSize = 5;
- hasConstantDynamic = true;
- break;
- case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
- cpInfoSize = 5;
- hasConstantInvokeDynamic = true;
- break;
- case Symbol.CONSTANT_LONG_TAG:
- case Symbol.CONSTANT_DOUBLE_TAG:
- cpInfoSize = 9;
- currentCpInfoIndex++;
- break;
- case Symbol.CONSTANT_UTF8_TAG:
- cpInfoSize = 3 + readUnsignedShort(currentCpInfoOffset + 1);
- if (cpInfoSize > currentMaxStringLength) {
- // The size in bytes of this CONSTANT_Utf8 structure provides a conservative estimate
- // of the length in characters of the corresponding string, and is much cheaper to
- // compute than this exact length.
- currentMaxStringLength = cpInfoSize;
- }
- break;
- case Symbol.CONSTANT_METHOD_HANDLE_TAG:
- cpInfoSize = 4;
- break;
- case Symbol.CONSTANT_CLASS_TAG:
- case Symbol.CONSTANT_STRING_TAG:
- case Symbol.CONSTANT_METHOD_TYPE_TAG:
- case Symbol.CONSTANT_PACKAGE_TAG:
- case Symbol.CONSTANT_MODULE_TAG:
- cpInfoSize = 3;
- break;
- default:
- throw new IllegalArgumentException();
- }
- currentCpInfoOffset += cpInfoSize;
- }
- maxStringLength = currentMaxStringLength;
- // The Classfile's access_flags field is just after the last constant pool entry.
- header = currentCpInfoOffset;
-
- // Allocate the cache of ConstantDynamic values, if there is at least one.
- constantDynamicValues = hasConstantDynamic ? new ConstantDynamic[constantPoolCount] : null;
-
- // Read the BootstrapMethods attribute, if any (only get the offset of each method).
- bootstrapMethodOffsets =
- (hasConstantDynamic | hasConstantInvokeDynamic)
- ? readBootstrapMethodsAttribute(currentMaxStringLength)
- : null;
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param inputStream an input stream of the JVMS ClassFile structure to be read. This input
- * stream must contain nothing more than the ClassFile structure itself. It is read from its
- * current position to its end.
- * @throws IOException if a problem occurs during reading.
- */
- public ClassReader(final InputStream inputStream) throws IOException {
- this(readStream(inputStream, false));
- }
-
- /**
- * Constructs a new {@link ClassReader} object.
- *
- * @param className the fully qualified name of the class to be read. The ClassFile structure is
- * retrieved with the current class loader's {@link ClassLoader#getSystemResourceAsStream}.
- * @throws IOException if an exception occurs during reading.
- */
- public ClassReader(final String className) throws IOException {
- this(
- readStream(
- ClassLoader.getSystemResourceAsStream(className.replace('.', '/') + ".class"), true));
- }
-
- /**
- * Reads the given input stream and returns its content as a byte array.
- *
- * @param inputStream an input stream.
- * @param close true to close the input stream after reading.
- * @return the content of the given input stream.
- * @throws IOException if a problem occurs during reading.
- */
- private static byte[] readStream(final InputStream inputStream, final boolean close)
- throws IOException {
- if (inputStream == null) {
- throw new IOException("Class not found");
- }
- try {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
- int bytesRead;
- while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
- outputStream.write(data, 0, bytesRead);
- }
- outputStream.flush();
- return outputStream.toByteArray();
- } finally {
- if (close) {
- inputStream.close();
- }
- }
- }
-
- // -----------------------------------------------------------------------------------------------
- // Accessors
- // -----------------------------------------------------------------------------------------------
-
- /**
- * Returns the class's access flags (see {@link Opcodes}). This value may not reflect Deprecated
- * and Synthetic flags when bytecode is before 1.5 and those flags are represented by attributes.
- *
- * @return the class access flags.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public int getAccess() {
- return readUnsignedShort(header);
- }
-
- /**
- * Returns the internal name of the class (see {@link Type#getInternalName()}).
- *
- * @return the internal class name.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String getClassName() {
- // this_class is just after the access_flags field (using 2 bytes).
- return readClass(header + 2, new char[maxStringLength]);
- }
-
- /**
- * Returns the internal of name of the super class (see {@link Type#getInternalName()}). For
- * interfaces, the super class is {@link Object}.
- *
- * @return the internal name of the super class, or {@literal null} for {@link Object} class.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String getSuperName() {
- // super_class is after the access_flags and this_class fields (2 bytes each).
- return readClass(header + 4, new char[maxStringLength]);
- }
-
- /**
- * Returns the internal names of the implemented interfaces (see {@link Type#getInternalName()}).
- *
- * @return the internal names of the directly implemented interfaces. Inherited implemented
- * interfaces are not returned.
- * @see ClassVisitor#visit(int, int, String, String, String, String[])
- */
- public String[] getInterfaces() {
- // interfaces_count is after the access_flags, this_class and super_class fields (2 bytes each).
- int currentOffset = header + 6;
- int interfacesCount = readUnsignedShort(currentOffset);
- String[] interfaces = new String[interfacesCount];
- if (interfacesCount > 0) {
- char[] charBuffer = new char[maxStringLength];
- for (int i = 0; i < interfacesCount; ++i) {
- currentOffset += 2;
- interfaces[i] = readClass(currentOffset, charBuffer);
- }
- }
- return interfaces;
- }
-
- // -----------------------------------------------------------------------------------------------
- // Public methods
- // -----------------------------------------------------------------------------------------------
-
- /**
- * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
- * {@link ClassReader}.
- *
- * @param classVisitor the visitor that must visit this class.
- * @param parsingOptions the options to use to parse this class. One or more of {@link
- * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
- */
- public void accept(final ClassVisitor classVisitor, final int parsingOptions) {
- accept(classVisitor, new Attribute[0], parsingOptions);
- }
-
- /**
- * Makes the given visitor visit the JVMS ClassFile structure passed to the constructor of this
- * {@link ClassReader}.
- *
- * @param classVisitor the visitor that must visit this class.
- * @param attributePrototypes prototypes of the attributes that must be parsed during the visit of
- * the class. Any attribute whose type is not equal to the type of one the prototypes will not
- * be parsed: its byte array value will be passed unchanged to the ClassWriter. <i>This may
- * corrupt it if this value contains references to the constant pool, or has syntactic or
- * semantic links with a class element that has been transformed by a class adapter between
- * the reader and the writer</i>.
- * @param parsingOptions the options to use to parse this class. One or more of {@link
- * #SKIP_CODE}, {@link #SKIP_DEBUG}, {@link #SKIP_FRAMES} or {@link #EXPAND_FRAMES}.
- */
- public void accept(
- final ClassVisitor classVisitor,
- final Attribute[] attributePrototypes,
- final int parsingOptions) {
- Context context = new Context();
- context.attributePrototypes = attributePrototypes;
- context.parsingOptions = parsingOptions;
- context.charBuffer = new char[maxStringLength];
-
- // Read the access_flags, this_class, super_class, interface_count and interfaces fields.
- char[] charBuffer = context.charBuffer;
- int currentOffset = header;
- int accessFlags = readUnsignedShort(currentOffset);
- String thisClass = readClass(currentOffset + 2, charBuffer);
- String superClass = readClass(currentOffset + 4, charBuffer);
- String[] interfaces = new String[readUnsignedShort(currentOffset + 6)];
- currentOffset += 8;
- for (int i = 0; i < interfaces.length; ++i) {
- interfaces[i] = readClass(currentOffset, charBuffer);
- currentOffset += 2;
- }
-
- // Read the class attributes (the variables are ordered as in Section 4.7 of the JVMS).
- // Attribute offsets exclude the attribute_name_index and attribute_length fields.
- // - The offset of the InnerClasses attribute, or 0.
- int innerClassesOffset = 0;
- // - The offset of the EnclosingMethod attribute, or 0.
- int enclosingMethodOffset = 0;
- // - The string corresponding to the Signature attribute, or null.
- String signature = null;
- // - The string corresponding to the SourceFile attribute, or null.
- String sourceFile = null;
- // - The string corresponding to the SourceDebugExtension attribute, or null.
- String sourceDebugExtension = null;
- // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
- int runtimeVisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
- int runtimeInvisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
- int runtimeVisibleTypeAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
- int runtimeInvisibleTypeAnnotationsOffset = 0;
- // - The offset of the Module attribute, or 0.
- int moduleOffset = 0;
- // - The offset of the ModulePackages attribute, or 0.
- int modulePackagesOffset = 0;
- // - The string corresponding to the ModuleMainClass attribute, or null.
- String moduleMainClass = null;
- // - The string corresponding to the NestHost attribute, or null.
- String nestHostClass = null;
- // - The offset of the NestMembers attribute, or 0.
- int nestMembersOffset = 0;
- // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
- // This list in the <i>reverse order</i> or their order in the ClassFile structure.
- Attribute attributes = null;
-
- int currentAttributeOffset = getFirstAttributeOffset();
- for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
- // Read the attribute_info's attribute_name and attribute_length fields.
- String attributeName = readUTF8(currentAttributeOffset, charBuffer);
- int attributeLength = readInt(currentAttributeOffset + 2);
- currentAttributeOffset += 6;
- // The tests are sorted in decreasing frequency order (based on frequencies observed on
- // typical classes).
- if (Constants.SOURCE_FILE.equals(attributeName)) {
- sourceFile = readUTF8(currentAttributeOffset, charBuffer);
- } else if (Constants.INNER_CLASSES.equals(attributeName)) {
- innerClassesOffset = currentAttributeOffset;
- } else if (Constants.ENCLOSING_METHOD.equals(attributeName)) {
- enclosingMethodOffset = currentAttributeOffset;
- } else if (Constants.NEST_HOST.equals(attributeName)) {
- nestHostClass = readClass(currentAttributeOffset, charBuffer);
- } else if (Constants.NEST_MEMBERS.equals(attributeName)) {
- nestMembersOffset = currentAttributeOffset;
- } else if (Constants.SIGNATURE.equals(attributeName)) {
- signature = readUTF8(currentAttributeOffset, charBuffer);
- } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleAnnotationsOffset = currentAttributeOffset;
- } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleTypeAnnotationsOffset = currentAttributeOffset;
- } else if (Constants.DEPRECATED.equals(attributeName)) {
- accessFlags |= Opcodes.ACC_DEPRECATED;
- } else if (Constants.SYNTHETIC.equals(attributeName)) {
- accessFlags |= Opcodes.ACC_SYNTHETIC;
- } else if (Constants.SOURCE_DEBUG_EXTENSION.equals(attributeName)) {
- sourceDebugExtension =
- readUtf(currentAttributeOffset, attributeLength, new char[attributeLength]);
- } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleAnnotationsOffset = currentAttributeOffset;
- } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleTypeAnnotationsOffset = currentAttributeOffset;
- } else if (Constants.MODULE.equals(attributeName)) {
- moduleOffset = currentAttributeOffset;
- } else if (Constants.MODULE_MAIN_CLASS.equals(attributeName)) {
- moduleMainClass = readClass(currentAttributeOffset, charBuffer);
- } else if (Constants.MODULE_PACKAGES.equals(attributeName)) {
- modulePackagesOffset = currentAttributeOffset;
- } else if (!Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
- // The BootstrapMethods attribute is read in the constructor.
- Attribute attribute =
- readAttribute(
- attributePrototypes,
- attributeName,
- currentAttributeOffset,
- attributeLength,
- charBuffer,
- -1,
- null);
- attribute.nextAttribute = attributes;
- attributes = attribute;
- }
- currentAttributeOffset += attributeLength;
- }
-
- // Visit the class declaration. The minor_version and major_version fields start 6 bytes before
- // the first constant pool entry, which itself starts at cpInfoOffsets[1] - 1 (by definition).
- classVisitor.visit(
- readInt(cpInfoOffsets[1] - 7), accessFlags, thisClass, signature, superClass, interfaces);
-
- // Visit the SourceFile and SourceDebugExtenstion attributes.
- if ((parsingOptions & SKIP_DEBUG) == 0
- && (sourceFile != null || sourceDebugExtension != null)) {
- classVisitor.visitSource(sourceFile, sourceDebugExtension);
- }
-
- // Visit the Module, ModulePackages and ModuleMainClass attributes.
- if (moduleOffset != 0) {
- readModuleAttributes(
- classVisitor, context, moduleOffset, modulePackagesOffset, moduleMainClass);
- }
-
- // Visit the NestHost attribute.
- if (nestHostClass != null) {
- classVisitor.visitNestHost(nestHostClass);
- }
-
- // Visit the EnclosingMethod attribute.
- if (enclosingMethodOffset != 0) {
- String className = readClass(enclosingMethodOffset, charBuffer);
- int methodIndex = readUnsignedShort(enclosingMethodOffset + 2);
- String name = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex], charBuffer);
- String type = methodIndex == 0 ? null : readUTF8(cpInfoOffsets[methodIndex] + 2, charBuffer);
- classVisitor.visitOuterClass(className, name, type);
- }
-
- // Visit the RuntimeVisibleAnnotations attribute.
- if (runtimeVisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleAnnotations attribute.
- if (runtimeInvisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeVisibleTypeAnnotations attribute.
- if (runtimeVisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- classVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleTypeAnnotations attribute.
- if (runtimeInvisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- classVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the non standard attributes.
- while (attributes != null) {
- // Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
- Attribute nextAttribute = attributes.nextAttribute;
- attributes.nextAttribute = null;
- classVisitor.visitAttribute(attributes);
- attributes = nextAttribute;
- }
-
- // Visit the NestedMembers attribute.
- if (nestMembersOffset != 0) {
- int numberOfNestMembers = readUnsignedShort(nestMembersOffset);
- int currentNestMemberOffset = nestMembersOffset + 2;
- while (numberOfNestMembers-- > 0) {
- classVisitor.visitNestMember(readClass(currentNestMemberOffset, charBuffer));
- currentNestMemberOffset += 2;
- }
- }
-
- // Visit the InnerClasses attribute.
- if (innerClassesOffset != 0) {
- int numberOfClasses = readUnsignedShort(innerClassesOffset);
- int currentClassesOffset = innerClassesOffset + 2;
- while (numberOfClasses-- > 0) {
- classVisitor.visitInnerClass(
- readClass(currentClassesOffset, charBuffer),
- readClass(currentClassesOffset + 2, charBuffer),
- readUTF8(currentClassesOffset + 4, charBuffer),
- readUnsignedShort(currentClassesOffset + 6));
- currentClassesOffset += 8;
- }
- }
-
- // Visit the fields and methods.
- int fieldsCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (fieldsCount-- > 0) {
- currentOffset = readField(classVisitor, context, currentOffset);
- }
- int methodsCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (methodsCount-- > 0) {
- currentOffset = readMethod(classVisitor, context, currentOffset);
- }
-
- // Visit the end of the class.
- classVisitor.visitEnd();
- }
-
- // ----------------------------------------------------------------------------------------------
- // Methods to parse modules, fields and methods
- // ----------------------------------------------------------------------------------------------
-
- /**
- * Reads the Module, ModulePackages and ModuleMainClass attributes and visit them.
- *
- * @param classVisitor the current class visitor
- * @param context information about the class being parsed.
- * @param moduleOffset the offset of the Module attribute (excluding the attribute_info's
- * attribute_name_index and attribute_length fields).
- * @param modulePackagesOffset the offset of the ModulePackages attribute (excluding the
- * attribute_info's attribute_name_index and attribute_length fields), or 0.
- * @param moduleMainClass the string corresponding to the ModuleMainClass attribute, or null.
- */
- private void readModuleAttributes(
- final ClassVisitor classVisitor,
- final Context context,
- final int moduleOffset,
- final int modulePackagesOffset,
- final String moduleMainClass) {
- char[] buffer = context.charBuffer;
-
- // Read the module_name_index, module_flags and module_version_index fields and visit them.
- int currentOffset = moduleOffset;
- String moduleName = readModule(currentOffset, buffer);
- int moduleFlags = readUnsignedShort(currentOffset + 2);
- String moduleVersion = readUTF8(currentOffset + 4, buffer);
- currentOffset += 6;
- ModuleVisitor moduleVisitor = classVisitor.visitModule(moduleName, moduleFlags, moduleVersion);
- if (moduleVisitor == null) {
- return;
- }
-
- // Visit the ModuleMainClass attribute.
- if (moduleMainClass != null) {
- moduleVisitor.visitMainClass(moduleMainClass);
- }
-
- // Visit the ModulePackages attribute.
- if (modulePackagesOffset != 0) {
- int packageCount = readUnsignedShort(modulePackagesOffset);
- int currentPackageOffset = modulePackagesOffset + 2;
- while (packageCount-- > 0) {
- moduleVisitor.visitPackage(readPackage(currentPackageOffset, buffer));
- currentPackageOffset += 2;
- }
- }
-
- // Read the 'requires_count' and 'requires' fields.
- int requiresCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (requiresCount-- > 0) {
- // Read the requires_index, requires_flags and requires_version fields and visit them.
- String requires = readModule(currentOffset, buffer);
- int requiresFlags = readUnsignedShort(currentOffset + 2);
- String requiresVersion = readUTF8(currentOffset + 4, buffer);
- currentOffset += 6;
- moduleVisitor.visitRequire(requires, requiresFlags, requiresVersion);
- }
-
- // Read the 'exports_count' and 'exports' fields.
- int exportsCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (exportsCount-- > 0) {
- // Read the exports_index, exports_flags, exports_to_count and exports_to_index fields
- // and visit them.
- String exports = readPackage(currentOffset, buffer);
- int exportsFlags = readUnsignedShort(currentOffset + 2);
- int exportsToCount = readUnsignedShort(currentOffset + 4);
- currentOffset += 6;
- String[] exportsTo = null;
- if (exportsToCount != 0) {
- exportsTo = new String[exportsToCount];
- for (int i = 0; i < exportsToCount; ++i) {
- exportsTo[i] = readModule(currentOffset, buffer);
- currentOffset += 2;
- }
- }
- moduleVisitor.visitExport(exports, exportsFlags, exportsTo);
- }
-
- // Reads the 'opens_count' and 'opens' fields.
- int opensCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (opensCount-- > 0) {
- // Read the opens_index, opens_flags, opens_to_count and opens_to_index fields and visit them.
- String opens = readPackage(currentOffset, buffer);
- int opensFlags = readUnsignedShort(currentOffset + 2);
- int opensToCount = readUnsignedShort(currentOffset + 4);
- currentOffset += 6;
- String[] opensTo = null;
- if (opensToCount != 0) {
- opensTo = new String[opensToCount];
- for (int i = 0; i < opensToCount; ++i) {
- opensTo[i] = readModule(currentOffset, buffer);
- currentOffset += 2;
- }
- }
- moduleVisitor.visitOpen(opens, opensFlags, opensTo);
- }
-
- // Read the 'uses_count' and 'uses' fields.
- int usesCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (usesCount-- > 0) {
- moduleVisitor.visitUse(readClass(currentOffset, buffer));
- currentOffset += 2;
- }
-
- // Read the 'provides_count' and 'provides' fields.
- int providesCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (providesCount-- > 0) {
- // Read the provides_index, provides_with_count and provides_with_index fields and visit them.
- String provides = readClass(currentOffset, buffer);
- int providesWithCount = readUnsignedShort(currentOffset + 2);
- currentOffset += 4;
- String[] providesWith = new String[providesWithCount];
- for (int i = 0; i < providesWithCount; ++i) {
- providesWith[i] = readClass(currentOffset, buffer);
- currentOffset += 2;
- }
- moduleVisitor.visitProvide(provides, providesWith);
- }
-
- // Visit the end of the module attributes.
- moduleVisitor.visitEnd();
- }
-
- /**
- * Reads a JVMS field_info structure and makes the given visitor visit it.
- *
- * @param classVisitor the visitor that must visit the field.
- * @param context information about the class being parsed.
- * @param fieldInfoOffset the start offset of the field_info structure.
- * @return the offset of the first byte following the field_info structure.
- */
- private int readField(
- final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
- char[] charBuffer = context.charBuffer;
-
- // Read the access_flags, name_index and descriptor_index fields.
- int currentOffset = fieldInfoOffset;
- int accessFlags = readUnsignedShort(currentOffset);
- String name = readUTF8(currentOffset + 2, charBuffer);
- String descriptor = readUTF8(currentOffset + 4, charBuffer);
- currentOffset += 6;
-
- // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
- // Attribute offsets exclude the attribute_name_index and attribute_length fields.
- // - The value corresponding to the ConstantValue attribute, or null.
- Object constantValue = null;
- // - The string corresponding to the Signature attribute, or null.
- String signature = null;
- // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
- int runtimeVisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
- int runtimeInvisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
- int runtimeVisibleTypeAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
- int runtimeInvisibleTypeAnnotationsOffset = 0;
- // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
- // This list in the <i>reverse order</i> or their order in the ClassFile structure.
- Attribute attributes = null;
-
- int attributesCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (attributesCount-- > 0) {
- // Read the attribute_info's attribute_name and attribute_length fields.
- String attributeName = readUTF8(currentOffset, charBuffer);
- int attributeLength = readInt(currentOffset + 2);
- currentOffset += 6;
- // The tests are sorted in decreasing frequency order (based on frequencies observed on
- // typical classes).
- if (Constants.CONSTANT_VALUE.equals(attributeName)) {
- int constantvalueIndex = readUnsignedShort(currentOffset);
- constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
- } else if (Constants.SIGNATURE.equals(attributeName)) {
- signature = readUTF8(currentOffset, charBuffer);
- } else if (Constants.DEPRECATED.equals(attributeName)) {
- accessFlags |= Opcodes.ACC_DEPRECATED;
- } else if (Constants.SYNTHETIC.equals(attributeName)) {
- accessFlags |= Opcodes.ACC_SYNTHETIC;
- } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleTypeAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleTypeAnnotationsOffset = currentOffset;
- } else {
- Attribute attribute =
- readAttribute(
- context.attributePrototypes,
- attributeName,
- currentOffset,
- attributeLength,
- charBuffer,
- -1,
- null);
- attribute.nextAttribute = attributes;
- attributes = attribute;
- }
- currentOffset += attributeLength;
- }
-
- // Visit the field declaration.
- FieldVisitor fieldVisitor =
- classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
- if (fieldVisitor == null) {
- return currentOffset;
- }
-
- // Visit the RuntimeVisibleAnnotations attribute.
- if (runtimeVisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleAnnotations attribute.
- if (runtimeInvisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeVisibleTypeAnnotations attribute.
- if (runtimeVisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- fieldVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleTypeAnnotations attribute.
- if (runtimeInvisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- fieldVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the non standard attributes.
- while (attributes != null) {
- // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
- Attribute nextAttribute = attributes.nextAttribute;
- attributes.nextAttribute = null;
- fieldVisitor.visitAttribute(attributes);
- attributes = nextAttribute;
- }
-
- // Visit the end of the field.
- fieldVisitor.visitEnd();
- return currentOffset;
- }
-
- /**
- * Reads a JVMS method_info structure and makes the given visitor visit it.
- *
- * @param classVisitor the visitor that must visit the method.
- * @param context information about the class being parsed.
- * @param methodInfoOffset the start offset of the method_info structure.
- * @return the offset of the first byte following the method_info structure.
- */
- private int readMethod(
- final ClassVisitor classVisitor, final Context context, final int methodInfoOffset) {
- char[] charBuffer = context.charBuffer;
-
- // Read the access_flags, name_index and descriptor_index fields.
- int currentOffset = methodInfoOffset;
- context.currentMethodAccessFlags = readUnsignedShort(currentOffset);
- context.currentMethodName = readUTF8(currentOffset + 2, charBuffer);
- context.currentMethodDescriptor = readUTF8(currentOffset + 4, charBuffer);
- currentOffset += 6;
-
- // Read the method attributes (the variables are ordered as in Section 4.7 of the JVMS).
- // Attribute offsets exclude the attribute_name_index and attribute_length fields.
- // - The offset of the Code attribute, or 0.
- int codeOffset = 0;
- // - The offset of the Exceptions attribute, or 0.
- int exceptionsOffset = 0;
- // - The strings corresponding to the Exceptions attribute, or null.
- String[] exceptions = null;
- // - Whether the method has a Synthetic attribute.
- boolean synthetic = false;
- // - The constant pool index contained in the Signature attribute, or 0.
- int signatureIndex = 0;
- // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
- int runtimeVisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
- int runtimeInvisibleAnnotationsOffset = 0;
- // - The offset of the RuntimeVisibleParameterAnnotations attribute, or 0.
- int runtimeVisibleParameterAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleParameterAnnotations attribute, or 0.
- int runtimeInvisibleParameterAnnotationsOffset = 0;
- // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
- int runtimeVisibleTypeAnnotationsOffset = 0;
- // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
- int runtimeInvisibleTypeAnnotationsOffset = 0;
- // - The offset of the AnnotationDefault attribute, or 0.
- int annotationDefaultOffset = 0;
- // - The offset of the MethodParameters attribute, or 0.
- int methodParametersOffset = 0;
- // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
- // This list in the <i>reverse order</i> or their order in the ClassFile structure.
- Attribute attributes = null;
-
- int attributesCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (attributesCount-- > 0) {
- // Read the attribute_info's attribute_name and attribute_length fields.
- String attributeName = readUTF8(currentOffset, charBuffer);
- int attributeLength = readInt(currentOffset + 2);
- currentOffset += 6;
- // The tests are sorted in decreasing frequency order (based on frequencies observed on
- // typical classes).
- if (Constants.CODE.equals(attributeName)) {
- if ((context.parsingOptions & SKIP_CODE) == 0) {
- codeOffset = currentOffset;
- }
- } else if (Constants.EXCEPTIONS.equals(attributeName)) {
- exceptionsOffset = currentOffset;
- exceptions = new String[readUnsignedShort(exceptionsOffset)];
- int currentExceptionOffset = exceptionsOffset + 2;
- for (int i = 0; i < exceptions.length; ++i) {
- exceptions[i] = readClass(currentExceptionOffset, charBuffer);
- currentExceptionOffset += 2;
- }
- } else if (Constants.SIGNATURE.equals(attributeName)) {
- signatureIndex = readUnsignedShort(currentOffset);
- } else if (Constants.DEPRECATED.equals(attributeName)) {
- context.currentMethodAccessFlags |= Opcodes.ACC_DEPRECATED;
- } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleTypeAnnotationsOffset = currentOffset;
- } else if (Constants.ANNOTATION_DEFAULT.equals(attributeName)) {
- annotationDefaultOffset = currentOffset;
- } else if (Constants.SYNTHETIC.equals(attributeName)) {
- synthetic = true;
- context.currentMethodAccessFlags |= Opcodes.ACC_SYNTHETIC;
- } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleTypeAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
- runtimeVisibleParameterAnnotationsOffset = currentOffset;
- } else if (Constants.RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attributeName)) {
- runtimeInvisibleParameterAnnotationsOffset = currentOffset;
- } else if (Constants.METHOD_PARAMETERS.equals(attributeName)) {
- methodParametersOffset = currentOffset;
- } else {
- Attribute attribute =
- readAttribute(
- context.attributePrototypes,
- attributeName,
- currentOffset,
- attributeLength,
- charBuffer,
- -1,
- null);
- attribute.nextAttribute = attributes;
- attributes = attribute;
- }
- currentOffset += attributeLength;
- }
-
- // Visit the method declaration.
- MethodVisitor methodVisitor =
- classVisitor.visitMethod(
- context.currentMethodAccessFlags,
- context.currentMethodName,
- context.currentMethodDescriptor,
- signatureIndex == 0 ? null : readUtf(signatureIndex, charBuffer),
- exceptions);
- if (methodVisitor == null) {
- return currentOffset;
- }
-
- // If the returned MethodVisitor is in fact a MethodWriter, it means there is no method
- // adapter between the reader and the writer. In this case, it might be possible to copy
- // the method attributes directly into the writer. If so, return early without visiting
- // the content of these attributes.
- if (methodVisitor instanceof MethodWriter) {
- MethodWriter methodWriter = (MethodWriter) methodVisitor;
- if (methodWriter.canCopyMethodAttributes(
- this,
- methodInfoOffset,
- currentOffset - methodInfoOffset,
- synthetic,
- (context.currentMethodAccessFlags & Opcodes.ACC_DEPRECATED) != 0,
- readUnsignedShort(methodInfoOffset + 4),
- signatureIndex,
- exceptionsOffset)) {
- return currentOffset;
- }
- }
-
- // Visit the MethodParameters attribute.
- if (methodParametersOffset != 0) {
- int parametersCount = readByte(methodParametersOffset);
- int currentParameterOffset = methodParametersOffset + 1;
- while (parametersCount-- > 0) {
- // Read the name_index and access_flags fields and visit them.
- methodVisitor.visitParameter(
- readUTF8(currentParameterOffset, charBuffer),
- readUnsignedShort(currentParameterOffset + 2));
- currentParameterOffset += 4;
- }
- }
-
- // Visit the AnnotationDefault attribute.
- if (annotationDefaultOffset != 0) {
- AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
- readElementValue(annotationVisitor, annotationDefaultOffset, null, charBuffer);
- if (annotationVisitor != null) {
- annotationVisitor.visitEnd();
- }
- }
-
- // Visit the RuntimeVisibleAnnotations attribute.
- if (runtimeVisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleAnnotations attribute.
- if (runtimeInvisibleAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeVisibleTypeAnnotations attribute.
- if (runtimeVisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- methodVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ true),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeInvisibleTypeAnnotations attribute.
- if (runtimeInvisibleTypeAnnotationsOffset != 0) {
- int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
- int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
- while (numAnnotations-- > 0) {
- // Parse the target_type, target_info and target_path fields.
- currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
- // Parse the type_index field.
- String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
- currentAnnotationOffset += 2;
- // Parse num_element_value_pairs and element_value_pairs and visit these values.
- currentAnnotationOffset =
- readElementValues(
- methodVisitor.visitTypeAnnotation(
- context.currentTypeAnnotationTarget,
- context.currentTypeAnnotationTargetPath,
- annotationDescriptor,
- /* visible = */ false),
- currentAnnotationOffset,
- /* named = */ true,
- charBuffer);
- }
- }
-
- // Visit the RuntimeVisibleParameterAnnotations attribute.
- if (runtimeVisibleParameterAnnotationsOffset != 0) {
- readParameterAnnotations(
- methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
- }
-
- // Visit the RuntimeInvisibleParameterAnnotations attribute.
- if (runtimeInvisibleParameterAnnotationsOffset != 0) {
- readParameterAnnotations(
- methodVisitor,
- context,
- runtimeInvisibleParameterAnnotationsOffset,
- /* visible = */ false);
- }
-
- // Visit the non standard attributes.
- while (attributes != null) {
- // Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
- Attribute nextAttribute = attributes.nextAttribute;
- attributes.nextAttribute = null;
- methodVisitor.visitAttribute(attributes);
- attributes = nextAttribute;
- }
-
- // Visit the Code attribute.
- if (codeOffset != 0) {
- methodVisitor.visitCode();
- readCode(methodVisitor, context, codeOffset);
- }
-
- // Visit the end of the method.
- methodVisitor.visitEnd();
- return currentOffset;
- }
-
- // ----------------------------------------------------------------------------------------------
- // Methods to parse a Code attribute
- // ----------------------------------------------------------------------------------------------
-
- /**
- * Reads a JVMS 'Code' attribute and makes the given visitor visit it.
- *
- * @param methodVisitor the visitor that must visit the Code attribute.
- * @param context information about the class being parsed.
- * @param codeOffset the start offset in {@link #b} of the Code attribute, excluding its
- * attribute_name_index and attribute_length fields.
- */
- private void readCode(
- final MethodVisitor methodVisitor, final Context context, final int codeOffset) {
- int currentOffset = codeOffset;
-
- // Read the max_stack, max_locals and code_length fields.
- final byte[] classFileBuffer = b;
- final char[] charBuffer = context.charBuffer;
- final int maxStack = readUnsignedShort(currentOffset);
- final int maxLocals = readUnsignedShort(currentOffset + 2);
- final int codeLength = readInt(currentOffset + 4);
- currentOffset += 8;
-
- // Read the bytecode 'code' array to create a label for each referenced instruction.
- final int bytecodeStartOffset = currentOffset;
- final int bytecodeEndOffset = currentOffset + codeLength;
- final Label[] labels = context.currentMethodLabels = new Label[codeLength + 1];
- while (currentOffset < bytecodeEndOffset) {
- final int bytecodeOffset = currentOffset - bytecodeStartOffset;
- final int opcode = classFileBuffer[currentOffset] & 0xFF;
- switch (opcode) {
- case Constants.NOP:
- case Constants.ACONST_NULL:
- case Constants.ICONST_M1:
- case Constants.ICONST_0:
- case Constants.ICONST_1:
- case Constants.ICONST_2:
- case Constants.ICONST_3:
- case Constants.ICONST_4:
- case Constants.ICONST_5:
- case Constants.LCONST_0:
- case Constants.LCONST_1:
- case Constants.FCONST_0:
- case Constants.FCONST_1:
- case Constants.FCONST_2:
- case Constants.DCONST_0:
- case Constants.DCONST_1:
- case Constants.IALOAD:
- case Constants.LALOAD:
- case Constants.FALOAD:
- case Constants.DALOAD:
- case Constants.AALOAD:
- case Constants.BALOAD:
- case Constants.CALOAD:
- case Constants.SALOAD:
- case Constants.IASTORE:
- case Constants.LASTORE:
- case Constants.FASTORE:
- case Constants.DASTORE:
- case Constants.AASTORE:
- case Constants.BASTORE:
- case Constants.CASTORE:
- case Constants.SASTORE:
- case Constants.POP:
- case Constants.POP2:
- case Constants.DUP:
- case Constants.DUP_X1:
- case Constants.DUP_X2:
- case Constants.DUP2:
- case Constants.DUP2_X1:
- case Constants.DUP2_X2:
- case Constants.SWAP:
- case Constants.IADD:
- case Constants.LADD:
- case Constants.FADD:
- case Constants.DADD:
- case Constants.ISUB:
- case Constants.LSUB:
- case Constants.FSUB:
- case Constants.DSUB:
- case Constants.IMUL:
- case Constants.LMUL:
- case Constants.FMUL:
- case Constants.DMUL:
- case Constants.IDIV:
- case Constants.LDIV:
- case Constants.FDIV:
- case Constants.DDIV:
- case Constants.IREM:
- case Constants.LREM:
- case Constants.FREM:
- case Constants.DREM:
- case Constants.INEG:
- case Constants.LNEG:
- case Constants.FNEG:
- case Constants.DNEG:
- case Constants.ISHL:
- case Constants.LSHL:
- case Constants.ISHR:
- case Constants.LSHR:
- case Constants.IUSHR:
- case Constants.LUSHR:
- case Constants.IAND:
- case Constants.LAND:
- case Constants.IOR:
- case Constants.LOR:
- case Constants.IXOR:
- case Constants.LXOR:
- case Constants.I2L:
- case Constants.I2F:
- case Constants.I2D:
- case Constants.L2I:
- case Constants.L2F:
- case Constants.L2D:
- case Constants.F2I:
- case Constants.F2L:
- case Constants.F2D:
- case Constants.D2I:
- case Constants.D2L:
- case Constants.D2F:
- case Constants.I2B:
- case Constants.I2C:
- case Constants.I2S:
- case Constants.LCMP:
- case Constants.FCMPL:
- case Constants.FCMPG:
- case Constants.DCMPL:
- case Constants.DCMPG:
- case Constants.IRETURN:
- case Constants.LRETURN:
- case Constants.FRETURN:
- case Constants.DRETURN:
- case Constants.ARETURN:
- case Constants.RETURN:
- case Constants.ARRAYLENGTH:
- case Constants.ATHROW:
- case Constants.MONITORENTER:
- case Constants.MONITOREXIT:
- case Constants.ILOAD_0:
- case Constants.ILOAD_1:
- case Constants.ILOAD_2:
- case Constants.ILOAD_3:
- case Constants.LLOAD_0:
- case Constants.LLOAD_1:
- case Constants.LLOAD_2:
- case Constants.LLOAD_3:
- case Constants.FLOAD_0:
- case Constants.FLOAD_1:
- case Constants.FLOAD_2:
- case Constants.FLOAD_3:
- case Constants.DLOAD_0:
- case Constants.DLOAD_1:
- case Constants.DLOAD_2:
- case Constants.DLOAD_3:
- case Constants.ALOAD_0:
- case Constants.ALOAD_1:
- case Constants.ALOAD_2:
- case Constants.ALOAD_3:
- case Constants.ISTORE_0:
- case Constants.ISTORE_1:
- case Constants.ISTORE_2:
- case Constants.ISTORE_3:
- case Constants.LSTORE_0:
- case Constants.LSTORE_1:
- case Constants.LSTORE_2:
- case Constants.LSTORE_3:
- case Constants.FSTORE_0:
- case Constants.FSTORE_1:
- case Constants.FSTORE_2:
- case Constants.FSTORE_3:
- case Constants.DSTORE_0:
- case Constants.DSTORE_1:
- case Constants.DSTORE_2:
- case Constants.DSTORE_3:
- case Constants.ASTORE_0:
- case Constants.ASTORE_1:
- case Constants.ASTORE_2:
- case Constants.ASTORE_3:
- currentOffset += 1;
- break;
- case Constants.IFEQ:
- case Constants.IFNE:
- case Constants.IFLT:
- case Constants.IFGE:
- case Constants.IFGT:
- case Constants.IFLE:
- case Constants.IF_ICMPEQ:
- case Constants.IF_ICMPNE:
- case Constants.IF_ICMPLT:
- case Constants.IF_ICMPGE:
- case Constants.IF_ICMPGT:
- case Constants.IF_ICMPLE:
- case Constants.IF_ACMPEQ:
- case Constants.IF_ACMPNE:
- case Constants.GOTO:
- case Constants.JSR:
- case Constants.IFNULL:
- case Constants.IFNONNULL:
- createLabel(bytecodeOffset + readShort(currentOffset + 1), labels);
- currentOffset += 3;
- break;
- case Constants.ASM_IFEQ:
- case Constants.ASM_IFNE:
- case Constants.ASM_IFLT:
- case Constants.ASM_IFGE:
- case Constants.ASM_IFGT:
- case Constants.ASM_IFLE:
- case Constants.ASM_IF_ICMPEQ:
- case Constants.ASM_IF_ICMPNE:
- case Constants.ASM_IF_ICMPLT:
- case Constants.ASM_IF_ICMPGE:
- case Constants.ASM_IF_ICMPGT:
- case Constants.ASM_IF_ICMPLE:
- case Constants.ASM_IF_ACMPEQ:
- case Constants.ASM_IF_ACMPNE:
- case Constants.ASM_GOTO:
- case Constants.ASM_JSR:
- case Constants.ASM_IFNULL:
- case Constants.ASM_IFNONNULL:
- createLabel(bytecodeOffset + readUnsignedShort(currentOffset + 1), labels);
- currentOffset += 3;
- break;
- case Constants.GOTO_W:
- case Constants.JSR_W:
- case Constants.ASM_GOTO_W:
- createLabel(bytecodeOffset + readInt(currentOffset + 1), labels);
- currentOffset += 5;
- break;
- case Constants.WIDE:
- switch (classFileBuffer[currentOffset + 1] & 0xFF) {
- case Constants.ILOAD:
- case Constants.FLOAD:
- case Constants.ALOAD:
- case Constants.LLOAD:
- case Constants.DLOAD:
- case Constants.ISTORE:
- case Constants.FSTORE:
- case Constants.ASTORE:
- case Constants.LSTORE:
- case Constants.DSTORE:
- case Constants.RET:
- currentOffset += 4;
- break;
- case Constants.IINC:
- currentOffset += 6;
- break;
- default:
- throw new IllegalArgumentException();
- }
- break;
- case Constants.TABLESWITCH:
- // Skip 0 to 3 padding bytes.
- currentOffset += 4 - (bytecodeOffset & 3);
- // Read the default label and the number of table entries.
- createLabel(bytecodeOffset + readInt(currentOffset), labels);
- int numTableEntries = readInt(currentOffset + 8) - readInt(currentOffset + 4) + 1;
- currentOffset += 12;
- // Read the table labels.
- while (numTableEntries-- > 0) {
- createLabel(bytecodeOffset + readInt(currentOffset), labels);
- currentOffset += 4;
- }
- break;
- case Constants.LOOKUPSWITCH:
- // Skip 0 to 3 padding bytes.
- currentOffset += 4 - (bytecodeOffset & 3);
- // Read the default label and the number of switch cases.
- createLabel(bytecodeOffset + readInt(currentOffset), labels);
- int numSwitchCases = readInt(currentOffset + 4);
- currentOffset += 8;
- // Read the switch labels.
- while (numSwitchCases-- > 0) {
- createLabel(bytecodeOffset + readInt(currentOffset + 4), labels);
- currentOffset += 8;
- }
- break;
- case Constants.ILOAD:
- case Constants.LLOAD:
- case Constants.FLOAD:
- case Constants.DLOAD:
- case Constants.ALOAD:
- case Constants.ISTORE:
- case Constants.LSTORE:
- case Constants.FSTORE:
- case Constants.DSTORE:
- case Constants.ASTORE:
- case Constants.RET:
- case Constants.BIPUSH:
- case Constants.NEWARRAY:
- case Constants.LDC:
- currentOffset += 2;
- break;
- case Constants.SIPUSH:
- case Constants.LDC_W:
- case Constants.LDC2_W:
- case Constants.GETSTATIC:
- case Constants.PUTSTATIC:
- case Constants.GETFIELD:
- case Constants.PUTFIELD:
- case Constants.INVOKEVIRTUAL:
- case Constants.INVOKESPECIAL:
- case Constants.INVOKESTATIC:
- case Constants.NEW:
- case Constants.ANEWARRAY:
- case Constants.CHECKCAST:
- case Constants.INSTANCEOF:
- case Constants.IINC:
- currentOffset += 3;
- break;
- case Constants.INVOKEINTERFACE:
- case Constants.INVOKEDYNAMIC:
- currentOffset += 5;
- break;
- case Constants.MULTIANEWARRAY:
- currentOffset += 4;
- break;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- // Read the 'exception_table_length' and 'exception_table' field to create a label for each
- // referenced instruction, and to make methodVisitor visit the corresponding try catch blocks.
- int exceptionTableLength = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (exceptionTableLength-- > 0) {
- Label start = createLabel(readUnsignedShort(currentOffset), labels);
- Label end = createLabel(readUnsignedShort(currentOffset + 2), labels);
- Label handler = createLabel(readUnsignedShort(currentOffset + 4), labels);
- String catchType = readUTF8(cpInfoOffsets[readUnsignedShort(currentOffset + 6)], charBuffer);
- currentOffset += 8;
- methodVisitor.visitTryCatchBlock(start, end, handler, catchType);
- }
-
- // Read the Code attributes to create a label for each referenced instruction (the variables
- // are ordered as in Section 4.7 of the JVMS). Attribute offsets exclude the
- // attribute_name_index and attribute_length fields.
- // - The offset of the current 'stack_map_frame' in the StackMap[Table] attribute, or 0.
- // Initially, this is the offset of the first 'stack_map_frame' entry. Then this offset is
- // updated after each stack_map_frame is read.
- int stackMapFrameOffset = 0;
- // - The end offset of the StackMap[Table] attribute, or 0.
- int stackMapTableEndOffset = 0;
- // - Whether the stack map frames are compressed (i.e. in a StackMapTable) or not.
- boolean compressedFrames = true;
- // - The offset of the LocalVariableTable attribute, or 0.
- int localVariableTableOffset = 0;
- // - The offset of the LocalVariableTypeTable attribute, or 0.
- int localVariableTypeTableOffset = 0;
- // - The offset of each 'type_annotation' entry in the RuntimeVisibleTypeAnnotations
- // attribute, or null.
- int[] visibleTypeAnnotationOffsets = null;
- // - The offset of each 'type_annotation' entry in the RuntimeInvisibleTypeAnnotations
- // attribute, or null.
- int[] invisibleTypeAnnotationOffsets = null;
- // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
- // This list in the <i>reverse order</i> or their order in the ClassFile structure.
- Attribute attributes = null;
-
- int attributesCount = readUnsignedShort(currentOffset);
- currentOffset += 2;
- while (attributesCount-- > 0) {
- // Read the attribute_info's attribute_name and attribute_length fields.
- String attributeName = readUTF8(currentOffset, charBuffer);
- int attributeLength = readInt(currentOffset + 2);
- currentOffset += 6;
- if (Constants.LOCAL_VARIABLE_TABLE.equals(attributeName)) {
- if ((context.parsingOptions & SKIP_DEBUG) == 0) {
- localVariableTableOffset = currentOffset;
- // Parse the attribute to find the corresponding (debug only) labels.
- int currentLocalVariableTableOffset = currentOffset;
- int localVariableTableLength = readUnsignedShort(currentLocalVariableTableOffset);
- currentLocalVariableTableOffset += 2;
- while (localVariableTableLength-- > 0) {
- int startPc = readUnsignedShort(currentLocalVariableTableOffset);
- createDebugLabel(startPc, labels);
- int length = readUnsignedShort(currentLocalVariableTableOffset + 2);
- createDebugLabel(startPc + length, labels);
- // Skip the name_index, descriptor_index and index fields (2 bytes each).
- currentLocalVariableTableOffset += 10;
- }
- }
- } else if (Constants.LOCAL_VARIABLE_TYPE_TABLE.equals(attributeName)) {
- localVariableTypeTableOffset = currentOffset;
- // Here we do not extract the labels corresponding to the attribute content. We assume they
- // are the same or a subset of those of the LocalVariableTable attribute.
- } else if (Constants.LINE_NUMBER_TABLE.equals(attributeName)) {
- if ((context.parsingOptions & SKIP_DEBUG) == 0) {
- // Parse the attribute to find the corresponding (debug only) labels.
- int currentLineNumberTableOffset = currentOffset;
- int lineNumberTableLength = readUnsignedShort(currentLineNumberTableOffset);
- currentLineNumberTableOffset += 2;
- while (lineNumberTableLength-- > 0) {
- int startPc = readUnsignedShort(currentLineNumberTableOffset);
- int lineNumber = readUnsignedShort(currentLineNumberTableOffset + 2);
- currentLineNumberTableOffset += 4;
- createDebugLabel(startPc, labels);
- labels[startPc].addLineNumber(lineNumber);
- }
- }
- } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- visibleTypeAnnotationOffsets =
- readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ true);
- // Here we do not extract the labels corresponding to the attribute content. This would
- // require a full parsing of the attribute, which would need to be repeated when parsing
- // the bytecode instructions (see below). Instead, the content of the attribute is read one
- // type annotation at a time (i.e. after a type annotation has been visited, the next type
- // annotation is read), and the labels it contains are also extracted one annotation at a
- // time. This assumes that type annotations are ordered by increasing bytecode offset.
- } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
- invisibleTypeAnnotationOffsets =
- readTypeAnnotations(methodVisitor, context, currentOffset, /* visible = */ false);
- // Same comment as above for the RuntimeVisibleTypeAnnotations attribute.
- } else if (Constants.STACK_MAP_TABLE.equals(attributeName)) {
- if ((context.parsingOptions & SKIP_FRAMES) == 0) {
- stackMapFrameOffset = currentOffset + 2;
- stackMapTableEndOffset = currentOffset + attributeLength;
- }
- // Here we do not extract the labels corresponding to the attribute content. This would
- // require a full parsing of the attribute, which would need to be repeated when parsing
- // the bytecode instructions (see below). Instead, the content of the attribute is read one
- // frame at a time (i.e. after a frame has been visited, the next frame is read), and the
- // labels it contains are also extracted one frame at a time. Thanks to the ordering of
- // frames, having only a "one frame lookahead" is not a problem, i.e. it is not possible to
- // see an offset smaller than the offset of the current instruction and for which no Label
- // exist. Except for UNINITIALIZED type offsets. We solve this by parsing the stack map
- // table without a full decoding (see below).
- } else if ("StackMap".equals(attributeName)) {
- if ((context.parsingOptions & SKIP_FRAMES) == 0) {
- stackMapFrameOffset = currentOffset + 2;
- stackMapTableEndOffset = currentOffset + attributeLength;
- compressedFrames = false;
- }
- // IMPORTANT! Here we assume that the frames are ordered, as in the StackMapTable attribute,
- // although this is not guaranteed by the attribute format. This allows an incremental
- // extraction of the labels corresponding to this attribute (see the comment above for the
- // StackMapTable attribute).
- } else {
- Attribute attribute =
- readAttribute(
- context.attributePrototypes,
- attributeName,
- currentOffset,
- attributeLength,
- charBuffer,
- codeOffset,
- labels);
- attribute.nextAttribute = attributes;
- attributes = attribute;
- }
- currentOffset += attributeLength;
- }
-
- // Initialize the context fields related to stack map frames, and generate the first
- // (implicit) stack map frame, if needed.
- final boolean expandFrames = (context.parsingOptions & EXPAND_FRAMES) != 0;
- if (stackMapFrameOffset != 0) {
- // The bytecode offset of the first explicit frame is not offset_delta + 1 but only
- // offset_delta. Setting the implicit frame offset to -1 allows us to use of the
- // "offset_delta + 1" rule in all cases.
- context.currentFrameOffset = -1;
- context.currentFrameType = 0;
- context.currentFrameLocalCount = 0;
- context.currentFrameLocalCountDelta = 0;
- context.currentFrameLocalTypes = new Object[maxLocals];
- context.currentFrameStackCount = 0;
- context.currentFrameStackTypes = new Object[maxStack];
- if (expandFrames) {
- computeImplicitFrame(context);
- }
- // Find the labels for UNINITIALIZED frame types. Instead of decoding each element of the
- // stack map table, we look for 3 consecutive bytes that "look like" an UNINITIALIZED type
- // (tag ITEM_Uninitialized, offset within bytecode bounds, NEW instruction at this offset).
- // We may find false positives (i.e. not real UNINITIALIZED types), but this should be rare,
- // and the only consequence will be the creation of an unneeded label. This is better than
- // creating a label for each NEW instruction, and faster than fully decoding the whole stack
- // map table.
- for (int offset = stackMapFrameOffset; offset < stackMapTableEndOffset - 2; ++offset) {
- if (classFileBuffer[offset] == Frame.ITEM_UNINITIALIZED) {
- int potentialBytecodeOffset = readUnsignedShort(offset + 1);
- if (potentialBytecodeOffset >= 0
- && potentialBytecodeOffset < codeLength
- && (classFileBuffer[bytecodeStartOffset + potentialBytecodeOffset] & 0xFF)
- == Opcodes.NEW) {
- createLabel(potentialBytecodeOffset, labels);
- }
- }
- }
- }
- if (expandFrames && (context.parsingOptions & EXPAND_ASM_INSNS) != 0) {
- // Expanding the ASM specific instructions can introduce F_INSERT frames, even if the method
- // does not currently have any frame. These inserted frames must be computed by simulating the
- // effect of the bytecode instructions, one by one, starting from the implicit first frame.
- // For this, MethodWriter needs to know maxLocals before the first instruction is visited. To
- // ensure this, we visit the implicit first frame here (passing only maxLocals - the rest is
- // computed in MethodWriter).
- methodVisitor.visitFrame(Opcodes.F_NEW, maxLocals, null, 0, null);
- }
-
- // Visit the bytecode instructions. First, introduce state variables for the incremental parsing
- // of the type annotations.
-
- // Index of the next runtime visible type annotation to read (in the
- // visibleTypeAnnotationOffsets array).
- int currentVisibleTypeAnnotationIndex = 0;
- // The bytecode offset of the next runtime visible type annotation to read, or -1.
- int currentVisibleTypeAnnotationBytecodeOffset =
- getTypeAnnotationBytecodeOffset(visibleTypeAnnotationOffsets, 0);
- // Index of the next runtime invisible type annotation to read (in the
- // invisibleTypeAnnotationOffsets array).
- int currentInvisibleTypeAnnotationIndex = 0;
- // The bytecode offset of the next runtime invisible type annotation to read, or -1.
- int currentInvisibleTypeAnnotationBytecodeOffset =
- getTypeAnnotationBytecodeOffset(invisibleTypeAnnotationOffsets, 0);
-
- // Whether a F_INSERT stack map frame must be inserted before the current instruction.
- boolean insertFrame = false;
-
- // The delta to subtract from a goto_w or jsr_w opcode to get the corresponding goto or jsr
- // opcode, or 0 if goto_w and jsr_w must be left unchanged (i.e. when expanding ASM specific
- // instructions).
- final int wideJumpOpcodeDelta =
- (context.parsingOptions & EXPAND_ASM_INSNS) == 0 ? Constants.WIDE_JUMP_OPCODE_DELTA : 0;
-
- currentOffset = bytecodeStartOffset;
- while (currentOffset < bytecodeEndOffset) {
- final int currentBytecodeOffset = currentOffset - bytecodeStartOffset;
-
- // Visit the label and the line number(s) for this bytecode offset, if any.
- Label currentLabel = labels[currentBytecodeOffset];
- if (currentLabel != null) {
- currentLabel.accept(methodVisitor, (context.parsingOptions & SKIP_DEBUG) == 0);
- }
-
- // Visit the stack map frame for this bytecode offset, if any.
- while (stackMapFrameOffset != 0
- && (context.currentFrameOffset == currentBytecodeOffset
- || context.currentFrameOffset == -1)) {
- // If there is a stack map frame for this offset, make methodVisitor visit it, and read the
- // next stack map frame if there is one.
- if (context.currentFrameOffset != -1) {
- if (!compressedFrames || expandFrames) {
- methodVisitor.visitFrame(
- Opcodes.F_NEW,
- context.currentFrameLocalCount,
- context.currentFrameLocalTypes,
- context.currentFrameStackCount,
- context.currentFrameStackTypes);
- } else {
- methodVisitor.visitFrame(
- context.currentFrameType,
- context.currentFrameLocalCountDelta,
- context.currentFrameLocalTypes,
- context.currentFrameStackCount,
- context.currentFrameStackTypes);
- }
- // Since there is already a stack map frame for this bytecode offset, there is no need to
- // insert a new one.
- insertFrame = false;
- }
- if (stackMapFrameOffset < stackMapTableEndOffset) {
- stackMapFrameOffset =
- readStackMapFrame(stackMapFrameOffset, compressedFrames, expandFrames, context);
- } else {
- stackMapFrameOffset = 0;
- }
- }
-
- // Insert a stack map frame for this bytecode offset, if requested by setting insertFrame to
- // true during the previous iteration. The actual frame content is computed in MethodWriter.
- if (insertFrame) {
- if ((context.parsingOptions & EXPAND_FRAMES) != 0) {
- methodVisitor.visitFrame(Constants.F_INSERT, 0, null, 0, null);
- }
- insertFrame = false;
- }
-
- // Visit the instruction at this bytecode offset.
- int opcode = classFileBuffer[currentOffset] & 0xFF;
- switch (opcode) {
- case Constants.NOP:
- case Constants.ACONST_NULL:
- case Constants.ICONST_M1:
- case Constants.ICONST_0:
- case Constants.ICONST_1:
- case Constants.ICONST_2:
- case Constants.ICONST_3:
- case Constants.ICONST_4:
- case Constants.ICONST_5:
- case Constants.LCONST_0:
- case Constants.LCONST_1:
- case Constants.FCONST_0:
- case Constants.FCONST_1:
- case Constants.FCONST_2:
- case Constants.DCONST_0:
- case Constants.DCONST_1:
- case Constants.IALOAD:
- case Constants.LALOAD:
- case Constants.FALOAD:
- case Constants.DALOAD:
- case Constants.AALOAD:
- case Constants.BALOAD:
- case Constants.CALOAD:
- case Constants.SALOAD:
- case Constants.IASTORE:
- case Constants.LASTORE:
- case Constants.FASTORE:
- case Constants.DASTORE:
- case Constants.AASTORE:
- case Constants.BASTORE:
- case Constants.CASTORE:
- case Constants.SASTORE:
- case Constants.POP:
- case Constants.POP2:
- case Constants.DUP:
- case Constants.DUP_X1:
- case Constants.DUP_X2:
- case Constants.DUP2:
- case Constants.DUP2_X1:
- case Constants.DUP2_X2:
- case Constants.SWAP:
- case Constants.IADD:
- case Constants.LADD:
- case Constants.FADD:
- case Constants.DADD:
- case Constants.ISUB:
- case Constants.LSUB:
- case Constants.FSUB:
- case Constants.DSUB:
- case Constants.IMUL:
- case Constants.LMUL:
- case Constants.FMUL:
- case Constants.DMUL:
- case Constants.IDIV:
- case Constants.LDIV:
- case Constants.FDIV:
- case Constants.DDIV:
- case Constants.IREM:
- case Constants.LREM:
- case Constants.FREM:
- case Constants.DREM:
- case Constants.INEG:
- case Constants.LNEG:
- case Constants.FNEG:
- case Constants.DNEG:
- case Constants.ISHL:
- case Constants.LSHL:
- case Constants.ISHR: