8241627: Updating ASM to 8.0.1 for JDK 15

Co-authored-by: Igor Ignatyev <igor.ignatyev@oracle.com>
Reviewed-by: psandoz, chegar
This commit is contained in:
Vicente Romero 2020-04-21 21:25:26 -04:00
parent c7ae195a03
commit 78a0baa57c
89 changed files with 4070 additions and 1984 deletions
src/java.base/share
classes/jdk/internal/org/objectweb/asm
AnnotationVisitor.javaAnnotationWriter.javaAttribute.javaClassReader.javaClassVisitor.javaClassWriter.javaConstants.javaFieldVisitor.javaFieldWriter.javaFrame.javaLabel.javaMethodVisitor.javaMethodWriter.javaModuleVisitor.javaModuleWriter.javaOpcodes.javaRecordComponentVisitor.javaRecordComponentWriter.javaSymbolTable.javaType.javaTypePath.java
commons
signature
tree
util
version.txt
legal
test/jdk/java/io/Serializable/records

@ -74,7 +74,10 @@ public abstract class AnnotationVisitor {
*/
protected final int api;
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
/**
* The annotation visitor to which this visitor must delegate method calls. May be {@literal
* null}.
*/
protected AnnotationVisitor av;
/**
@ -93,11 +96,20 @@ public abstract class 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.
* calls. May be {@literal null}.
*/
@SuppressWarnings("deprecation")
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.av = annotationVisitor;

@ -122,7 +122,7 @@ final class AnnotationWriter extends AnnotationVisitor {
private AnnotationWriter nextAnnotation;
// -----------------------------------------------------------------------------------------------
// Constructors
// Constructors and factories
// -----------------------------------------------------------------------------------------------
/**
@ -135,15 +135,15 @@ final class AnnotationWriter extends AnnotationVisitor {
* 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).
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
* {@literal null} in other cases (e.g. nested or array annotations).
*/
AnnotationWriter(
final SymbolTable symbolTable,
final boolean useNamedValues,
final ByteVector annotation,
final AnnotationWriter previousAnnotation) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.useNamedValues = useNamedValues;
this.annotation = annotation;
@ -156,21 +156,61 @@ final class AnnotationWriter extends AnnotationVisitor {
}
/**
* Constructs a new {@link AnnotationWriter} using named values.
* Creates 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 descriptor the class descriptor of the annotation class.
* @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
* other cases (e.g. nested or array annotations).
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
* {@literal null} in other cases (e.g. nested or array annotations).
* @return a new {@link AnnotationWriter} for the given annotation descriptor.
*/
AnnotationWriter(
static AnnotationWriter create(
final SymbolTable symbolTable,
final ByteVector annotation,
final String descriptor,
final AnnotationWriter previousAnnotation) {
this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
// Create a ByteVector to hold an 'annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
ByteVector annotation = new ByteVector();
// Write type_index and reserve space for num_element_value_pairs.
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
return new AnnotationWriter(
symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
}
/**
* Creates a new {@link AnnotationWriter} using named values.
*
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
* @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
* {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
* @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
* {@literal null} in other cases (e.g. nested or array annotations).
* @return a new {@link AnnotationWriter} for the given type annotation reference and descriptor.
*/
static AnnotationWriter create(
final SymbolTable symbolTable,
final int typeRef,
final TypePath typePath,
final String descriptor,
final AnnotationWriter previousAnnotation) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget(typeRef, typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
return new AnnotationWriter(
symbolTable, /* useNamedValues = */ true, typeAnnotation, previousAnnotation);
}
// -----------------------------------------------------------------------------------------------
@ -275,7 +315,7 @@ final class AnnotationWriter extends AnnotationVisitor {
}
// 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);
return new AnnotationWriter(symbolTable, /* useNamedValues = */ true, annotation, null);
}
@Override
@ -315,7 +355,7 @@ final class AnnotationWriter extends AnnotationVisitor {
* 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.
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or {@literal null}.
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
* annotation and all its predecessors. This includes the size of the attribute_name_index and
* attribute_length fields.
@ -334,6 +374,56 @@ final class AnnotationWriter extends AnnotationVisitor {
return attributeSize;
}
/**
* Returns the size of the Runtime[In]Visible[Type]Annotations attributes containing the given
* annotations and all their <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the
* attribute names to the constant pool of the class (if not null).
*
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be
* {@literal null}.
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field,
* method or class. The previous ones can be accessed with the {@link #previousAnnotation}
* field. May be {@literal null}.
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a
* field, method or class. The previous ones can be accessed with the {@link
* #previousAnnotation} field. May be {@literal null}.
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a
* field, method or class field. The previous ones can be accessed with the {@link
* #previousAnnotation} field. May be {@literal null}.
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing the
* given annotations and all their predecessors. This includes the size of the
* attribute_name_index and attribute_length fields.
*/
static int computeAnnotationsSize(
final AnnotationWriter lastRuntimeVisibleAnnotation,
final AnnotationWriter lastRuntimeInvisibleAnnotation,
final AnnotationWriter lastRuntimeVisibleTypeAnnotation,
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation) {
int size = 0;
if (lastRuntimeVisibleAnnotation != null) {
size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
}
if (lastRuntimeInvisibleAnnotation != null) {
size +=
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
size +=
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
size +=
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
}
return size;
}
/**
* Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
* <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
@ -366,6 +456,51 @@ final class AnnotationWriter extends AnnotationVisitor {
}
}
/**
* Puts the Runtime[In]Visible[Type]Annotations attributes containing the given annotations and
* all their <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector.
* Annotations are put in the same order they have been visited.
*
* @param symbolTable where the constants used in the AnnotationWriter instances are stored.
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be
* {@literal null}.
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field,
* method or class. The previous ones can be accessed with the {@link #previousAnnotation}
* field. May be {@literal null}.
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a
* field, method or class. The previous ones can be accessed with the {@link
* #previousAnnotation} field. May be {@literal null}.
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a
* field, method or class field. The previous ones can be accessed with the {@link
* #previousAnnotation} field. May be {@literal null}.
* @param output where the attributes must be put.
*/
static void putAnnotations(
final SymbolTable symbolTable,
final AnnotationWriter lastRuntimeVisibleAnnotation,
final AnnotationWriter lastRuntimeInvisibleAnnotation,
final AnnotationWriter lastRuntimeVisibleTypeAnnotation,
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation,
final ByteVector output) {
if (lastRuntimeVisibleAnnotation != null) {
lastRuntimeVisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleAnnotation != null) {
lastRuntimeInvisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
lastRuntimeVisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
}
}
/**
* Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
* annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the

@ -59,7 +59,7 @@
package jdk.internal.org.objectweb.asm;
/**
* A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
* 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
@ -83,7 +83,7 @@ public class Attribute {
/**
* 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}.
* store a list of class, field, method or Code attributes). May be {@literal null}.
*/
Attribute nextAttribute;
@ -111,9 +111,9 @@ public class Attribute {
}
/**
* Returns {@literal true} if this type of attribute is a code attribute.
* Returns {@literal true} if this type of attribute is a Code attribute.
*
* @return {@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;
@ -123,7 +123,7 @@ public class Attribute {
* 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.
* a Code attribute that contains labels.
*/
protected Label[] getLabels() {
return new Label[0];
@ -135,18 +135,18 @@ public class Attribute {
* 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
* @param offset index of the first byte of the attribute's content in {@link ClassReader}. 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
* in {@link ClassReader}, 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.
* is not a Code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
*/
protected Attribute read(
@ -158,7 +158,7 @@ public class Attribute {
final Label[] labels) {
Attribute attribute = new Attribute(type);
attribute.content = new byte[length];
System.arraycopy(classReader.b, offset, attribute.content, 0, length);
System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
return attribute;
}
@ -169,16 +169,16 @@ public class Attribute {
*
* @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
* @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'
* 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 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.
* attribute, or -1 if this attribute is not a Code attribute.
* @return the byte array form of this attribute.
*/
protected ByteVector write(
@ -228,16 +228,16 @@ public class Attribute {
* 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
* @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
* 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 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.
* 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.
*/
@ -258,6 +258,42 @@ public class Attribute {
return size;
}
/**
* Returns the total size in bytes of all the attributes that correspond to the given field,
* method or class access flags and signature. This size includes the 6 header bytes
* (attribute_name_index and attribute_length) per attribute. Also adds the attribute type names
* to the constant pool.
*
* @param symbolTable where the constants used in the attributes must be stored.
* @param accessFlags some field, method or class access flags.
* @param signatureIndex the constant pool index of a field, method of class signature.
* @return the size of all the attributes in bytes. This size includes the size of the attribute
* headers.
*/
static int computeAttributesSize(
final SymbolTable symbolTable, final int accessFlags, final int signatureIndex) {
int size = 0;
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
// Synthetic attributes always use 6 bytes.
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
size += 6;
}
if (signatureIndex != 0) {
// Signature attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.SIGNATURE);
size += 8;
}
// ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
// Deprecated attributes always use 6 bytes.
symbolTable.addConstantUtf8(Constants.DEPRECATED);
size += 6;
}
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
@ -280,16 +316,16 @@ public class Attribute {
* 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
* @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
* 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 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.
* Code attributes, or -1 if they are not Code attribute.
* @param output where the attributes must be written.
*/
final void putAttributes(
@ -311,6 +347,37 @@ public class Attribute {
}
}
/**
* Puts all the attributes that correspond to the given field, method or class access flags and
* signature, in the given byte vector. This includes the 6 header bytes (attribute_name_index and
* attribute_length) per attribute.
*
* @param symbolTable where the constants used in the attributes must be stored.
* @param accessFlags some field, method or class access flags.
* @param signatureIndex the constant pool index of a field, method of class signature.
* @param output where the attributes must be written.
*/
static void putAttributes(
final SymbolTable symbolTable,
final int accessFlags,
final int signatureIndex,
final ByteVector output) {
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
}
if (signatureIndex != 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
.putInt(2)
.putShort(signatureIndex);
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
}
}
/** A set of attribute prototypes (attributes with the same type are considered equal). */
static final class Set {

@ -61,9 +61,9 @@ package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a Java class. The methods of this class must be called in the following order:
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
* visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
* {@code visitMethod} )* {@code visitEnd}.
* visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
* visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
*
* @author Eric Bruneton
*/
@ -75,7 +75,7 @@ public abstract class ClassVisitor {
*/
protected final int api;
/** The class visitor to which this visitor must delegate method calls. May be null. */
/** The class visitor to which this visitor must delegate method calls. May be {@literal null}. */
protected ClassVisitor cv;
/**
@ -92,13 +92,23 @@ public abstract class ClassVisitor {
* Constructs a new {@link ClassVisitor}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.
*/
@SuppressWarnings("deprecation")
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.cv = classVisitor;
@ -110,7 +120,8 @@ public abstract class ClassVisitor {
* @param version the class version. The minor version is stored in the 16 most significant bits,
* and the major version in the 16 least significant bits.
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
* the class is deprecated.
* the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link
* Opcodes#ACC_RECORD}.
* @param name the internal name of the class (see {@link Type#getInternalName()}).
* @param signature the signature of this class. May be {@literal null} if the class is not a
* generic one, and does not extend or implement generic classes or interfaces.
@ -127,6 +138,9 @@ public abstract class ClassVisitor {
final String signature,
final String superName,
final String[] interfaces) {
if (api < Opcodes.ASM8 && (access & Opcodes.ACC_RECORD) != 0) {
throw new UnsupportedOperationException("Records requires ASM8");
}
if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces);
}
@ -271,6 +285,24 @@ public abstract class ClassVisitor {
}
}
/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
* of the allowed subtypes of the current class.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
if (api != Opcodes.ASM9_EXPERIMENTAL) {
throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
}
if (cv != null) {
cv.visitPermittedSubtypeExperimental(permittedSubtype);
}
}
/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited.
@ -290,6 +322,27 @@ public abstract class ClassVisitor {
}
}
/**
* Visits a record component of the class.
*
* @param name the record component name.
* @param descriptor the record component descriptor (see {@link Type}).
* @param signature the record component signature. May be {@literal null} if the record component
* type does not use generic types.
* @return a visitor to visit this record component annotations and attributes, or {@literal null}
* if this class visitor is not interested in visiting these annotations and attributes.
*/
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
if (api < Opcodes.ASM8) {
throw new UnsupportedOperationException("This feature requires ASM8");
}
if (cv != null) {
return cv.visitRecordComponent(name, descriptor, signature);
}
return null;
}
/**
* Visits a field of the class.
*

@ -110,8 +110,8 @@ public class ClassWriter extends ClassVisitor {
/**
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
* access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
* ClassFile structure.
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
* removed when generating the ClassFile structure.
*/
private int accessFlags;
@ -208,6 +208,26 @@ public class ClassWriter extends ClassVisitor {
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */
private ByteVector nestMemberClasses;
/** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
private int numberOfPermittedSubtypeClasses;
/** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
private ByteVector permittedSubtypeClasses;
/**
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the first
* element of this list.
*/
private RecordComponentWriter firstRecordComponent;
/**
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the last
* element of this list.
*/
private RecordComponentWriter lastRecordComponent;
/**
* The first non standard attribute of this class. The next ones can be accessed with the {@link
* Attribute#nextAttribute} field. May be {@literal null}.
@ -265,7 +285,7 @@ public class ClassWriter extends ClassVisitor {
* maximum stack size nor the stack frames will be computed for these methods</i>.
*/
public ClassWriter(final ClassReader classReader, final int flags) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
if ((flags & COMPUTE_FRAMES) != 0) {
this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
@ -329,7 +349,7 @@ public class ClassWriter extends ClassVisitor {
}
@Override
public void visitNestHost(final String nestHost) {
public final void visitNestHost(final String nestHost) {
nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
}
@ -344,37 +364,26 @@ public class ClassWriter extends ClassVisitor {
@Override
public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
// Create a ByteVector to hold an 'annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
ByteVector annotation = new ByteVector();
// Write type_index and reserve space for num_element_value_pairs.
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else {
return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
}
}
@Override
public final AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget(typeRef, typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else {
return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
}
}
@ -386,7 +395,7 @@ public class ClassWriter extends ClassVisitor {
}
@Override
public void visitNestMember(final String nestMember) {
public final void visitNestMember(final String nestMember) {
if (nestMemberClasses == null) {
nestMemberClasses = new ByteVector();
}
@ -394,6 +403,22 @@ public class ClassWriter extends ClassVisitor {
nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
}
/**
* <b>Experimental, use at your own risk.</b>
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
if (permittedSubtypeClasses == null) {
permittedSubtypeClasses = new ByteVector();
}
++numberOfPermittedSubtypeClasses;
permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
}
@Override
public final void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
@ -419,6 +444,19 @@ public class ClassWriter extends ClassVisitor {
// and throw an exception if there is a difference?
}
@Override
public final RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
RecordComponentWriter recordComponentWriter =
new RecordComponentWriter(symbolTable, name, descriptor, signature);
if (firstRecordComponent == null) {
firstRecordComponent = recordComponentWriter;
} else {
lastRecordComponent.delegate = recordComponentWriter;
}
return lastRecordComponent = recordComponentWriter;
}
@Override
public final FieldVisitor visitField(
final int access,
@ -469,7 +507,7 @@ public class ClassWriter extends ClassVisitor {
* @throws ClassTooLargeException if the constant pool of the class is too large.
* @throws MethodTooLargeException if the Code attribute of a method is too large.
*/
public byte[] toByteArray() throws ClassTooLargeException, MethodTooLargeException {
public byte[] toByteArray() {
// First step: compute the size in bytes of the ClassFile structure.
// The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
// constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
@ -489,6 +527,7 @@ public class ClassWriter extends ClassVisitor {
size += methodWriter.computeMethodInfoSize();
methodWriter = (MethodWriter) methodWriter.mv;
}
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
int attributesCount = 0;
if (innerClasses != null) {
@ -568,6 +607,24 @@ public class ClassWriter extends ClassVisitor {
size += 8 + nestMemberClasses.length;
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
}
if (permittedSubtypeClasses != null) {
++attributesCount;
size += 8 + permittedSubtypeClasses.length;
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
}
int recordComponentCount = 0;
int recordSize = 0;
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
++recordComponentCount;
recordSize += recordComponentWriter.computeRecordComponentInfoSize();
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
++attributesCount;
size += 8 + recordSize;
symbolTable.addConstantUtf8(Constants.RECORD);
}
if (firstAttribute != null) {
attributesCount += firstAttribute.getAttributeCount();
size += firstAttribute.computeAttributesSize(symbolTable);
@ -648,22 +705,13 @@ public class ClassWriter extends ClassVisitor {
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
}
if (lastRuntimeVisibleAnnotation != null) {
lastRuntimeVisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result);
}
if (lastRuntimeInvisibleAnnotation != null) {
lastRuntimeInvisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
lastRuntimeVisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result);
}
AnnotationWriter.putAnnotations(
symbolTable,
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation,
result);
symbolTable.putBootstrapMethods(result);
if (moduleWriter != null) {
moduleWriter.putAttributes(result);
@ -681,6 +729,24 @@ public class ClassWriter extends ClassVisitor {
.putShort(numberOfNestMemberClasses)
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
}
if (permittedSubtypeClasses != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
.putInt(permittedSubtypeClasses.length + 2)
.putShort(numberOfPermittedSubtypeClasses)
.putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
}
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.RECORD))
.putInt(recordSize + 2)
.putShort(recordComponentCount);
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
recordComponentWriter.putRecordComponentInfo(result);
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
}
if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, result);
}
@ -717,6 +783,10 @@ public class ClassWriter extends ClassVisitor {
nestHostClassIndex = 0;
numberOfNestMemberClasses = 0;
nestMemberClasses = null;
numberOfPermittedSubtypeClasses = 0;
permittedSubtypeClasses = null;
firstRecordComponent = null;
lastRecordComponent = null;
firstAttribute = null;
compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
new ClassReader(classFile, 0, /* checkClassVersion = */ false)
@ -745,6 +815,11 @@ public class ClassWriter extends ClassVisitor {
methodWriter.collectAttributePrototypes(attributePrototypes);
methodWriter = (MethodWriter) methodWriter.mv;
}
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
recordComponentWriter.collectAttributePrototypes(attributePrototypes);
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
return attributePrototypes.toArray();
}

@ -58,6 +58,11 @@
*/
package jdk.internal.org.objectweb.asm;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;
/**
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
* API.
@ -65,7 +70,7 @@ package jdk.internal.org.objectweb.asm;
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
* @author Eric Bruneton
*/
final class Constants implements Opcodes {
final class Constants {
// The ClassFile attribute names, in the order they are defined in
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
@ -99,6 +104,8 @@ final class Constants implements Opcodes {
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers";
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
static final String RECORD = "Record";
// ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
@ -171,7 +178,7 @@ final class Constants implements Opcodes {
// Constants to convert between normal and wide jump instructions.
// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO;
// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
@ -184,25 +191,62 @@ final class Constants implements Opcodes {
// ASM specific opcodes, used for long forward jump instructions.
static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_GOTO_W = 220;
private Constants() {}
static void checkAsmExperimental(final Object caller) {
Class<?> callerClass = caller.getClass();
String internalName = callerClass.getName().replace('.', '/');
if (!isWhitelisted(internalName)) {
checkIsPreview(callerClass.getClassLoader().getResourceAsStream(internalName + ".class"));
}
}
static boolean isWhitelisted(final String internalName) {
if (!internalName.startsWith("jdk/internal/org/objectweb/asm/")) {
return false;
}
String member = "(Annotation|Class|Field|Method|Module|RecordComponent|Signature)";
return internalName.contains("Test$")
|| Pattern.matches(
"jdk/internal/org/objectweb/asm/util/Trace" + member + "Visitor(\\$.*)?", internalName)
|| Pattern.matches(
"jdk/internal/org/objectweb/asm/util/Check" + member + "Adapter(\\$.*)?", internalName);
}
static void checkIsPreview(final InputStream classInputStream) {
if (classInputStream == null) {
throw new IllegalStateException("Bytecode not available, can't check class version");
}
int minorVersion;
try (DataInputStream callerClassStream = new DataInputStream(classInputStream); ) {
callerClassStream.readInt();
minorVersion = callerClassStream.readUnsignedShort();
} catch (IOException ioe) {
throw new IllegalStateException("I/O error, can't check class version", ioe);
}
if (minorVersion != 0xFFFF) {
throw new IllegalStateException(
"ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
}
}
}

@ -69,18 +69,20 @@ public abstract class FieldVisitor {
/**
* 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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
*/
protected final int api;
/** The field visitor to which this visitor must delegate method calls. May be null. */
/** The field visitor to which this visitor must delegate method calls. May be {@literal null}. */
protected FieldVisitor fv;
/**
* Constructs a new {@link FieldVisitor}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
*/
public FieldVisitor(final int api) {
this(api, null);
@ -90,13 +92,23 @@ public abstract class FieldVisitor {
* Constructs a new {@link FieldVisitor}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
* null.
*/
@SuppressWarnings("deprecation")
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.fv = fieldVisitor;

@ -155,7 +155,7 @@ final class FieldWriter extends FieldVisitor {
final String descriptor,
final String signature,
final Object constantValue) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.accessFlags = access;
this.nameIndex = symbolTable.addConstantUtf8(name);
@ -174,37 +174,26 @@ final class FieldWriter extends FieldVisitor {
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
// Create a ByteVector to hold an 'annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
ByteVector annotation = new ByteVector();
// Write type_index and reserve space for num_element_value_pairs.
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else {
return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
}
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget(typeRef, typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else {
return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
}
}
@ -239,44 +228,13 @@ final class FieldWriter extends FieldVisitor {
symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
size += 8;
}
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
// Synthetic attributes always use 6 bytes.
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
size += 6;
}
if (signatureIndex != 0) {
// Signature attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.SIGNATURE);
size += 8;
}
// ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
// Deprecated attributes always use 6 bytes.
symbolTable.addConstantUtf8(Constants.DEPRECATED);
size += 6;
}
if (lastRuntimeVisibleAnnotation != null) {
size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
}
if (lastRuntimeInvisibleAnnotation != null) {
size +=
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
size +=
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
size +=
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
}
size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
size +=
AnnotationWriter.computeAnnotationsSize(
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation);
if (firstAttribute != null) {
size += firstAttribute.computeAttributesSize(symbolTable);
}
@ -333,34 +291,14 @@ final class FieldWriter extends FieldVisitor {
.putInt(2)
.putShort(constantValueIndex);
}
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
}
if (signatureIndex != 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
.putInt(2)
.putShort(signatureIndex);
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
}
if (lastRuntimeVisibleAnnotation != null) {
lastRuntimeVisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleAnnotation != null) {
lastRuntimeInvisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
lastRuntimeVisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
}
Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
AnnotationWriter.putAnnotations(
symbolTable,
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation,
output);
if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, output);
}

@ -85,19 +85,19 @@ package jdk.internal.org.objectweb.asm;
*
* <pre>
* =====================================
* |.DIM|KIND|FLAG|...............VALUE|
* |...DIM|KIND|.F|...............VALUE|
* =====================================
* </pre>
*
* <ul>
* <li>the DIM field, stored in the 4 most significant bits, is a signed number of array
* dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right
* shift of {@link #DIM_SHIFT}.
* <li>the DIM field, stored in the 6 most significant bits, is a signed number of array
* dimensions (from -32 to 31, included). It can be retrieved with {@link #DIM_MASK} and a
* right shift of {@link #DIM_SHIFT}.
* <li>the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
* retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link
* #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
* or {@link #STACK_KIND}.
* <li>the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag
* <li>the FLAGS field, stored in 2 bits, contains up to 2 boolean flags. Currently only one flag
* is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
* <li>the VALUE field, stored in the remaining 20 bits, contains either
* <ul>
@ -120,9 +120,9 @@ package jdk.internal.org.objectweb.asm;
* <p>Output frames can contain abstract types of any kind and with a positive or negative array
* dimension (and even unassigned types, represented by 0 - which does not correspond to any valid
* abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or
* UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type
* table contains only internal type names (array type descriptors are forbidden - array dimensions
* must be represented through the DIM field).
* UNINITIALIZED_KIND abstract types of positive or {@literal null} array dimension. In all cases
* the type table contains only internal type names (array type descriptors are forbidden - array
* dimensions must be represented through the DIM field).
*
* <p>The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE +
* TOP), for local variables as well as in the operand stack. This is necessary to be able to
@ -160,18 +160,25 @@ class Frame {
private static final int ITEM_ASM_CHAR = 11;
private static final int ITEM_ASM_SHORT = 12;
// The size and offset in bits of each field of an abstract type.
private static final int DIM_SIZE = 6;
private static final int KIND_SIZE = 4;
private static final int FLAGS_SIZE = 2;
private static final int VALUE_SIZE = 32 - DIM_SIZE - KIND_SIZE - FLAGS_SIZE;
private static final int DIM_SHIFT = KIND_SIZE + FLAGS_SIZE + VALUE_SIZE;
private static final int KIND_SHIFT = FLAGS_SIZE + VALUE_SIZE;
private static final int FLAGS_SHIFT = VALUE_SIZE;
// Bitmasks to get each field of an abstract type.
private static final int DIM_MASK = 0xF0000000;
private static final int KIND_MASK = 0x0F000000;
private static final int FLAGS_MASK = 0x00F00000;
private static final int VALUE_MASK = 0x000FFFFF;
private static final int DIM_MASK = ((1 << DIM_SIZE) - 1) << DIM_SHIFT;
private static final int KIND_MASK = ((1 << KIND_SIZE) - 1) << KIND_SHIFT;
private static final int VALUE_MASK = (1 << VALUE_SIZE) - 1;
// Constants to manipulate the DIM field of an abstract type.
/** The number of right shift bits to use to get the array dimensions of an abstract type. */
private static final int DIM_SHIFT = 28;
/** The constant to be added to an abstract type to get one with one more array dimension. */
private static final int ARRAY_OF = +1 << DIM_SHIFT;
@ -180,11 +187,11 @@ class Frame {
// Possible values for the KIND field of an abstract type.
private static final int CONSTANT_KIND = 0x01000000;
private static final int REFERENCE_KIND = 0x02000000;
private static final int UNINITIALIZED_KIND = 0x03000000;
private static final int LOCAL_KIND = 0x04000000;
private static final int STACK_KIND = 0x05000000;
private static final int CONSTANT_KIND = 1 << KIND_SHIFT;
private static final int REFERENCE_KIND = 2 << KIND_SHIFT;
private static final int UNINITIALIZED_KIND = 3 << KIND_SHIFT;
private static final int LOCAL_KIND = 4 << KIND_SHIFT;
private static final int STACK_KIND = 5 << KIND_SHIFT;
// Possible flags for the FLAGS field of an abstract type.
@ -193,7 +200,7 @@ class Frame {
* concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been
* partially overridden with an xSTORE instruction).
*/
private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK;
private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 1 << FLAGS_SHIFT;
// Useful predefined abstract types (all the possible CONSTANT_KIND types).
@ -571,7 +578,8 @@ class Frame {
* @param descriptor a type or method descriptor (in which case its return type is pushed).
*/
private void push(final SymbolTable symbolTable, final String descriptor) {
int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
int typeDescriptorOffset =
descriptor.charAt(0) == '(' ? Type.getReturnTypeOffset(descriptor) : 0;
int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset);
if (abstractType != 0) {
push(abstractType);
@ -1134,6 +1142,42 @@ class Frame {
// Frame merging methods, used in the second step of the stack map frame computation algorithm
// -----------------------------------------------------------------------------------------------
/**
* Computes the concrete output type corresponding to a given abstract output type.
*
* @param abstractOutputType an abstract output type.
* @param numStack the size of the input stack, used to resolve abstract output types of
* STACK_KIND kind.
* @return the concrete output type corresponding to 'abstractOutputType'.
*/
private int getConcreteOutputType(final int abstractOutputType, final int numStack) {
int dim = abstractOutputType & DIM_MASK;
int kind = abstractOutputType & KIND_MASK;
if (kind == LOCAL_KIND) {
// By definition, a LOCAL_KIND type designates the concrete type of a local variable at
// the beginning of the basic block corresponding to this frame (which is known when
// this method is called, but was not when the abstract type was computed).
int concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
return concreteOutputType;
} else if (kind == STACK_KIND) {
// By definition, a STACK_KIND type designates the concrete type of a local variable at
// the beginning of the basic block corresponding to this frame (which is known when
// this method is called, but was not when the abstract type was computed).
int concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
return concreteOutputType;
} else {
return abstractOutputType;
}
}
/**
* Merges the input frame of the given {@link Frame} with the input and output frames of this
* {@link Frame}. Returns {@literal true} if the given frame has been changed by this operation
@ -1168,29 +1212,7 @@ class Frame {
// value at the beginning of the block.
concreteOutputType = inputLocals[i];
} else {
int dim = abstractOutputType & DIM_MASK;
int kind = abstractOutputType & KIND_MASK;
if (kind == LOCAL_KIND) {
// By definition, a LOCAL_KIND type designates the concrete type of a local variable at
// the beginning of the basic block corresponding to this frame (which is known when
// this method is called, but was not when the abstract type was computed).
concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
} else if (kind == STACK_KIND) {
// By definition, a STACK_KIND type designates the concrete type of a local variable at
// the beginning of the basic block corresponding to this frame (which is known when
// this method is called, but was not when the abstract type was computed).
concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
} else {
concreteOutputType = abstractOutputType;
}
concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
}
} else {
// If the local variable has never been assigned in this basic block, it is equal to its
@ -1244,25 +1266,8 @@ class Frame {
// Then, do this for the stack operands that have pushed in the basic block (this code is the
// same as the one above for local variables).
for (int i = 0; i < outputStackTop; ++i) {
int concreteOutputType;
int abstractOutputType = outputStack[i];
int dim = abstractOutputType & DIM_MASK;
int kind = abstractOutputType & KIND_MASK;
if (kind == LOCAL_KIND) {
concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
} else if (kind == STACK_KIND) {
concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
concreteOutputType = TOP;
}
} else {
concreteOutputType = abstractOutputType;
}
int concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
}
@ -1279,10 +1284,10 @@ class Frame {
* @param symbolTable the type table to use to lookup and store type {@link Symbol}.
* @param sourceType the abstract type with which the abstract type array element must be merged.
* This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link
* #UNINITIALIZED_KIND} kind, with positive or null array dimensions.
* #UNINITIALIZED_KIND} kind, with positive or {@literal null} array dimensions.
* @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND},
* {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array
* dimensions.
* {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or {@literal
* null} array dimensions.
* @param dstIndex the index of the type that must be merged in dstTypes.
* @return {@literal true} if the type array has been modified by this operation.
*/

@ -258,7 +258,8 @@ public class Label {
/**
* The maximum height reached by the output stack, relatively to the top of the input stack, in
* the basic block corresponding to this label. This maximum is always positive or null.
* the basic block corresponding to this label. This maximum is always positive or {@literal
* null}.
*/
short outputStackMax;
@ -295,12 +296,12 @@ public class Label {
Edge outgoingEdges;
/**
* The next element in the list of labels to which this label belongs, or null if it does not
* belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in
* order to ensure that this field is null if and only if this label does not belong to a list of
* labels. Note that there can be several lists of labels at the same time, but that a label can
* belong to at most one list at a time (unless some lists share a common tail, but this is not
* used in practice).
* The next element in the list of labels to which this label belongs, or {@literal null} if it
* does not belong to any list. All lists of labels must end with the {@link #EMPTY_LIST}
* sentinel, in order to ensure that this field is null if and only if this label does not belong
* to a list of labels. Note that there can be several lists of labels at the same time, but that
* a label can belong to at most one list at a time (unless some lists share a common tail, but
* this is not used in practice).
*
* <p>List of labels are used in {@link MethodWriter#computeAllFrames} and {@link
* MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size,

@ -87,7 +87,9 @@ public abstract class MethodVisitor {
*/
protected final int api;
/** The method visitor to which this visitor must delegate method calls. May be null. */
/**
* The method visitor to which this visitor must delegate method calls. May be {@literal null}.
*/
protected MethodVisitor mv;
/**
@ -108,9 +110,18 @@ public abstract class MethodVisitor {
* @param methodVisitor the method visitor to which this visitor must delegate method calls. May
* be null.
*/
@SuppressWarnings("deprecation")
public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.mv = methodVisitor;
@ -123,7 +134,7 @@ public abstract class MethodVisitor {
/**
* Visits a parameter of this method.
*
* @param name parameter name or null if none is provided.
* @param name parameter name or {@literal null} if none is provided.
* @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
* or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
*/
@ -426,14 +437,8 @@ public abstract class MethodVisitor {
@Deprecated
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor);
}
int opcodeAndSource = opcode | (api < Opcodes.ASM5 ? Opcodes.SOURCE_DEPRECATED : 0);
visitMethodInsn(opcodeAndSource, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
/**
@ -453,15 +458,15 @@ public abstract class MethodVisitor {
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (api < Opcodes.ASM5 && (opcode & Opcodes.SOURCE_DEPRECATED) == 0) {
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
throw new UnsupportedOperationException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
}
visitMethodInsn(opcode, owner, name, descriptor);
return;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
mv.visitMethodInsn(opcode & ~Opcodes.SOURCE_MASK, owner, name, descriptor, isInterface);
}
}
@ -569,7 +574,7 @@ public abstract class MethodVisitor {
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException(REQUIRES_ASM5);
}
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (mv != null) {

@ -623,7 +623,7 @@ final class MethodWriter extends MethodVisitor {
final String signature,
final String[] exceptions,
final int compute) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
this.nameIndex = symbolTable.addConstantUtf8(name);
@ -685,37 +685,26 @@ final class MethodWriter extends MethodVisitor {
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
// Create a ByteVector to hold an 'annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
ByteVector annotation = new ByteVector();
// Write type_index and reserve space for num_element_value_pairs.
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else {
return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
}
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget(typeRef, typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else {
return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
}
}
@ -731,27 +720,24 @@ final class MethodWriter extends MethodVisitor {
@Override
public AnnotationVisitor visitParameterAnnotation(
final int parameter, final String annotationDescriptor, final boolean visible) {
// Create a ByteVector to hold an 'annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
ByteVector annotation = new ByteVector();
// Write type_index and reserve space for num_element_value_pairs.
annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0);
if (visible) {
if (lastRuntimeVisibleParameterAnnotations == null) {
lastRuntimeVisibleParameterAnnotations =
new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
}
return lastRuntimeVisibleParameterAnnotations[parameter] =
new AnnotationWriter(
symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]);
AnnotationWriter.create(
symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
} else {
if (lastRuntimeInvisibleParameterAnnotations == null) {
lastRuntimeInvisibleParameterAnnotations =
new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
}
return lastRuntimeInvisibleParameterAnnotations[parameter] =
new AnnotationWriter(
symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]);
AnnotationWriter.create(
symbolTable,
annotationDescriptor,
lastRuntimeInvisibleParameterAnnotations[parameter]);
}
}
@ -820,6 +806,9 @@ final class MethodWriter extends MethodVisitor {
}
visitFrameEnd();
} else {
if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
}
int offsetDelta;
if (stackMapTableEntries == null) {
stackMapTableEntries = new ByteVector();
@ -1446,20 +1435,22 @@ final class MethodWriter extends MethodVisitor {
@Override
public AnnotationVisitor visitInsnAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable,
(typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
typePath,
descriptor,
lastCodeRuntimeVisibleTypeAnnotation);
} else {
return lastCodeRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable,
(typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
typePath,
descriptor,
lastCodeRuntimeInvisibleTypeAnnotation);
}
}
@ -1480,20 +1471,14 @@ final class MethodWriter extends MethodVisitor {
@Override
public AnnotationVisitor visitTryCatchAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
ByteVector typeAnnotation = new ByteVector();
// Write target_type, target_info, and target_path.
TypeReference.putTarget(typeRef, typeAnnotation);
TypePath.put(typePath, typeAnnotation);
// Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
} else {
return lastCodeRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation);
}
}
@ -1561,10 +1546,18 @@ final class MethodWriter extends MethodVisitor {
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
new AnnotationWriter(
symbolTable,
/* useNamedValues = */ true,
typeAnnotation,
lastCodeRuntimeVisibleTypeAnnotation);
} else {
return lastCodeRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
new AnnotationWriter(
symbolTable,
/* useNamedValues = */ true,
typeAnnotation,
lastCodeRuntimeInvisibleTypeAnnotation);
}
}
@ -2035,10 +2028,6 @@ final class MethodWriter extends MethodVisitor {
* attribute) are the same as the corresponding attributes in the given method.
*
* @param source the source ClassReader from which the attributes of this method might be copied.
* @param methodInfoOffset the offset in 'source.b' of the method_info JVMS structure from which
* the attributes of this method might be copied.
* @param methodInfoLength the length in 'source.b' of the method_info JVMS structure from which
* the attributes of this method might be copied.
* @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
* of this method might be copied contains a Synthetic attribute.
* @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
@ -2055,8 +2044,6 @@ final class MethodWriter extends MethodVisitor {
*/
boolean canCopyMethodAttributes(
final ClassReader source,
final int methodInfoOffset,
final int methodInfoLength,
final boolean hasSyntheticAttribute,
final boolean hasDeprecatedAttribute,
final int descriptorIndex,
@ -2091,12 +2078,23 @@ final class MethodWriter extends MethodVisitor {
currentExceptionOffset += 2;
}
}
return true;
}
/**
* Sets the source from which the attributes of this method will be copied.
*
* @param methodInfoOffset the offset in 'symbolTable.getSource()' of the method_info JVMS
* structure from which the attributes of this method will be copied.
* @param methodInfoLength the length in 'symbolTable.getSource()' of the method_info JVMS
* structure from which the attributes of this method will be copied.
*/
void setMethodAttributesSource(final int methodInfoOffset, final int methodInfoLength) {
// Don't copy the attributes yet, instead store their location in the source class reader so
// they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
// of the method_info JVMS structure.
this.sourceOffset = methodInfoOffset + 6;
this.sourceLength = methodInfoLength - 6;
return true;
}
/**
@ -2164,29 +2162,13 @@ final class MethodWriter extends MethodVisitor {
symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
size += 8 + 2 * numberOfExceptions;
}
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
size += 6;
}
if (signatureIndex != 0) {
symbolTable.addConstantUtf8(Constants.SIGNATURE);
size += 8;
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
symbolTable.addConstantUtf8(Constants.DEPRECATED);
size += 6;
}
if (lastRuntimeVisibleAnnotation != null) {
size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
}
if (lastRuntimeInvisibleAnnotation != null) {
size +=
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
}
size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
size +=
AnnotationWriter.computeAnnotationsSize(
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation);
if (lastRuntimeVisibleParameterAnnotations != null) {
size +=
AnnotationWriter.computeParameterAnnotationsSize(
@ -2205,16 +2187,6 @@ final class MethodWriter extends MethodVisitor {
? lastRuntimeInvisibleParameterAnnotations.length
: invisibleAnnotableParameterCount);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
size +=
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
size +=
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
}
if (defaultValue != null) {
symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
size += 6 + defaultValue.length;
@ -2242,7 +2214,7 @@ final class MethodWriter extends MethodVisitor {
output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
// If this method_info must be copied from an existing one, copy it now and return early.
if (sourceOffset != 0) {
output.putByteArray(symbolTable.getSource().b, sourceOffset, sourceLength);
output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength);
return;
}
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
@ -2396,26 +2368,14 @@ final class MethodWriter extends MethodVisitor {
output.putShort(exceptionIndex);
}
}
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
}
if (signatureIndex != 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
.putInt(2)
.putShort(signatureIndex);
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
}
if (lastRuntimeVisibleAnnotation != null) {
lastRuntimeVisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleAnnotation != null) {
lastRuntimeInvisibleAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
}
Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
AnnotationWriter.putAnnotations(
symbolTable,
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation,
output);
if (lastRuntimeVisibleParameterAnnotations != null) {
AnnotationWriter.putParameterAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
@ -2434,14 +2394,6 @@ final class MethodWriter extends MethodVisitor {
: invisibleAnnotableParameterCount,
output);
}
if (lastRuntimeVisibleTypeAnnotation != null) {
lastRuntimeVisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
}
if (defaultValue != null) {
output
.putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))

@ -73,7 +73,9 @@ public abstract class ModuleVisitor {
*/
protected final int api;
/** The module visitor to which this visitor must delegate method calls. May be null. */
/**
* The module visitor to which this visitor must delegate method calls. May be {@literal null}.
*/
protected ModuleVisitor mv;
/**
@ -94,9 +96,18 @@ public abstract class ModuleVisitor {
* @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
* be null.
*/
@SuppressWarnings("deprecation")
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.mv = moduleVisitor;

@ -125,7 +125,7 @@ final class ModuleWriter extends ModuleVisitor {
private int mainClassIndex;
ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.moduleNameIndex = name;
this.moduleFlags = access;

@ -78,9 +78,222 @@ public interface Opcodes {
int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8;
int ASM7 = 7 << 16 | 0 << 8;
int ASM8 = 8 << 16 | 0 << 8;
// Java ClassFile versions (the minor version is stored in the 16 most
// significant bits, and the
/**
* <i>Experimental, use at your own risk. This field will be renamed when it becomes stable, this
* will break existing code using it. Only code compiled with --enable-preview can use this.</i>
*
* @deprecated This API is experimental.
*/
@Deprecated int ASM9_EXPERIMENTAL = 1 << 24 | 9 << 16 | 0 << 8;
/*
* Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff
* method in API_OLD is deprecated and replaced with visitNewStuff in API_NEW, then the
* redirection should be done as follows:
*
* <pre>
* public class StuffVisitor {
* ...
*
* &#64;Deprecated public void visitOldStuff(int arg, ...) {
* // SOURCE_DEPRECATED means "a call from a deprecated method using the old 'api' value".
* visitNewStuf(arg | (api &#60; API_NEW ? SOURCE_DEPRECATED : 0), ...);
* }
*
* public void visitNewStuff(int argAndSource, ...) {
* if (api &#60; API_NEW &#38;&#38; (argAndSource &#38; SOURCE_DEPRECATED) == 0) {
* visitOldStuff(argAndSource, ...);
* } else {
* int arg = argAndSource &#38; ~SOURCE_MASK;
* [ do stuff ]
* }
* }
* }
* </pre>
*
* <p>If 'api' is equal to API_NEW, there are two cases:
*
* <ul>
* <li>call visitNewStuff: the redirection test is skipped and 'do stuff' is executed directly.
* <li>call visitOldSuff: the source is not set to SOURCE_DEPRECATED before calling
* visitNewStuff, but the redirection test is skipped anyway in visitNewStuff, which
* directly executes 'do stuff'.
* </ul>
*
* <p>If 'api' is equal to API_OLD, there are two cases:
*
* <ul>
* <li>call visitOldSuff: the source is set to SOURCE_DEPRECATED before calling visitNewStuff.
* Because of this visitNewStuff does not redirect back to visitOldStuff, and instead
* executes 'do stuff'.
* <li>call visitNewStuff: the call is redirected to visitOldStuff because the source is 0.
* visitOldStuff now sets the source to SOURCE_DEPRECATED and calls visitNewStuff back. This
* time visitNewStuff does not redirect the call, and instead executes 'do stuff'.
* </ul>
*
* <h1>User subclasses</h1>
*
* <p>If a user subclass overrides one of these methods, there are only two cases: either 'api' is
* API_OLD and visitOldStuff is overridden (and visitNewStuff is not), or 'api' is API_NEW or
* more, and visitNewStuff is overridden (and visitOldStuff is not). Any other case is a user
* programming error.
*
* <p>If 'api' is equal to API_NEW, the class hierarchy is equivalent to
*
* <pre>
* public class StuffVisitor {
* &#64;Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
* public void visitNewStuff(int arg, ...) { [ do stuff ] }
* }
* class UserStuffVisitor extends StuffVisitor {
* &#64;Override public void visitNewStuff(int arg, ...) {
* super.visitNewStuff(int arg, ...); // optional
* [ do user stuff ]
* }
* }
* </pre>
*
* <p>It is then obvious that whether visitNewStuff or visitOldStuff is called, 'do stuff' and 'do
* user stuff' will be executed, in this order.
*
* <p>If 'api' is equal to API_OLD, the class hierarchy is equivalent to
*
* <pre>
* public class StuffVisitor {
* &#64;Deprecated public void visitOldStuff(int arg, ...) {
* visitNewStuf(arg | SOURCE_DEPRECATED, ...);
* }
* public void visitNewStuff(int argAndSource...) {
* if ((argAndSource & SOURCE_DEPRECATED) == 0) {
* visitOldStuff(argAndSource, ...);
* } else {
* int arg = argAndSource &#38; ~SOURCE_MASK;
* [ do stuff ]
* }
* }
* }
* class UserStuffVisitor extends StuffVisitor {
* &#64;Override public void visitOldStuff(int arg, ...) {
* super.visitOldStuff(int arg, ...); // optional
* [ do user stuff ]
* }
* }
* </pre>
*
* <p>and there are two cases:
*
* <ul>
* <li>call visitOldSuff: in the call to super.visitOldStuff, the source is set to
* SOURCE_DEPRECATED and visitNewStuff is called. Here 'do stuff' is run because the source
* was previously set to SOURCE_DEPRECATED, and execution eventually returns to
* UserStuffVisitor.visitOldStuff, where 'do user stuff' is run.
* <li>call visitNewStuff: the call is redirected to UserStuffVisitor.visitOldStuff because the
* source is 0. Execution continues as in the previous case, resulting in 'do stuff' and 'do
* user stuff' being executed, in this order.
* </ul>
*
* <h1>ASM subclasses</h1>
*
* <p>In ASM packages, subclasses of StuffVisitor can typically be sub classed again by the user,
* and can be used with API_OLD or API_NEW. Because of this, if such a subclass must override
* visitNewStuff, it must do so in the following way (and must not override visitOldStuff):
*
* <pre>
* public class AsmStuffVisitor extends StuffVisitor {
* &#64;Override public void visitNewStuff(int argAndSource, ...) {
* if (api &#60; API_NEW &#38;&#38; (argAndSource &#38; SOURCE_DEPRECATED) == 0) {
* super.visitNewStuff(argAndSource, ...);
* return;
* }
* super.visitNewStuff(argAndSource, ...); // optional
* int arg = argAndSource &#38; ~SOURCE_MASK;
* [ do other stuff ]
* }
* }
* </pre>
*
* <p>If a user class extends this with 'api' equal to API_NEW, the class hierarchy is equivalent
* to
*
* <pre>
* public class StuffVisitor {
* &#64;Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
* public void visitNewStuff(int arg, ...) { [ do stuff ] }
* }
* public class AsmStuffVisitor extends StuffVisitor {
* &#64;Override public void visitNewStuff(int arg, ...) {
* super.visitNewStuff(arg, ...);
* [ do other stuff ]
* }
* }
* class UserStuffVisitor extends StuffVisitor {
* &#64;Override public void visitNewStuff(int arg, ...) {
* super.visitNewStuff(int arg, ...);
* [ do user stuff ]
* }
* }
* </pre>
*
* <p>It is then obvious that whether visitNewStuff or visitOldStuff is called, 'do stuff', 'do
* other stuff' and 'do user stuff' will be executed, in this order. If, on the other hand, a user
* class extends AsmStuffVisitor with 'api' equal to API_OLD, the class hierarchy is equivalent to
*
* <pre>
* public class StuffVisitor {
* &#64;Deprecated public void visitOldStuff(int arg, ...) {
* visitNewStuf(arg | SOURCE_DEPRECATED, ...);
* }
* public void visitNewStuff(int argAndSource, ...) {
* if ((argAndSource & SOURCE_DEPRECATED) == 0) {
* visitOldStuff(argAndSource, ...);
* } else {
* int arg = argAndSource &#38; ~SOURCE_MASK;
* [ do stuff ]
* }
* }
* }
* public class AsmStuffVisitor extends StuffVisitor {
* &#64;Override public void visitNewStuff(int argAndSource, ...) {
* if ((argAndSource &#38; SOURCE_DEPRECATED) == 0) {
* super.visitNewStuff(argAndSource, ...);
* return;
* }
* super.visitNewStuff(argAndSource, ...); // optional
* int arg = argAndSource &#38; ~SOURCE_MASK;
* [ do other stuff ]
* }
* }
* class UserStuffVisitor extends StuffVisitor {
* &#64;Override public void visitOldStuff(int arg, ...) {
* super.visitOldStuff(arg, ...);
* [ do user stuff ]
* }
* }
* </pre>
*
* <p>and, here again, whether visitNewStuff or visitOldStuff is called, 'do stuff', 'do other
* stuff' and 'do user stuff' will be executed, in this order (exercise left to the reader).
*
* <h1>Notes</h1>
*
* <ul>
* <li>the SOURCE_DEPRECATED flag is set only if 'api' is API_OLD, just before calling
* visitNewStuff. By hypothesis, this method is not overridden by the user. Therefore, user
* classes can never see this flag. Only ASM subclasses must take care of extracting the
* actual argument value by clearing the source flags.
* <li>because the SOURCE_DEPRECATED flag is immediately cleared in the caller, the caller can
* call visitOldStuff or visitNewStuff (in 'do stuff' and 'do user stuff') on a delegate
* visitor without any risks (breaking the redirection logic, "leaking" the flag, etc).
* <li>all the scenarios discussed above are unit tested in MethodVisitorTest.
* </ul>
*/
int SOURCE_DEPRECATED = 0x100;
int SOURCE_MASK = SOURCE_DEPRECATED;
// Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the
// major version in the 16 least significant bits).
int V1_1 = 3 << 16 | 45;
@ -134,7 +347,7 @@ public interface Opcodes {
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner
int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific access flags.
@ -142,6 +355,7 @@ public interface Opcodes {
// access flags, and also to make sure that these flags are automatically filtered out when
// written in class files (because access flags are stored using 16 bits only).
int ACC_RECORD = 0x10000; // class
int ACC_DEPRECATED = 0x20000; // class, field, method
// Possible values for the type operand of the NEWARRAY instruction.

@ -0,0 +1,182 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a record component. The methods of this class must be called in the following
* order: ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
* visitEnd}.
*
* @author Remi Forax
* @author Eric Bruneton
*/
public abstract class RecordComponentVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field must be {@link
* Opcodes#ASM8}.
*/
protected final int api;
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*/
/*package-private*/ RecordComponentVisitor delegate;
/**
* Constructs a new {@link RecordComponentVisitor}.
*
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
*/
public RecordComponentVisitor(final int api) {
this(api, null);
}
/**
* Constructs a new {@link RecordComponentVisitor}.
*
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
* @param recordComponentVisitor the record component visitor to which this visitor must delegate
* method calls. May be null.
*/
@SuppressWarnings("deprecation")
public RecordComponentVisitor(
final int api, final RecordComponentVisitor recordComponentVisitor) {
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.delegate = recordComponentVisitor;
}
/**
* The record visitor to which this visitor must delegate method calls. May be {@literal null}.
*
* @return the record visitor to which this visitor must delegate method calls or {@literal null}.
*/
public RecordComponentVisitor getDelegate() {
return delegate;
}
/**
* Visits an annotation of the record component.
*
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (delegate != null) {
return delegate.visitAnnotation(descriptor, visible);
}
return null;
}
/**
* Visits an annotation on a type in the record component signature.
*
* @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
* {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (delegate != null) {
return delegate.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
return null;
}
/**
* Visits a non standard attribute of the record component.
*
* @param attribute an attribute.
*/
public void visitAttribute(final Attribute attribute) {
if (delegate != null) {
delegate.visitAttribute(attribute);
}
}
/**
* Visits the end of the record component. This method, which is the last one to be called, is
* used to inform the visitor that everything have been visited.
*/
public void visitEnd() {
if (delegate != null) {
delegate.visitEnd();
}
}
}

@ -0,0 +1,256 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm;
final class RecordComponentWriter extends RecordComponentVisitor {
/** Where the constants used in this RecordComponentWriter must be stored. */
private final SymbolTable symbolTable;
// Note: fields are ordered as in the record_component_info structure, and those related to
// attributes are ordered as in Section 4.7 of the JVMS.
/** The name_index field of the Record attribute. */
private final int nameIndex;
/** The descriptor_index field of the the Record attribute. */
private final int descriptorIndex;
/**
* The signature_index field of the Signature attribute of this record component, or 0 if there is
* no Signature attribute.
*/
private int signatureIndex;
/**
* The last runtime visible annotation of this record component. The previous ones can be accessed
* with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter lastRuntimeVisibleAnnotation;
/**
* The last runtime invisible annotation of this record component. The previous ones can be
* accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter lastRuntimeInvisibleAnnotation;
/**
* The last runtime visible type annotation of this record component. The previous ones can be
* accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
/**
* The last runtime invisible type annotation of this record component. The previous ones can be
* accessed with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
/**
* The first non standard attribute of this record component. The next ones can be accessed with
* the {@link Attribute#nextAttribute} field. May be {@literal null}.
*
* <p><b>WARNING</b>: this list stores the attributes in the <i>reverse</i> order of their visit.
* firstAttribute is actually the last attribute visited in {@link #visitAttribute(Attribute)}.
* The {@link #putRecordComponentInfo(ByteVector)} method writes the attributes in the order
* defined by this list, i.e. in the reverse order specified by the user.
*/
private Attribute firstAttribute;
/**
* Constructs a new {@link RecordComponentWriter}.
*
* @param symbolTable where the constants used in this RecordComponentWriter must be stored.
* @param name the record component name.
* @param descriptor the record component descriptor (see {@link Type}).
* @param signature the record component signature. May be {@literal null}.
*/
RecordComponentWriter(
final SymbolTable symbolTable,
final String name,
final String descriptor,
final String signature) {
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.nameIndex = symbolTable.addConstantUtf8(name);
this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
if (signature != null) {
this.signatureIndex = symbolTable.addConstantUtf8(signature);
}
}
// -----------------------------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// -----------------------------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (visible) {
return lastRuntimeVisibleAnnotation =
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else {
return lastRuntimeInvisibleAnnotation =
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
}
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (visible) {
return lastRuntimeVisibleTypeAnnotation =
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else {
return lastRuntimeInvisibleTypeAnnotation =
AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
}
}
@Override
public void visitAttribute(final Attribute attribute) {
// Store the attributes in the <i>reverse</i> order of their visit by this method.
attribute.nextAttribute = firstAttribute;
firstAttribute = attribute;
}
@Override
public void visitEnd() {
// Nothing to do.
}
// -----------------------------------------------------------------------------------------------
// Utility methods
// -----------------------------------------------------------------------------------------------
/**
* Returns the size of the record component JVMS structure generated by this
* RecordComponentWriter. Also adds the names of the attributes of this record component in the
* constant pool.
*
* @return the size in bytes of the record_component_info of the Record attribute.
*/
int computeRecordComponentInfoSize() {
// name_index, descriptor_index and attributes_count fields use 6 bytes.
int size = 6;
size += Attribute.computeAttributesSize(symbolTable, 0, signatureIndex);
size +=
AnnotationWriter.computeAnnotationsSize(
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation);
if (firstAttribute != null) {
size += firstAttribute.computeAttributesSize(symbolTable);
}
return size;
}
/**
* Puts the content of the record component generated by this RecordComponentWriter into the given
* ByteVector.
*
* @param output where the record_component_info structure must be put.
*/
void putRecordComponentInfo(final ByteVector output) {
output.putShort(nameIndex).putShort(descriptorIndex);
// Compute and put the attributes_count field.
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
int attributesCount = 0;
if (signatureIndex != 0) {
++attributesCount;
}
if (lastRuntimeVisibleAnnotation != null) {
++attributesCount;
}
if (lastRuntimeInvisibleAnnotation != null) {
++attributesCount;
}
if (lastRuntimeVisibleTypeAnnotation != null) {
++attributesCount;
}
if (lastRuntimeInvisibleTypeAnnotation != null) {
++attributesCount;
}
if (firstAttribute != null) {
attributesCount += firstAttribute.getAttributeCount();
}
output.putShort(attributesCount);
Attribute.putAttributes(symbolTable, 0, signatureIndex, output);
AnnotationWriter.putAnnotations(
symbolTable,
lastRuntimeVisibleAnnotation,
lastRuntimeInvisibleAnnotation,
lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleTypeAnnotation,
output);
if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, output);
}
}
/**
* Collects the attributes of this record component into the given set of attribute prototypes.
*
* @param attributePrototypes a set of attribute prototypes.
*/
final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
attributePrototypes.addAttributes(firstAttribute);
}
}

@ -62,11 +62,11 @@ package jdk.internal.org.objectweb.asm;
* The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
* table entries of a class.
*
* @author Eric Bruneton
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
* 4.4</a>
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
* 4.7.23</a>
* @author Eric Bruneton
*/
final class SymbolTable {
@ -170,7 +170,7 @@ final class SymbolTable {
this.sourceClassReader = classReader;
// Copy the constant pool binary content.
byte[] inputBytes = classReader.b;
byte[] inputBytes = classReader.classFileBuffer;
int constantPoolOffset = classReader.getItem(1) - 1;
int constantPoolLength = classReader.header - constantPoolOffset;
constantPoolCount = classReader.getItemCount();
@ -273,7 +273,7 @@ final class SymbolTable {
*/
private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
// Find attributOffset of the 'bootstrap_methods' array.
byte[] inputBytes = classReader.b;
byte[] inputBytes = classReader.classFileBuffer;
int currentAttributeOffset = classReader.getFirstAttributeOffset();
for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
@ -1077,8 +1077,10 @@ final class SymbolTable {
// bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
// and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
// while adding the given bootstrap method to it, in the rest of this method.
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
addConstant(bootstrapMethodArgument);
int numBootstrapArguments = bootstrapMethodArguments.length;
int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments];
for (int i = 0; i < numBootstrapArguments; i++) {
bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index;
}
// Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
@ -1093,10 +1095,10 @@ final class SymbolTable {
bootstrapMethodHandle.getDesc(),
bootstrapMethodHandle.isInterface())
.index);
int numBootstrapArguments = bootstrapMethodArguments.length;
bootstrapMethodsAttribute.putShort(numBootstrapArguments);
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
for (int i = 0; i < numBootstrapArguments; i++) {
bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]);
}
// Compute the length and the hash code of the bootstrap method.
@ -1214,8 +1216,10 @@ final class SymbolTable {
* corresponding to the common super class of the given types.
*/
int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
// TODO sort the arguments? The merge result should be independent of their order.
long data = typeTableIndex1 | (((long) typeTableIndex2) << 32);
long data =
typeTableIndex1 < typeTableIndex2
? typeTableIndex1 | (((long) typeTableIndex2) << 32)
: typeTableIndex2 | (((long) typeTableIndex1) << 32);
int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
Entry entry = get(hashCode);
while (entry != null) {

@ -336,7 +336,8 @@ public final class Type {
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
}
++numArgumentTypes;
}
@ -354,7 +355,8 @@ public final class Type {
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
}
argumentTypes[currentArgumentTypeIndex++] =
getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
@ -394,19 +396,8 @@ public final class Type {
* @return the {@link Type} corresponding to the return type of the given method descriptor.
*/
public static Type getReturnType(final String methodDescriptor) {
// Skip the first character, which is always a '('.
int currentOffset = 1;
// Skip the argument types, one at a each loop iteration.
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
}
}
return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length());
return getTypeInternal(
methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length());
}
/**
@ -419,6 +410,29 @@ public final class Type {
return getType(method.getReturnType());
}
/**
* Returns the start index of the return type of the given method descriptor.
*
* @param methodDescriptor a method descriptor.
* @return the start index of the return type of the given method descriptor.
*/
static int getReturnTypeOffset(final String methodDescriptor) {
// Skip the first character, which is always a '('.
int currentOffset = 1;
// Skip the argument types, one at a each loop iteration.
while (methodDescriptor.charAt(currentOffset) != ')') {
while (methodDescriptor.charAt(currentOffset) == '[') {
currentOffset++;
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
}
}
return currentOffset + 1;
}
/**
* Returns the {@link Type} corresponding to the given field or method descriptor.
*
@ -536,11 +550,7 @@ public final class Type {
if (sort == OBJECT) {
return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
} else if (sort == INTERNAL) {
return new StringBuilder()
.append('L')
.append(valueBuffer, valueBegin, valueEnd)
.append(';')
.toString();
return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';';
} else {
return valueBuffer.substring(valueBegin, valueEnd);
}
@ -662,14 +672,7 @@ public final class Type {
}
stringBuilder.append(descriptor);
} else {
stringBuilder.append('L');
String name = currentClass.getName();
int nameLength = name.length();
for (int i = 0; i < nameLength; ++i) {
char car = name.charAt(i);
stringBuilder.append(car == '.' ? '/' : car);
}
stringBuilder.append(';');
stringBuilder.append('L').append(getInternalName(currentClass)).append(';');
}
}
@ -768,7 +771,8 @@ public final class Type {
}
if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
}
argumentsSize += 1;
}

@ -147,7 +147,7 @@ public final class TypePath {
* @return the corresponding TypePath object, or {@literal null} if the path is empty.
*/
public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.isEmpty()) {
if (typePath == null || typePath.length() == 0) {
return null;
}
int typePathLength = typePath.length();

@ -152,8 +152,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
public void visitCode() {
super.visitCode();
if (isConstructor) {
stackFrame = new ArrayList<Object>();
forwardJumpStackFrames = new HashMap<Label, List<Object>>();
stackFrame = new ArrayList<>();
forwardJumpStackFrames = new HashMap<>();
} else {
onMethodEnter();
}
@ -382,6 +382,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
popValue();
popValue();
break;
case RET:
break;
default:
throw new IllegalArgumentException(INVALID_OPCODE + opcode);
}
@ -467,35 +469,21 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
}
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
mv.visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, descriptor);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
doVisitMethodInsn(opcode, descriptor);
}
@ -611,7 +599,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
// initialized twice), so this is not issue (in the sense that there is no risk to emit a wrong
// 'onMethodEnter').
if (isConstructor && !forwardJumpStackFrames.containsKey(handler)) {
List<Object> handlerStackFrame = new ArrayList<Object>();
List<Object> handlerStackFrame = new ArrayList<>();
handlerStackFrame.add(OTHER);
forwardJumpStackFrames.put(handler, handlerStackFrame);
}
@ -628,7 +616,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
if (forwardJumpStackFrames.containsKey(label)) {
return;
}
forwardJumpStackFrames.put(label, new ArrayList<Object>(stackFrame));
forwardJumpStackFrames.put(label, new ArrayList<>(stackFrame));
}
private Object popValue() {

@ -147,7 +147,7 @@ public class AnalyzerAdapter extends MethodVisitor {
final String name,
final String descriptor,
final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, owner, access, name, descriptor, methodVisitor);
this(/* latest api = */ Opcodes.ASM8, owner, access, name, descriptor, methodVisitor);
if (getClass() != AnalyzerAdapter.class) {
throw new IllegalStateException();
}
@ -157,7 +157,8 @@ public class AnalyzerAdapter extends MethodVisitor {
* Constructs a new {@link AnalyzerAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param owner the owner's class name.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
@ -174,9 +175,9 @@ public class AnalyzerAdapter extends MethodVisitor {
final MethodVisitor methodVisitor) {
super(api, methodVisitor);
this.owner = owner;
locals = new ArrayList<Object>();
stack = new ArrayList<Object>();
uninitializedTypes = new HashMap<Object, Object>();
locals = new ArrayList<>();
stack = new ArrayList<>();
uninitializedTypes = new HashMap<>();
if ((access & Opcodes.ACC_STATIC) == 0) {
if ("<init>".equals(name)) {
@ -236,8 +237,8 @@ public class AnalyzerAdapter extends MethodVisitor {
this.locals.clear();
this.stack.clear();
} else {
this.locals = new ArrayList<Object>();
this.stack = new ArrayList<Object>();
this.locals = new ArrayList<>();
this.stack = new ArrayList<>();
}
visitFrameTypes(numLocal, local, this.locals);
visitFrameTypes(numStack, stack, this.stack);
@ -289,7 +290,7 @@ public class AnalyzerAdapter extends MethodVisitor {
if (opcode == Opcodes.NEW) {
if (labels == null) {
Label label = new Label();
labels = new ArrayList<Label>(3);
labels = new ArrayList<>(3);
labels.add(label);
if (mv != null) {
mv.visitLabel(label);
@ -310,45 +311,21 @@ public class AnalyzerAdapter extends MethodVisitor {
execute(opcode, 0, descriptor);
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
if (this.locals == null) {
labels = null;
return;
@ -409,7 +386,7 @@ public class AnalyzerAdapter extends MethodVisitor {
public void visitLabel(final Label label) {
super.visitLabel(label);
if (labels == null) {
labels = new ArrayList<Label>(3);
labels = new ArrayList<>(3);
}
labels.add(label);
}
@ -526,9 +503,12 @@ public class AnalyzerAdapter extends MethodVisitor {
maxStack = Math.max(maxStack, stack.size());
}
private void pushDescriptor(final String descriptor) {
int index = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
switch (descriptor.charAt(index)) {
private void pushDescriptor(final String fieldOrMethodDescriptor) {
String descriptor =
fieldOrMethodDescriptor.charAt(0) == '('
? Type.getReturnType(fieldOrMethodDescriptor).getDescriptor()
: fieldOrMethodDescriptor;
switch (descriptor.charAt(0)) {
case 'V':
return;
case 'Z':
@ -550,18 +530,10 @@ public class AnalyzerAdapter extends MethodVisitor {
push(Opcodes.TOP);
return;
case '[':
if (index == 0) {
push(descriptor);
} else {
push(descriptor.substring(index, descriptor.length()));
}
push(descriptor);
break;
case 'L':
if (index == 0) {
push(descriptor.substring(1, descriptor.length() - 1));
} else {
push(descriptor.substring(index + 1, descriptor.length() - 1));
}
push(descriptor.substring(1, descriptor.length() - 1));
break;
default:
throw new AssertionError();
@ -597,6 +569,9 @@ public class AnalyzerAdapter extends MethodVisitor {
}
private void execute(final int opcode, final int intArg, final String stringArg) {
if (opcode == Opcodes.JSR || opcode == Opcodes.RET) {
throw new IllegalArgumentException("JSR/RET are not supported");
}
if (this.locals == null) {
labels = null;
return;
@ -897,9 +872,6 @@ public class AnalyzerAdapter extends MethodVisitor {
pop(4);
push(Opcodes.INTEGER);
break;
case Opcodes.JSR:
case Opcodes.RET:
throw new IllegalArgumentException("JSR/RET are not supported");
case Opcodes.GETSTATIC:
pushDescriptor(stringArg);
break;

@ -79,15 +79,16 @@ public class AnnotationRemapper extends AnnotationVisitor {
* @param remapper the remapper to use to remap the types in the visited annotation.
*/
public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) {
this(Opcodes.ASM7, annotationVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, annotationVisitor, remapper);
}
/**
* Constructs a new {@link AnnotationRemapper}.
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}
* @param annotationVisitor the annotation visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited annotation.
*/
@ -113,9 +114,7 @@ public class AnnotationRemapper extends AnnotationVisitor {
if (annotationVisitor == null) {
return null;
} else {
return annotationVisitor == av
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
}
}
@ -125,9 +124,18 @@ public class AnnotationRemapper extends AnnotationVisitor {
if (annotationVisitor == null) {
return null;
} else {
return annotationVisitor == av
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
}
}
/**
* Constructs a new remapper for annotations. The default implementation of this method returns a
* new {@link AnnotationRemapper}.
*
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
return new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

@ -66,11 +66,26 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link ClassVisitor} that remaps types with a {@link Remapper}.
*
* <p><i>This visitor has several limitations</i>. A non-exhaustive list is the following:
*
* <ul>
* <li>it cannot remap type names in dynamically computed strings (remapping of type names in
* static values is supported).
* <li>it cannot remap values derived from type names at compile time, such as
* <ul>
* <li>type name hashcodes used by some Java compilers to implement the string switch
* statement.
* <li>some compound strings used by some Java compilers to implement lambda
* deserialization.
* </ul>
* </ul>
*
* @author Eugene Kuleshov
*/
public class ClassRemapper extends ClassVisitor {
@ -89,7 +104,7 @@ public class ClassRemapper extends ClassVisitor {
* @param remapper the remapper to use to remap the types in the visited class.
*/
public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) {
this(Opcodes.ASM7, classVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, classVisitor, remapper);
}
/**
@ -97,7 +112,8 @@ public class ClassRemapper extends ClassVisitor {
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param classVisitor the class visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited class.
*/
@ -157,6 +173,19 @@ public class ClassRemapper extends ClassVisitor {
super.visitAttribute(attribute);
}
@Override
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
RecordComponentVisitor recordComponentVisitor =
super.visitRecordComponent(
remapper.mapRecordComponentName(className, name, descriptor),
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true));
return recordComponentVisitor == null
? null
: createRecordComponentRemapper(recordComponentVisitor);
}
@Override
public FieldVisitor visitField(
final int access,
@ -220,6 +249,18 @@ public class ClassRemapper extends ClassVisitor {
super.visitNestMember(remapper.mapType(nestMember));
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
super.visitPermittedSubtypeExperimental(remapper.mapType(permittedSubtype));
}
/**
* Constructs a new remapper for fields. The default implementation of this method returns a new
* {@link FieldRemapper}.
@ -263,4 +304,16 @@ public class ClassRemapper extends ClassVisitor {
protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
return new ModuleRemapper(api, moduleVisitor, remapper);
}
/**
* Constructs a new remapper for record components. The default implementation of this method
* returns a new {@link RecordComponentRemapper}.
*
* @param recordComponentVisitor the RecordComponentVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected RecordComponentVisitor createRecordComponentRemapper(
final RecordComponentVisitor recordComponentVisitor) {
return new RecordComponentRemapper(api, recordComponentVisitor, remapper);
}
}

@ -78,7 +78,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
private int maxSize;
public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, methodVisitor);
this(/* latest api = */ Opcodes.ASM8, methodVisitor);
}
protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
@ -142,42 +142,20 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
super.visitFieldInsn(opcode, owner, name, descriptor);
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (opcode == INVOKEINTERFACE) {
minSize += 5;
maxSize += 5;
@ -185,9 +163,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 3;
maxSize += 3;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
}
@Override

@ -81,15 +81,15 @@ public class FieldRemapper extends FieldVisitor {
* @param remapper the remapper to use to remap the types in the visited field.
*/
public FieldRemapper(final FieldVisitor fieldVisitor, final Remapper remapper) {
this(Opcodes.ASM7, fieldVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, fieldVisitor, remapper);
}
/**
* Constructs a new {@link FieldRemapper}.
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
* @param fieldVisitor the field visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited field.
*/
@ -102,9 +102,7 @@ public class FieldRemapper extends FieldVisitor {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? null
: new AnnotationRemapper(api, annotationVisitor, remapper);
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
}
@Override
@ -112,8 +110,17 @@ public class FieldRemapper extends FieldVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? null
: new AnnotationRemapper(api, annotationVisitor, remapper);
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
}
/**
* Constructs a new remapper for annotations. The default implementation of this method returns a
* new {@link AnnotationRemapper}.
*
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
return new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

@ -214,7 +214,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
private final Type[] argumentTypes;
/** The types of the local variables of the visited method. */
private final List<Type> localTypes = new ArrayList<Type>();
private final List<Type> localTypes = new ArrayList<>();
/**
* Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
@ -232,7 +232,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
final int access,
final String name,
final String descriptor) {
this(Opcodes.ASM7, methodVisitor, access, name, descriptor);
this(/* latest api = */ Opcodes.ASM8, methodVisitor, access, name, descriptor);
if (getClass() != GeneratorAdapter.class) {
throw new IllegalStateException();
}
@ -242,7 +242,8 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* Constructs a new {@link GeneratorAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param methodVisitor the method visitor to which this adapter delegates calls.
* @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name.
@ -300,7 +301,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
method.getName(),
method.getDescriptor(),
signature,
getInternalNames(exceptions)));
exceptions == null ? null : getInternalNames(exceptions)));
}
/**
@ -310,9 +311,6 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* @return the internal names of the given types.
*/
private static String[] getInternalNames(final Type[] types) {
if (types == null) {
return null;
}
String[] names = new String[types.length];
for (int i = 0; i < names.length; ++i) {
names[i] = types[i].getInternalName();
@ -792,48 +790,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|| to.getSort() > Type.DOUBLE) {
throw new IllegalArgumentException("Cannot cast from " + from + " to " + to);
}
if (from == Type.DOUBLE_TYPE) {
if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.D2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.D2L);
} else {
mv.visitInsn(Opcodes.D2I);
cast(Type.INT_TYPE, to);
}
} else if (from == Type.FLOAT_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.F2D);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.F2L);
} else {
mv.visitInsn(Opcodes.F2I);
cast(Type.INT_TYPE, to);
}
} else if (from == Type.LONG_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.L2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.L2F);
} else {
mv.visitInsn(Opcodes.L2I);
cast(Type.INT_TYPE, to);
}
} else {
if (to == Type.BYTE_TYPE) {
mv.visitInsn(Opcodes.I2B);
} else if (to == Type.CHAR_TYPE) {
mv.visitInsn(Opcodes.I2C);
} else if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.I2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.I2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.I2L);
} else if (to == Type.SHORT_TYPE) {
mv.visitInsn(Opcodes.I2S);
}
}
InstructionAdapter.cast(mv, from, to);
}
}
@ -1350,37 +1307,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* @param type the type of the array elements.
*/
public void newArray(final Type type) {
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
arrayType = Opcodes.T_BOOLEAN;
break;
case Type.CHAR:
arrayType = Opcodes.T_CHAR;
break;
case Type.BYTE:
arrayType = Opcodes.T_BYTE;
break;
case Type.SHORT:
arrayType = Opcodes.T_SHORT;
break;
case Type.INT:
arrayType = Opcodes.T_INT;
break;
case Type.FLOAT:
arrayType = Opcodes.T_FLOAT;
break;
case Type.LONG:
arrayType = Opcodes.T_LONG;
break;
case Type.DOUBLE:
arrayType = Opcodes.T_DOUBLE;
break;
default:
typeInsn(Opcodes.ANEWARRAY, type);
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
InstructionAdapter.newarray(mv, type);
}
// -----------------------------------------------------------------------------------------------

@ -83,7 +83,7 @@ public class InstructionAdapter extends MethodVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public InstructionAdapter(final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, methodVisitor);
this(/* latest api = */ Opcodes.ASM8, methodVisitor);
if (getClass() != InstructionAdapter.class) {
throw new IllegalStateException();
}
@ -93,7 +93,8 @@ public class InstructionAdapter extends MethodVisitor {
* Constructs a new {@link InstructionAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param methodVisitor the method visitor to which this adapter delegates calls.
*/
protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) {
@ -536,42 +537,20 @@ public class InstructionAdapter extends MethodVisitor {
}
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
switch (opcode) {
case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, descriptor, isInterface);
@ -673,7 +652,7 @@ public class InstructionAdapter extends MethodVisitor {
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException("This feature requires ASM5");
}
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (value instanceof Integer) {
@ -947,47 +926,58 @@ public class InstructionAdapter extends MethodVisitor {
* @param to a Type.
*/
public void cast(final Type from, final Type to) {
cast(mv, from, to);
}
/**
* Generates the instruction to cast from the first given type to the other.
*
* @param methodVisitor the method visitor to use to generate the instruction.
* @param from a Type.
* @param to a Type.
*/
static void cast(final MethodVisitor methodVisitor, final Type from, final Type to) {
if (from != to) {
if (from == Type.DOUBLE_TYPE) {
if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.D2F);
methodVisitor.visitInsn(Opcodes.D2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.D2L);
methodVisitor.visitInsn(Opcodes.D2L);
} else {
mv.visitInsn(Opcodes.D2I);
cast(Type.INT_TYPE, to);
methodVisitor.visitInsn(Opcodes.D2I);
cast(methodVisitor, Type.INT_TYPE, to);
}
} else if (from == Type.FLOAT_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.F2D);
methodVisitor.visitInsn(Opcodes.F2D);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.F2L);
methodVisitor.visitInsn(Opcodes.F2L);
} else {
mv.visitInsn(Opcodes.F2I);
cast(Type.INT_TYPE, to);
methodVisitor.visitInsn(Opcodes.F2I);
cast(methodVisitor, Type.INT_TYPE, to);
}
} else if (from == Type.LONG_TYPE) {
if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.L2D);
methodVisitor.visitInsn(Opcodes.L2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.L2F);
methodVisitor.visitInsn(Opcodes.L2F);
} else {
mv.visitInsn(Opcodes.L2I);
cast(Type.INT_TYPE, to);
methodVisitor.visitInsn(Opcodes.L2I);
cast(methodVisitor, Type.INT_TYPE, to);
}
} else {
if (to == Type.BYTE_TYPE) {
mv.visitInsn(Opcodes.I2B);
methodVisitor.visitInsn(Opcodes.I2B);
} else if (to == Type.CHAR_TYPE) {
mv.visitInsn(Opcodes.I2C);
methodVisitor.visitInsn(Opcodes.I2C);
} else if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.I2D);
methodVisitor.visitInsn(Opcodes.I2D);
} else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.I2F);
methodVisitor.visitInsn(Opcodes.I2F);
} else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.I2L);
methodVisitor.visitInsn(Opcodes.I2L);
} else if (to == Type.SHORT_TYPE) {
mv.visitInsn(Opcodes.I2S);
methodVisitor.visitInsn(Opcodes.I2S);
}
}
}
@ -1256,6 +1246,16 @@ public class InstructionAdapter extends MethodVisitor {
* @param type an array Type.
*/
public void newarray(final Type type) {
newarray(mv, type);
}
/**
* Generates the instruction to create and push on the stack an array of the given type.
*
* @param methodVisitor the method visitor to use to generate the instruction.
* @param type an array Type.
*/
static void newarray(final MethodVisitor methodVisitor, final Type type) {
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
@ -1283,10 +1283,10 @@ public class InstructionAdapter extends MethodVisitor {
arrayType = Opcodes.T_DOUBLE;
break;
default:
mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType);
}
public void arraylength() {

@ -100,7 +100,7 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* instruction, bit i of the corresponding BitSet in this map is set iff instruction at index i
* belongs to this subroutine.
*/
private final Map<LabelNode, BitSet> subroutinesInsns = new HashMap<LabelNode, BitSet>();
private final Map<LabelNode, BitSet> subroutinesInsns = new HashMap<>();
/**
* The instructions that belong to more that one subroutine. Bit i is set iff instruction at index
@ -129,7 +129,14 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
final String descriptor,
final String signature,
final String[] exceptions) {
this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
this(
/* latest api = */ Opcodes.ASM8,
methodVisitor,
access,
name,
descriptor,
signature,
exceptions);
if (getClass() != JSRInlinerAdapter.class) {
throw new IllegalStateException();
}
@ -139,7 +146,8 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* Constructs a new {@link JSRInlinerAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param methodVisitor the method visitor to send the resulting inlined method code to, or <code>
* null</code>.
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
@ -322,14 +330,14 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* fully elaborated.
*/
private void emitCode() {
LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
LinkedList<Instantiation> worklist = new LinkedList<>();
// Create an instantiation of the main "subroutine", which is just the main routine.
worklist.add(new Instantiation(null, mainSubroutineInsns));
// Emit instantiations of each subroutine we encounter, including the main subroutine.
InsnList newInstructions = new InsnList();
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<>();
List<LocalVariableNode> newLocalVariables = new ArrayList<>();
while (!worklist.isEmpty()) {
Instantiation instantiation = worklist.removeFirst();
emitInstantiation(
@ -486,7 +494,7 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
this.parent = parent;
this.subroutineInsns = subroutineInsns;
this.returnLabel = parent == null ? null : new LabelNode();
this.clonedLabels = new HashMap<LabelNode, LabelNode>();
this.clonedLabels = new HashMap<>();
// Create a clone of each label in the original code of the subroutine. Note that we collapse
// labels which point at the same instruction into one.

@ -112,7 +112,7 @@ public class LocalVariablesSorter extends MethodVisitor {
*/
public LocalVariablesSorter(
final int access, final String descriptor, final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, access, descriptor, methodVisitor);
this(/* latest api = */ Opcodes.ASM8, access, descriptor, methodVisitor);
if (getClass() != LocalVariablesSorter.class) {
throw new IllegalStateException();
}
@ -122,7 +122,8 @@ public class LocalVariablesSorter extends MethodVisitor {
* Constructs a new {@link LocalVariablesSorter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param access access flags of the adapted method.
* @param descriptor the method's descriptor (see {@link Type}).
* @param methodVisitor the method visitor to which this adapter delegates calls.

@ -81,7 +81,7 @@ public class Method {
private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
static {
HashMap<String, String> descriptors = new HashMap<String, String>();
HashMap<String, String> descriptors = new HashMap<>();
descriptors.put("void", "V");
descriptors.put("byte", "B");
descriptors.put("char", "C");

@ -83,7 +83,7 @@ public class MethodRemapper extends MethodVisitor {
* @param remapper the remapper to use to remap the types in the visited method.
*/
public MethodRemapper(final MethodVisitor methodVisitor, final Remapper remapper) {
this(Opcodes.ASM7, methodVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, methodVisitor, remapper);
}
/**
@ -91,7 +91,8 @@ public class MethodRemapper extends MethodVisitor {
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param methodVisitor the method visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited method.
*/
@ -106,7 +107,7 @@ public class MethodRemapper extends MethodVisitor {
AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -115,7 +116,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -125,7 +126,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -135,7 +136,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -180,53 +181,24 @@ public class MethodRemapper extends MethodVisitor {
remapper.mapDesc(descriptor));
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
// Calling super.visitMethodInsn requires to call the correct version depending on this.api
// (otherwise infinite loops can occur). To simplify and to make it easier to automatically
// remove the backward compatibility code, we inline the code of the overridden method here.
if (mv != null) {
mv.visitMethodInsn(
opcode,
remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
}
super.visitMethodInsn(
opcodeAndSource,
remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
}
@Override
@ -268,7 +240,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -284,7 +256,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
@Override
@ -318,6 +290,17 @@ public class MethodRemapper extends MethodVisitor {
typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
: createAnnotationRemapper(annotationVisitor);
}
/**
* Constructs a new remapper for annotations. The default implementation of this method returns a
* new {@link AnnotationRemapper}.
*
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
return new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

@ -121,8 +121,8 @@ public final class ModuleHashesAttribute extends Attribute {
int numModules = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
ArrayList<String> moduleList = new ArrayList<String>(numModules);
ArrayList<byte[]> hashList = new ArrayList<byte[]>(numModules);
ArrayList<String> moduleList = new ArrayList<>(numModules);
ArrayList<byte[]> hashList = new ArrayList<>(numModules);
for (int i = 0; i < numModules; ++i) {
String module = classReader.readModule(currentOffset, charBuffer);

@ -79,15 +79,16 @@ public class ModuleRemapper extends ModuleVisitor {
* @param remapper the remapper to use to remap the types in the visited module.
*/
public ModuleRemapper(final ModuleVisitor moduleVisitor, final Remapper remapper) {
this(Opcodes.ASM7, moduleVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, moduleVisitor, remapper);
}
/**
* Constructs a new {@link ModuleRemapper}.
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param moduleVisitor the module visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited module.
*/

@ -0,0 +1,128 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link RecordComponentVisitor} that remaps types with a {@link Remapper}.
*
* @author Remi Forax
*/
public class RecordComponentRemapper extends RecordComponentVisitor {
/** The remapper used to remap the types in the visited field. */
protected final Remapper remapper;
/**
* Constructs a new {@link RecordComponentRemapper}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link
* #RecordComponentRemapper(int,RecordComponentVisitor,Remapper)} version.
*
* @param recordComponentVisitor the record component visitor this remapper must delegate to.
* @param remapper the remapper to use to remap the types in the visited record component.
*/
public RecordComponentRemapper(
final RecordComponentVisitor recordComponentVisitor, final Remapper remapper) {
this(/* latest api = */ Opcodes.ASM8, recordComponentVisitor, remapper);
}
/**
* Constructs a new {@link RecordComponentRemapper}.
*
* @param api the ASM API version supported by this remapper. Must be {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param recordComponentVisitor the record component visitor this remapper must delegate to.
* @param remapper the remapper to use to remap the types in the visited record component.
*/
protected RecordComponentRemapper(
final int api, final RecordComponentVisitor recordComponentVisitor, final Remapper remapper) {
super(api, recordComponentVisitor);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
}
/**
* Constructs a new remapper for annotations. The default implementation of this method returns a
* new {@link AnnotationRemapper}.
*
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
return new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

@ -140,8 +140,7 @@ public abstract class Remapper {
String remappedInternalName = mapType(internalName);
if (remappedInternalName != null) {
if (remappedInternalNames == null) {
remappedInternalNames = new String[internalNames.length];
System.arraycopy(internalNames, 0, remappedInternalNames, 0, internalNames.length);
remappedInternalNames = internalNames.clone();
}
remappedInternalNames[i] = remappedInternalName;
}
@ -281,7 +280,12 @@ public abstract class Remapper {
final String name, final String ownerName, final String innerName) {
final String remappedInnerName = this.mapType(name);
if (remappedInnerName.contains("$")) {
return remappedInnerName.substring(remappedInnerName.lastIndexOf('$') + 1);
int index = remappedInnerName.lastIndexOf('$') + 1;
while (index < remappedInnerName.length()
&& Character.isDigit(remappedInnerName.charAt(index))) {
index++;
}
return remappedInnerName.substring(index);
} else {
return innerName;
}
@ -312,6 +316,20 @@ public abstract class Remapper {
return name;
}
/**
* Maps a record component name to its new name. The default implementation of this method returns
* the given name, unchanged. Subclasses can override.
*
* @param owner the internal name of the owner class of the field.
* @param name the name of the field.
* @param descriptor the descriptor of the field.
* @return the new name of the field.
*/
public String mapRecordComponentName(
final String owner, final String name, final String descriptor) {
return name;
}
/**
* Maps a field name to its new name. The default implementation of this method returns the given
* name, unchanged. Subclasses can override.

@ -67,7 +67,6 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -182,7 +181,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public SerialVersionUIDAdder(final ClassVisitor classVisitor) {
this(Opcodes.ASM7, classVisitor);
this(/* latest api = */ Opcodes.ASM8, classVisitor);
if (getClass() != SerialVersionUIDAdder.class) {
throw new IllegalStateException();
}
@ -192,7 +191,8 @@ public class SerialVersionUIDAdder extends ClassVisitor {
* Constructs a new {@link SerialVersionUIDAdder}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
*/
protected SerialVersionUIDAdder(final int api, final ClassVisitor classVisitor) {
@ -218,11 +218,10 @@ public class SerialVersionUIDAdder extends ClassVisitor {
if (computeSvuid) {
this.name = name;
this.access = access;
this.interfaces = new String[interfaces.length];
this.svuidFields = new ArrayList<Item>();
this.svuidConstructors = new ArrayList<Item>();
this.svuidMethods = new ArrayList<Item>();
System.arraycopy(interfaces, 0, this.interfaces, 0, interfaces.length);
this.interfaces = interfaces.clone();
this.svuidFields = new ArrayList<>();
this.svuidConstructors = new ArrayList<>();
this.svuidMethods = new ArrayList<>();
}
super.visit(version, access, name, signature, superName, interfaces);
@ -372,13 +371,10 @@ public class SerialVersionUIDAdder extends ClassVisitor {
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected long computeSVUID() throws IOException {
ByteArrayOutputStream byteArrayOutputStream = null;
DataOutputStream dataOutputStream = null;
long svuid = 0;
try {
byteArrayOutputStream = new ByteArrayOutputStream();
dataOutputStream = new DataOutputStream(byteArrayOutputStream);
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
// 1. The class name written using UTF encoding.
dataOutputStream.writeUTF(name.replace('/', '.'));
@ -445,10 +441,6 @@ public class SerialVersionUIDAdder extends ClassVisitor {
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
}
} finally {
if (dataOutputStream != null) {
dataOutputStream.close();
}
}
return svuid;
@ -483,18 +475,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
final boolean dotted)
throws IOException {
Item[] items = itemCollection.toArray(new Item[0]);
Arrays.sort(
items,
new Comparator<Item>() {
@Override
public int compare(final Item item1, final Item item2) {
int result = item1.name.compareTo(item2.name);
if (result == 0) {
result = item1.descriptor.compareTo(item2.descriptor);
}
return result;
}
});
Arrays.sort(items);
for (Item item : items) {
dataOutputStream.writeUTF(item.name);
dataOutputStream.writeInt(item.access);
@ -506,7 +487,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
// Inner classes
// -----------------------------------------------------------------------------------------------
private static final class Item {
private static final class Item implements Comparable<Item> {
final String name;
final int access;
@ -517,5 +498,27 @@ public class SerialVersionUIDAdder extends ClassVisitor {
this.access = access;
this.descriptor = descriptor;
}
@Override
public int compareTo(final Item item) {
int result = name.compareTo(item.name);
if (result == 0) {
result = descriptor.compareTo(item.descriptor);
}
return result;
}
@Override
public boolean equals(final Object other) {
if (other instanceof Item) {
return compareTo((Item) other) == 0;
}
return false;
}
@Override
public int hashCode() {
return name.hashCode() ^ descriptor.hashCode();
}
}
}

@ -73,7 +73,7 @@ public class SignatureRemapper extends SignatureVisitor {
private final Remapper remapper;
private ArrayList<String> classNames = new ArrayList<String>();
private ArrayList<String> classNames = new ArrayList<>();
/**
* Constructs a new {@link SignatureRemapper}. <i>Subclasses must not use this constructor</i>.
@ -83,15 +83,16 @@ public class SignatureRemapper extends SignatureVisitor {
* @param remapper the remapper to use to remap the types in the visited signature.
*/
public SignatureRemapper(final SignatureVisitor signatureVisitor, final Remapper remapper) {
this(Opcodes.ASM7, signatureVisitor, remapper);
this(/* latest api = */ Opcodes.ASM8, signatureVisitor, remapper);
}
/**
* Constructs a new {@link SignatureRemapper}.
*
* @param api the ASM API version supported by this remapper. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5},{@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param signatureVisitor the signature visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited signature.
*/

@ -92,14 +92,15 @@ public class StaticInitMerger extends ClassVisitor {
* null.
*/
public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) {
this(Opcodes.ASM7, prefix, classVisitor);
this(/* latest api = */ Opcodes.ASM8, prefix, classVisitor);
}
/**
* Constructs a new {@link StaticInitMerger}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.

@ -100,7 +100,14 @@ public class TryCatchBlockSorter extends MethodNode {
final String descriptor,
final String signature,
final String[] exceptions) {
this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
this(
/* latest api = */ Opcodes.ASM8,
methodVisitor,
access,
name,
descriptor,
signature,
exceptions);
if (getClass() != TryCatchBlockSorter.class) {
throw new IllegalStateException();
}

@ -102,9 +102,15 @@ public abstract class SignatureVisitor {
* @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}.
*/
@SuppressWarnings("deprecation")
public SignatureVisitor(final int api) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
this.api = api;
}

@ -101,7 +101,7 @@ public class SignatureWriter extends SignatureVisitor {
/** Constructs a new {@link SignatureWriter}. */
public SignatureWriter() {
super(Opcodes.ASM7);
super(/* latest api =*/ Opcodes.ASM8);
}
// -----------------------------------------------------------------------------------------------

@ -270,7 +270,7 @@ public abstract class AbstractInsnNode {
*/
protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
if (insnNode.visibleTypeAnnotations != null) {
this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
this.visibleTypeAnnotations = new ArrayList<>();
for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
TypeAnnotationNode cloneAnnotation =
@ -281,7 +281,7 @@ public abstract class AbstractInsnNode {
}
}
if (insnNode.invisibleTypeAnnotations != null) {
this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
this.invisibleTypeAnnotations = new ArrayList<>();
for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
TypeAnnotationNode cloneAnnotation =

@ -91,7 +91,7 @@ public class AnnotationNode extends AnnotationVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public AnnotationNode(final String descriptor) {
this(Opcodes.ASM7, descriptor);
this(/* latest api = */ Opcodes.ASM8, descriptor);
if (getClass() != AnnotationNode.class) {
throw new IllegalStateException();
}
@ -101,7 +101,8 @@ public class AnnotationNode extends AnnotationVisitor {
* Constructs a new {@link AnnotationNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}
* @param descriptor the class descriptor of the annotation class.
*/
public AnnotationNode(final int api, final String descriptor) {
@ -115,7 +116,7 @@ public class AnnotationNode extends AnnotationVisitor {
* @param values where the visited values must be stored.
*/
AnnotationNode(final List<Object> values) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.values = values;
}
@ -126,7 +127,7 @@ public class AnnotationNode extends AnnotationVisitor {
@Override
public void visit(final String name, final Object value) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
values = new ArrayList<>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
@ -155,7 +156,7 @@ public class AnnotationNode extends AnnotationVisitor {
@Override
public void visitEnum(final String name, final String descriptor, final String value) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
values = new ArrayList<>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
@ -166,7 +167,7 @@ public class AnnotationNode extends AnnotationVisitor {
@Override
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
values = new ArrayList<>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
@ -179,12 +180,12 @@ public class AnnotationNode extends AnnotationVisitor {
@Override
public AnnotationVisitor visitArray(final String name) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
values = new ArrayList<>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
List<Object> array = new ArrayList<Object>();
List<Object> array = new ArrayList<>();
values.add(array);
return new AnnotationNode(array);
}
@ -204,7 +205,7 @@ public class AnnotationNode extends AnnotationVisitor {
* introduced in more recent versions of the ASM API than the given version.
*
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
*/
public void check(final int api) {
// nothing to do

@ -67,6 +67,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
@ -84,7 +85,7 @@ public class ClassNode extends ClassVisitor {
/**
* The class's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This field also indicates if
* the class is deprecated.
* the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link Opcodes#ACC_RECORD}.
*/
public int access;
@ -157,6 +158,18 @@ public class ClassNode extends ClassVisitor {
/** The internal names of the nest members of this class. May be {@literal null}. */
public List<String> nestMembers;
/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>. The internal names of the permitted subtypes of this
* class. May be {@literal null}.
*
* @deprecated this API is experimental.
*/
@Deprecated public List<String> permittedSubtypesExperimental;
/** The record components of this class. May be {@literal null}. */
public List<RecordComponentNode> recordComponents;
/** The fields of this class. */
public List<FieldNode> fields;
@ -170,7 +183,7 @@ public class ClassNode extends ClassVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public ClassNode() {
this(Opcodes.ASM7);
this(Opcodes.ASM8);
if (getClass() != ClassNode.class) {
throw new IllegalStateException();
}
@ -180,14 +193,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
*/
public ClassNode(final int api) {
super(api);
this.interfaces = new ArrayList<String>();
this.innerClasses = new ArrayList<InnerClassNode>();
this.fields = new ArrayList<FieldNode>();
this.methods = new ArrayList<MethodNode>();
this.interfaces = new ArrayList<>();
this.innerClasses = new ArrayList<>();
this.fields = new ArrayList<>();
this.methods = new ArrayList<>();
}
// -----------------------------------------------------------------------------------------------
@ -238,15 +252,9 @@ public class ClassNode extends ClassVisitor {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationNode annotation = new AnnotationNode(descriptor);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(annotation);
visibleAnnotations = Util.add(visibleAnnotations, annotation);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(annotation);
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
}
return annotation;
}
@ -256,33 +264,33 @@ public class ClassNode extends ClassVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(typeAnnotation);
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(typeAnnotation);
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@Override
public void visitAttribute(final Attribute attribute) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attribute);
attrs = Util.add(attrs, attribute);
}
@Override
public void visitNestMember(final String nestMember) {
if (nestMembers == null) {
nestMembers = new ArrayList<String>();
}
nestMembers.add(nestMember);
nestMembers = Util.add(nestMembers, nestMember);
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
permittedSubtypesExperimental = Util.add(permittedSubtypesExperimental, permittedSubtype);
}
@Override
@ -292,6 +300,14 @@ public class ClassNode extends ClassVisitor {
innerClasses.add(innerClass);
}
@Override
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
RecordComponentNode recordComponent = new RecordComponentNode(name, descriptor, signature);
recordComponents = Util.add(recordComponents, recordComponent);
return recordComponent;
}
@Override
public FieldVisitor visitField(
final int access,
@ -331,9 +347,16 @@ public class ClassNode extends ClassVisitor {
* in more recent versions of the ASM API than the given version.
*
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7}. or {@link Opcodes#ASM8}.
*/
@SuppressWarnings("deprecation")
public void check(final int api) {
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubtypesExperimental != null) {
throw new UnsupportedClassVersionException();
}
if (api < Opcodes.ASM8 && ((access & Opcodes.ACC_RECORD) != 0 || recordComponents != null)) {
throw new UnsupportedClassVersionException();
}
if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
throw new UnsupportedClassVersionException();
}
@ -369,6 +392,11 @@ public class ClassNode extends ClassVisitor {
invisibleTypeAnnotations.get(i).check(api);
}
}
if (recordComponents != null) {
for (int i = recordComponents.size() - 1; i >= 0; --i) {
recordComponents.get(i).check(api);
}
}
for (int i = fields.size() - 1; i >= 0; --i) {
fields.get(i).check(api);
}
@ -382,6 +410,7 @@ public class ClassNode extends ClassVisitor {
*
* @param classVisitor a class visitor.
*/
@SuppressWarnings("deprecation")
public void accept(final ClassVisitor classVisitor) {
// Visit the header.
String[] interfacesArray = new String[this.interfaces.size()];
@ -444,10 +473,22 @@ public class ClassNode extends ClassVisitor {
classVisitor.visitNestMember(nestMembers.get(i));
}
}
// Visit the permitted subtypes.
if (permittedSubtypesExperimental != null) {
for (int i = 0, n = permittedSubtypesExperimental.size(); i < n; ++i) {
classVisitor.visitPermittedSubtypeExperimental(permittedSubtypesExperimental.get(i));
}
}
// Visit the inner classes.
for (int i = 0, n = innerClasses.size(); i < n; ++i) {
innerClasses.get(i).accept(classVisitor);
}
// Visit the record components.
if (recordComponents != null) {
for (int i = 0, n = recordComponents.size(); i < n; ++i) {
recordComponents.get(i).accept(classVisitor);
}
}
// Visit the fields.
for (int i = 0, n = fields.size(); i < n; ++i) {
fields.get(i).accept(classVisitor);

@ -58,7 +58,6 @@
*/
package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
@ -131,17 +130,18 @@ public class FieldNode extends FieldVisitor {
final String descriptor,
final String signature,
final Object value) {
this(Opcodes.ASM7, access, name, descriptor, signature, value);
this(/* latest api = */ Opcodes.ASM8, access, name, descriptor, signature, value);
if (getClass() != FieldNode.class) {
throw new IllegalStateException();
}
}
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>.
* Constructs a new {@link FieldNode}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}
* or {@link Opcodes#ASM5}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param access the field's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This parameter
* also indicates if the field is synthetic and/or deprecated.
* @param name the field's name.
@ -174,15 +174,9 @@ public class FieldNode extends FieldVisitor {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationNode annotation = new AnnotationNode(descriptor);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(annotation);
visibleAnnotations = Util.add(visibleAnnotations, annotation);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(annotation);
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
}
return annotation;
}
@ -192,25 +186,16 @@ public class FieldNode extends FieldVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(typeAnnotation);
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(typeAnnotation);
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@Override
public void visitAttribute(final Attribute attribute) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attribute);
attrs = Util.add(attrs, attribute);
}
@Override

@ -183,7 +183,7 @@ public class FrameNode extends AbstractInsnNode {
FrameNode clone = new FrameNode();
clone.type = type;
if (local != null) {
clone.local = new ArrayList<Object>();
clone.local = new ArrayList<>();
for (int i = 0, n = local.size(); i < n; ++i) {
Object localElement = local.get(i);
if (localElement instanceof LabelNode) {
@ -193,7 +193,7 @@ public class FrameNode extends AbstractInsnNode {
}
}
if (stack != null) {
clone.stack = new ArrayList<Object>();
clone.stack = new ArrayList<>();
for (int i = 0, n = stack.size(); i < n; ++i) {
Object stackElement = stack.get(i);
if (stackElement instanceof LabelNode) {

@ -66,7 +66,7 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This implementation is not thread
* safe</i>.
*/
public class InsnList {
public class InsnList implements Iterable<AbstractInsnNode> {
/** The number of instructions in this list. */
private int size;
@ -182,6 +182,7 @@ public class InsnList {
*
* @return an iterator over the instructions in this list.
*/
@Override
public ListIterator<AbstractInsnNode> iterator() {
return iterator(0);
}
@ -240,7 +241,7 @@ public class InsnList {
cache[index] = newInsnNode;
newInsnNode.index = index;
} else {
newInsnNode.index = 0; // newInnsnNode now belongs to an InsnList.
newInsnNode.index = 0; // newInsnNode now belongs to an InsnList.
}
oldInsnNode.index = -1; // oldInsnNode no longer belongs to an InsnList.
oldInsnNode.previousInsn = null;
@ -565,6 +566,9 @@ public class InsnList {
@Override
public Object previous() {
if (previousInsn == null) {
throw new NoSuchElementException();
}
AbstractInsnNode result = previousInsn;
nextInsn = result;
previousInsn = result.previousInsn;

@ -114,14 +114,15 @@ public class LocalVariableAnnotationNode extends TypeAnnotationNode {
final LabelNode[] end,
final int[] index,
final String descriptor) {
this(Opcodes.ASM7, typeRef, typePath, start, end, index, descriptor);
this(/* latest api = */ Opcodes.ASM8, typeRef, typePath, start, end, index, descriptor);
}
/**
* Constructs a new {@link LocalVariableAnnotationNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
* @param start the fist instructions corresponding to the continuous ranges that make the scope
* of this local variable (inclusive).

@ -96,9 +96,7 @@ public class MethodInsnNode extends AbstractInsnNode {
* jdk.internal.org.objectweb.asm.Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @deprecated use {@link #MethodInsnNode(int, String, String, String, boolean)} instead.
*/
@Deprecated
public MethodInsnNode(
final int opcode, final String owner, final String name, final String descriptor) {
this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);

@ -186,7 +186,7 @@ public class MethodNode extends MethodVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public MethodNode() {
this(Opcodes.ASM7);
this(/* latest api = */ Opcodes.ASM8);
if (getClass() != MethodNode.class) {
throw new IllegalStateException();
}
@ -196,7 +196,8 @@ public class MethodNode extends MethodVisitor {
* Constructs an uninitialized {@link MethodNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
*/
public MethodNode(final int api) {
super(api);
@ -222,7 +223,7 @@ public class MethodNode extends MethodVisitor {
final String descriptor,
final String signature,
final String[] exceptions) {
this(Opcodes.ASM7, access, name, descriptor, signature, exceptions);
this(/* latest api = */ Opcodes.ASM8, access, name, descriptor, signature, exceptions);
if (getClass() != MethodNode.class) {
throw new IllegalStateException();
}
@ -232,7 +233,8 @@ public class MethodNode extends MethodVisitor {
* Constructs a new {@link MethodNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
* the method is synthetic and/or deprecated.
* @param name the method's name.
@ -255,9 +257,9 @@ public class MethodNode extends MethodVisitor {
this.signature = signature;
this.exceptions = Util.asArrayList(exceptions);
if ((access & Opcodes.ACC_ABSTRACT) == 0) {
this.localVariables = new ArrayList<LocalVariableNode>(5);
this.localVariables = new ArrayList<>(5);
}
this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
this.tryCatchBlocks = new ArrayList<>();
this.instructions = new InsnList();
}
@ -268,7 +270,7 @@ public class MethodNode extends MethodVisitor {
@Override
public void visitParameter(final String name, final int access) {
if (parameters == null) {
parameters = new ArrayList<ParameterNode>(5);
parameters = new ArrayList<>(5);
}
parameters.add(new ParameterNode(name, access));
}
@ -290,15 +292,9 @@ public class MethodNode extends MethodVisitor {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationNode annotation = new AnnotationNode(descriptor);
if (visible) {
if (visibleAnnotations == null) {
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(annotation);
visibleAnnotations = Util.add(visibleAnnotations, annotation);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(annotation);
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
}
return annotation;
}
@ -308,15 +304,9 @@ public class MethodNode extends MethodVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
if (visibleTypeAnnotations == null) {
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(typeAnnotation);
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(typeAnnotation);
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@ -340,29 +330,22 @@ public class MethodNode extends MethodVisitor {
int params = Type.getArgumentTypes(desc).length;
visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (visibleParameterAnnotations[parameter] == null) {
visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
}
visibleParameterAnnotations[parameter].add(annotation);
visibleParameterAnnotations[parameter] =
Util.add(visibleParameterAnnotations[parameter], annotation);
} else {
if (invisibleParameterAnnotations == null) {
int params = Type.getArgumentTypes(desc).length;
invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
}
if (invisibleParameterAnnotations[parameter] == null) {
invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
}
invisibleParameterAnnotations[parameter].add(annotation);
invisibleParameterAnnotations[parameter] =
Util.add(invisibleParameterAnnotations[parameter], annotation);
}
return annotation;
}
@Override
public void visitAttribute(final Attribute attribute) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attribute);
attrs = Util.add(attrs, attribute);
}
@Override
@ -412,33 +395,20 @@ public class MethodNode extends MethodVisitor {
instructions.add(new FieldInsnNode(opcode, owner, name, descriptor));
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor));
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
}
@ -500,15 +470,11 @@ public class MethodNode extends MethodVisitor {
// Add the annotation to this instruction.
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
if (currentInsn.visibleTypeAnnotations == null) {
currentInsn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
currentInsn.visibleTypeAnnotations.add(typeAnnotation);
currentInsn.visibleTypeAnnotations =
Util.add(currentInsn.visibleTypeAnnotations, typeAnnotation);
} else {
if (currentInsn.invisibleTypeAnnotations == null) {
currentInsn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
currentInsn.invisibleTypeAnnotations.add(typeAnnotation);
currentInsn.invisibleTypeAnnotations =
Util.add(currentInsn.invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@ -516,8 +482,9 @@ public class MethodNode extends MethodVisitor {
@Override
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
tryCatchBlocks.add(
new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type));
TryCatchBlockNode tryCatchBlock =
new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type);
tryCatchBlocks = Util.add(tryCatchBlocks, tryCatchBlock);
}
@Override
@ -526,15 +493,11 @@ public class MethodNode extends MethodVisitor {
TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
if (tryCatchBlock.visibleTypeAnnotations == null) {
tryCatchBlock.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
tryCatchBlock.visibleTypeAnnotations.add(typeAnnotation);
tryCatchBlock.visibleTypeAnnotations =
Util.add(tryCatchBlock.visibleTypeAnnotations, typeAnnotation);
} else {
if (tryCatchBlock.invisibleTypeAnnotations == null) {
tryCatchBlock.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
tryCatchBlock.invisibleTypeAnnotations.add(typeAnnotation);
tryCatchBlock.invisibleTypeAnnotations =
Util.add(tryCatchBlock.invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@ -547,9 +510,10 @@ public class MethodNode extends MethodVisitor {
final Label start,
final Label end,
final int index) {
localVariables.add(
LocalVariableNode localVariable =
new LocalVariableNode(
name, descriptor, signature, getLabelNode(start), getLabelNode(end), index));
name, descriptor, signature, getLabelNode(start), getLabelNode(end), index);
localVariables = Util.add(localVariables, localVariable);
}
@Override
@ -565,15 +529,11 @@ public class MethodNode extends MethodVisitor {
new LocalVariableAnnotationNode(
typeRef, typePath, getLabelNodes(start), getLabelNodes(end), index, descriptor);
if (visible) {
if (visibleLocalVariableAnnotations == null) {
visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
}
visibleLocalVariableAnnotations.add(localVariableAnnotation);
visibleLocalVariableAnnotations =
Util.add(visibleLocalVariableAnnotations, localVariableAnnotation);
} else {
if (invisibleLocalVariableAnnotations == null) {
invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
}
invisibleLocalVariableAnnotations.add(localVariableAnnotation);
invisibleLocalVariableAnnotations =
Util.add(invisibleLocalVariableAnnotations, localVariableAnnotation);
}
return localVariableAnnotation;
}
@ -639,7 +599,7 @@ public class MethodNode extends MethodVisitor {
* in more recent versions of the ASM API than the given version.
*
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
*/
public void check(final int api) {
if (api == Opcodes.ASM4) {
@ -694,7 +654,7 @@ public class MethodNode extends MethodVisitor {
throw new UnsupportedClassVersionException();
}
}
if (api != Opcodes.ASM7) {
if (api < Opcodes.ASM7) {
for (int i = instructions.size() - 1; i >= 0; --i) {
AbstractInsnNode insn = instructions.get(i);
if (insn instanceof LdcInsnNode) {
@ -713,8 +673,7 @@ public class MethodNode extends MethodVisitor {
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor classVisitor) {
String[] exceptionsArray = new String[this.exceptions.size()];
this.exceptions.toArray(exceptionsArray);
String[] exceptionsArray = exceptions == null ? null : exceptions.toArray(new String[0]);
MethodVisitor methodVisitor =
classVisitor.visitMethod(access, name, desc, signature, exceptionsArray);
if (methodVisitor != null) {

@ -115,7 +115,7 @@ public class ModuleNode extends ModuleVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public ModuleNode(final String name, final int access, final String version) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
if (getClass() != ModuleNode.class) {
throw new IllegalStateException();
}
@ -128,8 +128,8 @@ public class ModuleNode extends ModuleVisitor {
/**
* Constructs a {@link ModuleNode}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
* or {@link Opcodes#ASM7}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
* @param name the fully qualified name (using dots) of the module.
* @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
* ACC_MANDATED}.
@ -169,7 +169,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitPackage(final String packaze) {
if (packages == null) {
packages = new ArrayList<String>(5);
packages = new ArrayList<>(5);
}
packages.add(packaze);
}
@ -177,7 +177,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitRequire(final String module, final int access, final String version) {
if (requires == null) {
requires = new ArrayList<ModuleRequireNode>(5);
requires = new ArrayList<>(5);
}
requires.add(new ModuleRequireNode(module, access, version));
}
@ -185,7 +185,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitExport(final String packaze, final int access, final String... modules) {
if (exports == null) {
exports = new ArrayList<ModuleExportNode>(5);
exports = new ArrayList<>(5);
}
exports.add(new ModuleExportNode(packaze, access, Util.asArrayList(modules)));
}
@ -193,7 +193,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitOpen(final String packaze, final int access, final String... modules) {
if (opens == null) {
opens = new ArrayList<ModuleOpenNode>(5);
opens = new ArrayList<>(5);
}
opens.add(new ModuleOpenNode(packaze, access, Util.asArrayList(modules)));
}
@ -201,7 +201,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitUse(final String service) {
if (uses == null) {
uses = new ArrayList<String>(5);
uses = new ArrayList<>(5);
}
uses.add(service);
}
@ -209,7 +209,7 @@ public class ModuleNode extends ModuleVisitor {
@Override
public void visitProvide(final String service, final String... providers) {
if (provides == null) {
provides = new ArrayList<ModuleProvideNode>(5);
provides = new ArrayList<>(5);
}
provides.add(new ModuleProvideNode(service, Util.asArrayList(providers)));
}

@ -0,0 +1,234 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.tree;
import java.util.List;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A node that represents a record component.
*
* @author Remi Forax
*/
public class RecordComponentNode extends RecordComponentVisitor {
/** The record component name. */
public String name;
/** The record component descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String descriptor;
/** The record component signature. May be {@literal null}. */
public String signature;
/** The runtime visible annotations of this record component. May be {@literal null}. */
public List<AnnotationNode> visibleAnnotations;
/** The runtime invisible annotations of this record component. May be {@literal null}. */
public List<AnnotationNode> invisibleAnnotations;
/** The runtime visible type annotations of this record component. May be {@literal null}. */
public List<TypeAnnotationNode> visibleTypeAnnotations;
/** The runtime invisible type annotations of this record component. May be {@literal null}. */
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/** The non standard attributes of this record component. * May be {@literal null}. */
public List<Attribute> attrs;
/**
* Constructs a new {@link RecordComponentNode}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #RecordComponentNode(int, String, String, String)} version.
*
* @param name the record component name.
* @param descriptor the record component descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param signature the record component signature.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public RecordComponentNode(final String name, final String descriptor, final String signature) {
this(/* latest api = */ Opcodes.ASM8, name, descriptor, signature);
if (getClass() != RecordComponentNode.class) {
throw new IllegalStateException();
}
}
/**
* Constructs a new {@link RecordComponentNode}.
*
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
* @param name the record component name.
* @param descriptor the record component descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param signature the record component signature.
*/
public RecordComponentNode(
final int api, final String name, final String descriptor, final String signature) {
super(api);
this.name = name;
this.descriptor = descriptor;
this.signature = signature;
}
// -----------------------------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// -----------------------------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationNode annotation = new AnnotationNode(descriptor);
if (visible) {
visibleAnnotations = Util.add(visibleAnnotations, annotation);
} else {
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
}
return annotation;
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) {
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
} else {
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
}
return typeAnnotation;
}
@Override
public void visitAttribute(final Attribute attribute) {
attrs = Util.add(attrs, attribute);
}
@Override
public void visitEnd() {
// Nothing to do.
}
// -----------------------------------------------------------------------------------------------
// Accept methods
// -----------------------------------------------------------------------------------------------
/**
* Checks that this record component node is compatible with the given ASM API version. This
* method checks that this node, and all its children recursively, do not contain elements that
* were introduced in more recent versions of the ASM API than the given version.
*
* @param api an ASM API version. Must be {@link Opcodes#ASM8}.
*/
public void check(final int api) {
if (api < Opcodes.ASM8) {
throw new UnsupportedClassVersionException();
}
}
/**
* Makes the given class visitor visit this record component.
*
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor classVisitor) {
RecordComponentVisitor recordComponentVisitor =
classVisitor.visitRecordComponent(name, descriptor, signature);
if (recordComponentVisitor == null) {
return;
}
// Visit the annotations.
if (visibleAnnotations != null) {
for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = visibleAnnotations.get(i);
annotation.accept(recordComponentVisitor.visitAnnotation(annotation.desc, true));
}
}
if (invisibleAnnotations != null) {
for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = invisibleAnnotations.get(i);
annotation.accept(recordComponentVisitor.visitAnnotation(annotation.desc, false));
}
}
if (visibleTypeAnnotations != null) {
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
typeAnnotation.accept(
recordComponentVisitor.visitTypeAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
}
}
if (invisibleTypeAnnotations != null) {
for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
typeAnnotation.accept(
recordComponentVisitor.visitTypeAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
}
}
// Visit the non standard attributes.
if (attrs != null) {
for (int i = 0, n = attrs.size(); i < n; ++i) {
recordComponentVisitor.visitAttribute(attrs.get(i));
}
}
recordComponentVisitor.visitEnd();
}
}

@ -90,7 +90,7 @@ public class TypeAnnotationNode extends AnnotationNode {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) {
this(Opcodes.ASM7, typeRef, typePath, descriptor);
this(/* latest api = */ Opcodes.ASM8, typeRef, typePath, descriptor);
if (getClass() != TypeAnnotationNode.class) {
throw new IllegalStateException();
}
@ -100,7 +100,8 @@ public class TypeAnnotationNode extends AnnotationNode {
* Constructs a new {@link AnnotationNode}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets

@ -71,8 +71,14 @@ final class Util {
private Util() {}
static <T> List<T> add(final List<T> list, final T element) {
List<T> newList = list == null ? new ArrayList<>(1) : list;
newList.add(element);
return newList;
}
static <T> List<T> asArrayList(final int length) {
List<T> list = new ArrayList<T>(length);
List<T> list = new ArrayList<>(length);
for (int i = 0; i < length; ++i) {
list.add(null);
}
@ -81,9 +87,9 @@ final class Util {
static <T> List<T> asArrayList(final T[] array) {
if (array == null) {
return new ArrayList<T>();
return new ArrayList<>();
}
ArrayList<T> list = new ArrayList<T>(array.length);
ArrayList<T> list = new ArrayList<>(array.length);
for (T t : array) {
list.add(t);
}
@ -92,9 +98,9 @@ final class Util {
static List<Byte> asArrayList(final byte[] byteArray) {
if (byteArray == null) {
return new ArrayList<Byte>();
return new ArrayList<>();
}
ArrayList<Byte> byteList = new ArrayList<Byte>(byteArray.length);
ArrayList<Byte> byteList = new ArrayList<>(byteArray.length);
for (byte b : byteArray) {
byteList.add(b);
}
@ -103,9 +109,9 @@ final class Util {
static List<Boolean> asArrayList(final boolean[] booleanArray) {
if (booleanArray == null) {
return new ArrayList<Boolean>();
return new ArrayList<>();
}
ArrayList<Boolean> booleanList = new ArrayList<Boolean>(booleanArray.length);
ArrayList<Boolean> booleanList = new ArrayList<>(booleanArray.length);
for (boolean b : booleanArray) {
booleanList.add(b);
}
@ -114,9 +120,9 @@ final class Util {
static List<Short> asArrayList(final short[] shortArray) {
if (shortArray == null) {
return new ArrayList<Short>();
return new ArrayList<>();
}
ArrayList<Short> shortList = new ArrayList<Short>(shortArray.length);
ArrayList<Short> shortList = new ArrayList<>(shortArray.length);
for (short s : shortArray) {
shortList.add(s);
}
@ -125,9 +131,9 @@ final class Util {
static List<Character> asArrayList(final char[] charArray) {
if (charArray == null) {
return new ArrayList<Character>();
return new ArrayList<>();
}
ArrayList<Character> charList = new ArrayList<Character>(charArray.length);
ArrayList<Character> charList = new ArrayList<>(charArray.length);
for (char c : charArray) {
charList.add(c);
}
@ -136,9 +142,9 @@ final class Util {
static List<Integer> asArrayList(final int[] intArray) {
if (intArray == null) {
return new ArrayList<Integer>();
return new ArrayList<>();
}
ArrayList<Integer> intList = new ArrayList<Integer>(intArray.length);
ArrayList<Integer> intList = new ArrayList<>(intArray.length);
for (int i : intArray) {
intList.add(i);
}
@ -147,9 +153,9 @@ final class Util {
static List<Float> asArrayList(final float[] floatArray) {
if (floatArray == null) {
return new ArrayList<Float>();
return new ArrayList<>();
}
ArrayList<Float> floatList = new ArrayList<Float>(floatArray.length);
ArrayList<Float> floatList = new ArrayList<>(floatArray.length);
for (float f : floatArray) {
floatList.add(f);
}
@ -158,9 +164,9 @@ final class Util {
static List<Long> asArrayList(final long[] longArray) {
if (longArray == null) {
return new ArrayList<Long>();
return new ArrayList<>();
}
ArrayList<Long> longList = new ArrayList<Long>(longArray.length);
ArrayList<Long> longList = new ArrayList<>(longArray.length);
for (long l : longArray) {
longList.add(l);
}
@ -169,9 +175,9 @@ final class Util {
static List<Double> asArrayList(final double[] doubleArray) {
if (doubleArray == null) {
return new ArrayList<Double>();
return new ArrayList<>();
}
ArrayList<Double> doubleList = new ArrayList<Double>(doubleArray.length);
ArrayList<Double> doubleList = new ArrayList<>(doubleArray.length);
for (double d : doubleArray) {
doubleList.add(d);
}
@ -179,7 +185,7 @@ final class Util {
}
static <T> List<T> asArrayList(final int length, final T[] array) {
List<T> list = new ArrayList<T>(length);
List<T> list = new ArrayList<>(length);
for (int i = 0; i < length; ++i) {
list.add(array[i]); // NOPMD(UseArraysAsList): we convert a part of the array.
}

@ -155,7 +155,7 @@ public class Analyzer<V extends Value> implements Opcodes {
for (int j = startIndex; j < endIndex; ++j) {
List<TryCatchBlockNode> insnHandlers = handlers[j];
if (insnHandlers == null) {
insnHandlers = new ArrayList<TryCatchBlockNode>();
insnHandlers = new ArrayList<>();
handlers[j] = insnHandlers;
}
insnHandlers.add(tryCatchBlock);
@ -165,11 +165,11 @@ public class Analyzer<V extends Value> implements Opcodes {
// For each instruction, compute the subroutine to which it belongs.
// Follow the main 'subroutine', and collect the jsr instructions to nested subroutines.
Subroutine main = new Subroutine(null, method.maxLocals, null);
List<AbstractInsnNode> jsrInsns = new ArrayList<AbstractInsnNode>();
List<AbstractInsnNode> jsrInsns = new ArrayList<>();
findSubroutine(0, main, jsrInsns);
// Follow the nested subroutines, and collect their own nested subroutines, until all
// subroutines are found.
Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<LabelNode, Subroutine>();
Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<>();
while (!jsrInsns.isEmpty()) {
JumpInsnNode jsrInsn = (JumpInsnNode) jsrInsns.remove(0);
Subroutine subroutine = jsrSubroutines.get(jsrInsn.label);
@ -264,7 +264,7 @@ public class Analyzer<V extends Value> implements Opcodes {
}
} else if (insnOpcode == RET) {
if (subroutine == null) {
throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
throw new AnalyzerException(insnNode, "RET instruction outside of a subroutine");
}
for (int i = 0; i < subroutine.callers.size(); ++i) {
JumpInsnNode caller = subroutine.callers.get(i);
@ -344,7 +344,7 @@ public class Analyzer<V extends Value> implements Opcodes {
private void findSubroutine(
final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
throws AnalyzerException {
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<Integer>();
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<>();
instructionIndicesToProcess.add(insnIndex);
while (!instructionIndicesToProcess.isEmpty()) {
int currentInsnIndex =
@ -490,7 +490,7 @@ public class Analyzer<V extends Value> implements Opcodes {
* @return the created frame.
*/
protected Frame<V> newFrame(final int numLocals, final int numStack) {
return new Frame<V>(numLocals, numStack);
return new Frame<>(numLocals, numStack);
}
/**
@ -500,7 +500,7 @@ public class Analyzer<V extends Value> implements Opcodes {
* @return the created frame.
*/
protected Frame<V> newFrame(final Frame<? extends V> frame) {
return new Frame<V>(frame);
return new Frame<>(frame);
}
/**

@ -92,7 +92,7 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
* version.
*/
public BasicInterpreter() {
super(ASM7);
super(/* latest api = */ ASM8);
if (getClass() != BasicInterpreter.class) {
throw new IllegalStateException();
}
@ -103,7 +103,8 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
*
* @param api the ASM API version supported by this interpreter. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
*/
protected BasicInterpreter(final int api) {
super(api);

@ -78,7 +78,7 @@ public class BasicVerifier extends BasicInterpreter {
* use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
*/
public BasicVerifier() {
super(ASM7);
super(/* latest api = */ ASM8);
if (getClass() != BasicVerifier.class) {
throw new IllegalStateException();
}
@ -89,7 +89,8 @@ public class BasicVerifier extends BasicInterpreter {
*
* @param api the ASM API version supported by this interpreter. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
*/
protected BasicVerifier(final int api) {
super(api);

@ -151,7 +151,9 @@ public class Frame<V extends Value> {
* this frame corresponds to the successor of the jump instruction (i.e. the next instruction
* in the instructions sequence).
*/
public void initJumpTarget(final int opcode, final LabelNode target) {}
public void initJumpTarget(final int opcode, final LabelNode target) {
// Does nothing by default.
}
/**
* Sets the expected return type of the analyzed method.
@ -190,7 +192,7 @@ public class Frame<V extends Value> {
*/
public V getLocal(final int index) {
if (index >= numLocals) {
throw new IndexOutOfBoundsException("Trying to access an inexistant local variable");
throw new IndexOutOfBoundsException("Trying to get an inexistant local variable " + index);
}
return values[index];
}
@ -204,7 +206,7 @@ public class Frame<V extends Value> {
*/
public void setLocal(final int index, final V value) {
if (index >= numLocals) {
throw new IndexOutOfBoundsException("Trying to access an inexistant local variable " + index);
throw new IndexOutOfBoundsException("Trying to set an inexistant local variable " + index);
}
values[index] = value;
}
@ -237,7 +239,7 @@ public class Frame<V extends Value> {
* @param value the new value of the stack slot.
* @throws IndexOutOfBoundsException if the stack slot does not exist.
*/
public void setStack(final int index, final V value) throws IndexOutOfBoundsException {
public void setStack(final int index, final V value) {
values[numLocals + index] = value;
}
@ -379,23 +381,8 @@ public class Frame<V extends Value> {
break;
case Opcodes.DUP_X2:
value1 = pop();
if (value1.getSize() == 1) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
if (value1.getSize() == 1 && executeDupX2(insn, value1, interpreter)) {
break;
}
throw new AnalyzerException(insn, "Illegal use of DUP_X2");
case Opcodes.DUP2:
@ -466,23 +453,8 @@ public class Frame<V extends Value> {
break;
}
}
} else {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break;
}
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
} else if (executeDupX2(insn, value1, interpreter)) {
break;
}
throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
case Opcodes.SWAP:
@ -629,36 +601,11 @@ public class Frame<V extends Value> {
case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE:
{
List<V> valueList = new ArrayList<V>();
String methodDescriptor = ((MethodInsnNode) insn).desc;
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
valueList.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
valueList.add(0, pop());
}
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, valueList);
} else {
push(interpreter.naryOperation(insn, valueList));
}
break;
}
executeInvokeInsn(insn, ((MethodInsnNode) insn).desc, interpreter);
break;
case Opcodes.INVOKEDYNAMIC:
{
List<V> valueList = new ArrayList<V>();
String methodDesccriptor = ((InvokeDynamicInsnNode) insn).desc;
for (int i = Type.getArgumentTypes(methodDesccriptor).length; i > 0; --i) {
valueList.add(0, pop());
}
if (Type.getReturnType(methodDesccriptor) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, valueList);
} else {
push(interpreter.naryOperation(insn, valueList));
}
break;
}
executeInvokeInsn(insn, ((InvokeDynamicInsnNode) insn).desc, interpreter);
break;
case Opcodes.NEW:
push(interpreter.newOperation(insn));
break;
@ -679,7 +626,7 @@ public class Frame<V extends Value> {
interpreter.unaryOperation(insn, pop());
break;
case Opcodes.MULTIANEWARRAY:
List<V> valueList = new ArrayList<V>();
List<V> valueList = new ArrayList<>();
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
valueList.add(0, pop());
}
@ -694,6 +641,45 @@ public class Frame<V extends Value> {
}
}
private boolean executeDupX2(
final AbstractInsnNode insn, final V value1, final Interpreter<V> interpreter)
throws AnalyzerException {
V value2 = pop();
if (value2.getSize() == 1) {
V value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
return true;
}
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
return true;
}
return false;
}
private void executeInvokeInsn(
final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter)
throws AnalyzerException {
ArrayList<V> valueList = new ArrayList<>();
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
valueList.add(0, pop());
}
if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) {
valueList.add(0, pop());
}
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
interpreter.naryOperation(insn, valueList);
} else {
push(interpreter.naryOperation(insn, valueList));
}
}
/**
* Merges the given frame into this frame.
*

@ -124,7 +124,12 @@ public class SimpleVerifier extends BasicVerifier {
final Type currentSuperClass,
final List<Type> currentClassInterfaces,
final boolean isInterface) {
this(ASM7, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
this(
/* latest api = */ ASM8,
currentClass,
currentSuperClass,
currentClassInterfaces,
isInterface);
if (getClass() != SimpleVerifier.class) {
throw new IllegalStateException();
}
@ -136,7 +141,8 @@ public class SimpleVerifier extends BasicVerifier {
*
* @param api the ASM API version supported by this verifier. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
* @param currentClass the type of the class to be verified.
* @param currentSuperClass the type of the super class of the class to be verified.
* @param currentClassInterfaces the types of the interfaces directly implemented by the class to
@ -285,7 +291,7 @@ public class SimpleVerifier extends BasicVerifier {
type1 = type1.getElementType();
type2 = type2.getElementType();
}
do {
while (true) {
if (type1 == null || isInterface(type1)) {
return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
}
@ -293,7 +299,7 @@ public class SimpleVerifier extends BasicVerifier {
if (isAssignableFrom(type1, type2)) {
return newArrayValue(type1, numDimensions);
}
} while (true);
}
}
return BasicValue.UNINITIALIZED_VALUE;
}

@ -118,12 +118,18 @@ final class SmallSet<T> extends AbstractSet<T> {
@Override
public Iterator<T> iterator() {
return new IteratorImpl<T>(element1, element2);
return new IteratorImpl<>(element1, element2);
}
@Override
public int size() {
return element1 == null ? 0 : (element2 == null ? 1 : 2);
if (element1 == null) {
return 0;
} else if (element2 == null) {
return 1;
} else {
return 2;
}
}
// -----------------------------------------------------------------------------------------------
@ -155,7 +161,7 @@ final class SmallSet<T> extends AbstractSet<T> {
if (otherSet.element2 == null) {
// If this set also contains exactly one element, we have two distinct elements.
if (element2 == null) {
return new SmallSet<T>(element1, otherSet.element1);
return new SmallSet<>(element1, otherSet.element1);
}
// If otherSet is included in this set, return this set.
if (otherSet.element1 == element1 || otherSet.element1 == element2) {
@ -170,7 +176,7 @@ final class SmallSet<T> extends AbstractSet<T> {
// At this point we know that there are at least 3 distinct elements, so we need a generic set
// to store the result.
HashSet<T> result = new HashSet<T>(4);
HashSet<T> result = new HashSet<>(4);
result.add(element1);
if (element2 != null) {
result.add(element2);

@ -82,7 +82,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
* version.
*/
public SourceInterpreter() {
super(ASM7);
super(/* latest api = */ ASM8);
if (getClass() != SourceInterpreter.class) {
throw new IllegalStateException();
}
@ -93,7 +93,8 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
*
* @param api the ASM API version supported by this interpreter. Must be one of {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
*/
protected SourceInterpreter(final int api) {
super(api);
@ -235,7 +236,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
}
}
if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) {
HashSet<AbstractInsnNode> setUnion = new HashSet<AbstractInsnNode>();
HashSet<AbstractInsnNode> setUnion = new HashSet<>();
setUnion.addAll(value1.insns);
setUnion.addAll(value2.insns);
return new SourceValue(Math.min(value1.size, value2.size), setUnion);

@ -108,7 +108,7 @@ public class SourceValue implements Value {
*/
public SourceValue(final int size, final AbstractInsnNode insnNode) {
this.size = size;
this.insns = new SmallSet<AbstractInsnNode>(insnNode);
this.insns = new SmallSet<>(insnNode);
}
/**

@ -92,7 +92,7 @@ final class Subroutine {
Subroutine(final LabelNode start, final int maxLocals, final JumpInsnNode caller) {
this.start = start;
this.localsUsed = new boolean[maxLocals];
this.callers = new ArrayList<JumpInsnNode>();
this.callers = new ArrayList<>();
callers.add(caller);
}
@ -103,9 +103,8 @@ final class Subroutine {
*/
Subroutine(final Subroutine subroutine) {
this.start = subroutine.start;
this.localsUsed = new boolean[subroutine.localsUsed.length];
this.callers = new ArrayList<JumpInsnNode>(subroutine.callers);
System.arraycopy(subroutine.localsUsed, 0, this.localsUsed, 0, subroutine.localsUsed.length);
this.localsUsed = subroutine.localsUsed.clone();
this.callers = new ArrayList<>(subroutine.callers);
}
/**

@ -59,8 +59,11 @@
package jdk.internal.org.objectweb.asm.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ConstantDynamic;
@ -78,6 +81,11 @@ import jdk.internal.org.objectweb.asm.TypePath;
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public class ASMifier extends Printer {
/** The help message shown when command line arguments are incorrect. */
private static final String USAGE =
"Prints the ASM code to generate the given class.\n"
+ "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
/** A pseudo access flag used to distinguish class access flags. */
private static final int ACCESS_CLASS = 0x40000;
@ -92,15 +100,27 @@ public class ASMifier extends Printer {
private static final String ANNOTATION_VISITOR = "annotationVisitor";
private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
private static final String COMMA = "\", \"";
private static final String END_ARRAY = " });\n";
private static final String END_PARAMETERS = ");\n\n";
private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
private static final String VISIT_END = ".visitEnd();\n";
private static final List<String> FRAME_TYPES =
Collections.unmodifiableList(
Arrays.asList(
"Opcodes.TOP",
"Opcodes.INTEGER",
"Opcodes.FLOAT",
"Opcodes.DOUBLE",
"Opcodes.LONG",
"Opcodes.NULL",
"Opcodes.UNINITIALIZED_THIS"));
private static final Map<Integer, String> CLASS_VERSIONS;
static {
HashMap<Integer, String> classVersions = new HashMap<Integer, String>();
HashMap<Integer, String> classVersions = new HashMap<>();
classVersions.put(Opcodes.V1_1, "V1_1");
classVersions.put(Opcodes.V1_2, "V1_2");
classVersions.put(Opcodes.V1_3, "V1_3");
@ -113,6 +133,9 @@ public class ASMifier extends Printer {
classVersions.put(Opcodes.V10, "V10");
classVersions.put(Opcodes.V11, "V11");
classVersions.put(Opcodes.V12, "V12");
classVersions.put(Opcodes.V13, "V13");
classVersions.put(Opcodes.V14, "V14");
classVersions.put(Opcodes.V15, "V15");
CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
}
@ -132,7 +155,7 @@ public class ASMifier extends Printer {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public ASMifier() {
this(Opcodes.ASM7, "classWriter", 0);
this(/* latest api = */ Opcodes.ASM8, "classWriter", 0);
if (getClass() != ASMifier.class) {
throw new IllegalStateException();
}
@ -142,7 +165,7 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}.
*
* @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
* @param visitorVariableName the name of the visitor variable in the produced code.
* @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
*/
@ -162,10 +185,22 @@ public class ASMifier extends Printer {
* @throws IOException if the class cannot be found, or if an IOException occurs.
*/
public static void main(final String[] args) throws IOException {
String usage =
"Prints the ASM code to generate the given class.\n"
+ "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
main(usage, new ASMifier(), args);
main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
}
/**
* Prints the ASM source code to generate the given class to the given output.
*
* <p>Usage: ASMifier [-debug] &lt;binary class name or class file name&gt;
*
* @param args the command line arguments.
* @param output where to print the result.
* @param logger where to log errors.
* @throws IOException if the class cannot be found, or if an IOException occurs.
*/
static void main(final String[] args, final PrintWriter output, final PrintWriter logger)
throws IOException {
main(args, USAGE, new ASMifier(), output, logger);
}
// -----------------------------------------------------------------------------------------------
@ -189,7 +224,7 @@ public class ASMifier extends Printer {
simpleName = name;
} else {
text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
simpleName = name.substring(lastSlashIndex + 1).replace('-', '_');
simpleName = name.substring(lastSlashIndex + 1).replaceAll("[-\\(\\)]", "_");
}
}
text.add("import jdk.internal.org.objectweb.asm.AnnotationVisitor;\n");
@ -202,12 +237,14 @@ public class ASMifier extends Printer {
text.add("import jdk.internal.org.objectweb.asm.Label;\n");
text.add("import jdk.internal.org.objectweb.asm.MethodVisitor;\n");
text.add("import jdk.internal.org.objectweb.asm.Opcodes;\n");
text.add("import jdk.internal.org.objectweb.asm.RecordComponentVisitor;\n");
text.add("import jdk.internal.org.objectweb.asm.Type;\n");
text.add("import jdk.internal.org.objectweb.asm.TypePath;\n");
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
text.add("public static byte[] dump () throws Exception {\n\n");
text.add("ClassWriter classWriter = new ClassWriter(0);\n");
text.add("FieldVisitor fieldVisitor;\n");
text.add("RecordComponentVisitor recordComponentVisitor;\n");
text.add("MethodVisitor methodVisitor;\n");
text.add("AnnotationVisitor annotationVisitor0;\n\n");
@ -275,7 +312,7 @@ public class ASMifier extends Printer {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestHost(");
appendConstant(nestHost);
stringBuilder.append(");\n\n");
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@ -313,7 +350,23 @@ public class ASMifier extends Printer {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestMember(");
appendConstant(nestMember);
stringBuilder.append(");\n\n");
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitPermittedSubtypeExperimental(");
appendConstant(permittedSubtype);
stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString());
}
@ -333,6 +386,25 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString());
}
@Override
public ASMifier visitRecordComponent(
final String name, final String descriptor, final String signature) {
stringBuilder.setLength(0);
stringBuilder.append("{\n");
stringBuilder.append("recordComponentVisitor = classWriter.visitRecordComponent(");
appendConstant(name);
stringBuilder.append(", ");
appendConstant(descriptor);
stringBuilder.append(", ");
appendConstant(signature);
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
ASMifier asmifier = createASMifier("recordComponentVisitor", 0);
text.add(asmifier.getText());
text.add("}\n");
return asmifier;
}
@Override
public ASMifier visitField(
final int access,
@ -441,27 +513,18 @@ public class ASMifier extends Printer {
@Override
public void visitExport(final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitExport(");
appendConstant(packaze);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE);
if (modules != null && modules.length > 0) {
stringBuilder.append(", new String[] {");
for (int i = 0; i < modules.length; ++i) {
stringBuilder.append(i == 0 ? " " : ", ");
appendConstant(modules[i]);
}
stringBuilder.append(" }");
}
stringBuilder.append(");\n");
text.add(stringBuilder.toString());
visitExportOrOpen("moduleVisitor.visitExport(", packaze, access, modules);
}
@Override
public void visitOpen(final String packaze, final int access, final String... modules) {
visitExportOrOpen("moduleVisitor.visitOpen(", packaze, access, modules);
}
private void visitExportOrOpen(
final String visitMethod, final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append("moduleVisitor.visitOpen(");
stringBuilder.append(visitMethod);
appendConstant(packaze);
stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE);
@ -579,6 +642,33 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString());
}
// -----------------------------------------------------------------------------------------------
// Record components
// -----------------------------------------------------------------------------------------------
@Override
public ASMifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
return visitAnnotation(descriptor, visible);
}
@Override
public ASMifier visitRecordComponentTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
@Override
public void visitRecordComponentAttribute(final Attribute attribute) {
visitAttribute(attribute);
}
@Override
public void visitRecordComponentEnd() {
stringBuilder.setLength(0);
stringBuilder.append(name).append(VISIT_END);
text.add(stringBuilder.toString());
}
// -----------------------------------------------------------------------------------------------
// Fields
// -----------------------------------------------------------------------------------------------
@ -805,37 +895,8 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString());
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
@ -1205,14 +1266,12 @@ public class ASMifier extends Printer {
public void visitAttribute(final Attribute attribute) {
stringBuilder.setLength(0);
stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
if (attribute instanceof ASMifiable) {
if (attribute instanceof ASMifierSupport) {
if (labelNames == null) {
labelNames = new HashMap<Label, String>();
labelNames = new HashMap<>();
}
stringBuilder.append("{\n");
StringBuffer stringBuffer = new StringBuffer();
((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
stringBuilder.append(stringBuffer.toString());
((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames);
stringBuilder.append(name).append(".visitAttribute(attribute);\n");
stringBuilder.append("}\n");
}
@ -1233,7 +1292,7 @@ public class ASMifier extends Printer {
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected ASMifier createASMifier(
final String visitorVariableName, final int annotationVisitorId) {
return new ASMifier(Opcodes.ASM7, visitorVariableName, annotationVisitorId);
return new ASMifier(api, visitorVariableName, annotationVisitorId);
}
/**
@ -1379,6 +1438,13 @@ public class ASMifier extends Printer {
stringBuilder.append("ACC_DEPRECATED");
isEmpty = false;
}
if ((accessFlags & Opcodes.ACC_RECORD) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
}
stringBuilder.append("ACC_RECORD");
isEmpty = false;
}
if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
if (!isEmpty) {
stringBuilder.append(" | ");
@ -1415,17 +1481,17 @@ public class ASMifier extends Printer {
stringBuilder.append("new Handle(");
Handle handle = (Handle) value;
stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
stringBuilder.append(handle.getOwner()).append("\", \"");
stringBuilder.append(handle.getName()).append("\", \"");
stringBuilder.append(handle.getOwner()).append(COMMA);
stringBuilder.append(handle.getName()).append(COMMA);
stringBuilder.append(handle.getDesc()).append("\", ");
stringBuilder.append(handle.isInterface()).append(")");
} else if (value instanceof ConstantDynamic) {
stringBuilder.append("new ConstantDynamic(\"");
ConstantDynamic constantDynamic = (ConstantDynamic) value;
stringBuilder.append(constantDynamic.getName()).append("\", \"");
stringBuilder.append(constantDynamic.getName()).append(COMMA);
stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
appendConstant(constantDynamic.getBootstrapMethod());
stringBuilder.append(", new Object[] {");
stringBuilder.append(NEW_OBJECT_ARRAY);
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
appendConstant(constantDynamic.getBootstrapMethodArgument(i));
@ -1542,31 +1608,7 @@ public class ASMifier extends Printer {
if (frameTypes[i] instanceof String) {
appendConstant(frameTypes[i]);
} else if (frameTypes[i] instanceof Integer) {
switch (((Integer) frameTypes[i]).intValue()) {
case 0:
stringBuilder.append("Opcodes.TOP");
break;
case 1:
stringBuilder.append("Opcodes.INTEGER");
break;
case 2:
stringBuilder.append("Opcodes.FLOAT");
break;
case 3:
stringBuilder.append("Opcodes.DOUBLE");
break;
case 4:
stringBuilder.append("Opcodes.LONG");
break;
case 5:
stringBuilder.append("Opcodes.NULL");
break;
case 6:
stringBuilder.append("Opcodes.UNINITIALIZED_THIS");
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue()));
} else {
appendLabel((Label) frameTypes[i]);
}
@ -1582,7 +1624,7 @@ public class ASMifier extends Printer {
*/
protected void declareLabel(final Label label) {
if (labelNames == null) {
labelNames = new HashMap<Label, String>();
labelNames = new HashMap<>();
}
String labelName = labelNames.get(label);
if (labelName == null) {

@ -0,0 +1,82 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.util;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Label;
/**
* An {@link jdk.internal.org.objectweb.asm.Attribute} that can generate the ASM code to create an equivalent
* attribute.
*
* @author Eugene Kuleshov
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public interface ASMifierSupport {
/**
* Generates the ASM code to create an attribute equal to this attribute.
*
* @param outputBuilder where the generated code must be appended.
* @param visitorVariableName the name of the visitor variable in the produced code.
* @param labelNames the names of the labels in the generated code.
*/
void asmify(
StringBuilder outputBuilder, String visitorVariableName, Map<Label, String> labelNames);
}

@ -83,7 +83,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
}
CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues) {
super(Opcodes.ASM7, annotationVisitor);
super(/* latest api = */ Opcodes.ASM8, annotationVisitor);
this.useNamedValue = useNamedValues;
}

@ -75,6 +75,7 @@ import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
@ -140,6 +141,11 @@ import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier;
*/
public class CheckClassAdapter extends ClassVisitor {
/** The help message shown when command line arguments are incorrect. */
private static final String USAGE =
"Verifies the given class.\n"
+ "Usage: CheckClassAdapter <fully qualified class name or class file name>";
private static final String ERROR_AT = ": error at index ";
/** Whether the bytecode must be checked with a BasicVerifier. */
@ -199,7 +205,7 @@ public class CheckClassAdapter extends ClassVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
this(Opcodes.ASM7, classVisitor, checkDataFlow);
this(/* latest api = */ Opcodes.ASM8, classVisitor, checkDataFlow);
if (getClass() != CheckClassAdapter.class) {
throw new IllegalStateException();
}
@ -209,7 +215,8 @@ public class CheckClassAdapter extends ClassVisitor {
* Constructs a new {@link CheckClassAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param classVisitor the class visitor to which this adapter must delegate calls.
* @param checkDataFlow {@literal true} to perform basic data flow checks, or {@literal false} to
* not perform any data flow check (see {@link CheckMethodAdapter}). This option requires
@ -218,7 +225,7 @@ public class CheckClassAdapter extends ClassVisitor {
protected CheckClassAdapter(
final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
super(api, classVisitor);
this.labelInsnIndices = new HashMap<Label, Integer>();
this.labelInsnIndices = new HashMap<>();
this.checkDataFlow = checkDataFlow;
}
@ -250,6 +257,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_ANNOTATION
| Opcodes.ACC_ENUM
| Opcodes.ACC_DEPRECATED
| Opcodes.ACC_RECORD
| Opcodes.ACC_MODULE);
if (name == null) {
throw new IllegalArgumentException("Illegal class name (null)");
@ -345,6 +353,20 @@ public class CheckClassAdapter extends ClassVisitor {
super.visitNestMember(nestMember);
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
checkState();
CheckMethodAdapter.checkInternalName(version, permittedSubtype, "permittedSubtype");
super.visitPermittedSubtypeExperimental(permittedSubtype);
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
checkState();
@ -393,6 +415,19 @@ public class CheckClassAdapter extends ClassVisitor {
super.visitInnerClass(name, outerName, innerName, access);
}
@Override
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
checkState();
CheckMethodAdapter.checkUnqualifiedName(version, name, "record component name");
CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
if (signature != null) {
checkFieldSignature(signature);
}
return new CheckRecordComponentAdapter(
api, super.visitRecordComponent(name, descriptor, signature));
}
@Override
public FieldVisitor visitField(
final int access,
@ -412,6 +447,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_TRANSIENT
| Opcodes.ACC_SYNTHETIC
| Opcodes.ACC_ENUM
| Opcodes.ACC_MANDATED
| Opcodes.ACC_DEPRECATED);
CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
@ -446,6 +482,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_ABSTRACT
| Opcodes.ACC_STRICT
| Opcodes.ACC_SYNTHETIC
| Opcodes.ACC_MANDATED
| Opcodes.ACC_DEPRECATED);
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
@ -979,10 +1016,19 @@ public class CheckClassAdapter extends ClassVisitor {
* @throws IOException if the class cannot be found, or if an IO exception occurs.
*/
public static void main(final String[] args) throws IOException {
main(args, new PrintWriter(System.err, true));
}
/**
* Checks the given class.
*
* @param args the command line arguments.
* @param logger where to log errors.
* @throws IOException if the class cannot be found, or if an IO exception occurs.
*/
static void main(final String[] args, final PrintWriter logger) throws IOException {
if (args.length != 1) {
System.err.println(
"Verifies the given class.\n"
+ "Usage: CheckClassAdapter <fully qualified class name or class file name>");
logger.println(USAGE);
return;
}
@ -995,7 +1041,7 @@ public class CheckClassAdapter extends ClassVisitor {
classReader = new ClassReader(args[0]);
}
verify(classReader, false, new PrintWriter(System.err));
verify(classReader, false, logger);
}
/**
@ -1019,6 +1065,7 @@ public class CheckClassAdapter extends ClassVisitor {
* @param printResults whether to print the results of the bytecode verification.
* @param printWriter where the results (or the stack trace in case of error) must be printed.
*/
@SuppressWarnings("deprecation")
public static void verify(
final ClassReader classReader,
final ClassLoader loader,
@ -1026,12 +1073,13 @@ public class CheckClassAdapter extends ClassVisitor {
final PrintWriter printWriter) {
ClassNode classNode = new ClassNode();
classReader.accept(
new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
new CheckClassAdapter(Opcodes.ASM9_EXPERIMENTAL, classNode, false) {},
ClassReader.SKIP_DEBUG);
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<Type>();
List<Type> interfaces = new ArrayList<>();
for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName));
}
@ -1043,7 +1091,7 @@ public class CheckClassAdapter extends ClassVisitor {
syperType,
interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
Analyzer<BasicValue> analyzer = new Analyzer<>(verifier);
if (loader != null) {
verifier.setClassLoader(loader);
}

@ -83,7 +83,7 @@ public class CheckFieldAdapter extends FieldVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public CheckFieldAdapter(final FieldVisitor fieldVisitor) {
this(Opcodes.ASM7, fieldVisitor);
this(/* latest api = */ Opcodes.ASM8, fieldVisitor);
if (getClass() != CheckFieldAdapter.class) {
throw new IllegalStateException();
}
@ -93,7 +93,8 @@ public class CheckFieldAdapter extends FieldVisitor {
* Constructs a new {@link CheckFieldAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param fieldVisitor the field visitor to which this adapter must delegate calls.
*/
protected CheckFieldAdapter(final int api, final FieldVisitor fieldVisitor) {

@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.util;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -397,7 +398,7 @@ public class CheckMethodAdapter extends MethodVisitor {
*/
public CheckMethodAdapter(
final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
this(/* latest api = */ Opcodes.ASM8, methodVisitor, labelInsnIndices);
if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException();
}
@ -408,7 +409,8 @@ public class CheckMethodAdapter extends MethodVisitor {
* data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
*
* @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param methodVisitor the method visitor to which this adapter must delegate calls.
* @param labelInsnIndices the index of the instruction designated by each visited label so far
* (in other methods). This map is updated with the labels from the visited method.
@ -419,8 +421,8 @@ public class CheckMethodAdapter extends MethodVisitor {
final Map<Label, Integer> labelInsnIndices) {
super(api, methodVisitor);
this.labelInsnIndices = labelInsnIndices;
this.referencedLabels = new HashSet<Label>();
this.handlers = new ArrayList<Label>();
this.referencedLabels = new HashSet<>();
this.handlers = new ArrayList<>();
}
/**
@ -443,7 +445,8 @@ public class CheckMethodAdapter extends MethodVisitor {
final String descriptor,
final MethodVisitor methodVisitor,
final Map<Label, Integer> labelInsnIndices) {
this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
this(
/* latest api = */ Opcodes.ASM8, access, name, descriptor, methodVisitor, labelInsnIndices);
if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException();
}
@ -455,7 +458,8 @@ public class CheckMethodAdapter extends MethodVisitor {
* instruction IRETURN, or the invalid sequence IADD L2I will be detected.
*
* @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param access the method's access flags.
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
@ -475,7 +479,7 @@ public class CheckMethodAdapter extends MethodVisitor {
new MethodNode(api, access, name, descriptor, null, null) {
@Override
public void visitEnd() {
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
Analyzer<BasicValue> analyzer = new Analyzer<>(new BasicVerifier());
try {
analyzer.analyze("dummy", this);
} catch (IndexOutOfBoundsException e) {
@ -488,7 +492,9 @@ public class CheckMethodAdapter extends MethodVisitor {
} catch (AnalyzerException e) {
throwError(analyzer, e);
}
accept(methodVisitor);
if (methodVisitor != null) {
accept(methodVisitor);
}
}
private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
@ -735,42 +741,20 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount;
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final int opcodeAndSource,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
// Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
checkVisitCodeCalled();
checkVisitMaxsNotCalled();
checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
@ -789,13 +773,7 @@ public class CheckMethodAdapter extends MethodVisitor {
throw new IllegalArgumentException(
"INVOKESPECIAL can't be used with interfaces prior to Java 8");
}
// Calling super.visitMethodInsn requires to call the correct version depending on this.api
// (otherwise infinite loops can occur). To simplify and to make it easier to automatically
// remove the backward compatibility code, we inline the code of the overridden method here.
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
++insnCount;
}
@ -879,9 +857,7 @@ public class CheckMethodAdapter extends MethodVisitor {
checkLabel(labels[i], false, "label at index " + i);
}
super.visitTableSwitchInsn(min, max, dflt, labels);
for (Label label : labels) {
referencedLabels.add(label);
}
Collections.addAll(referencedLabels, labels);
++insnCount;
}
@ -898,9 +874,7 @@ public class CheckMethodAdapter extends MethodVisitor {
}
super.visitLookupSwitchInsn(dflt, keys, labels);
referencedLabels.add(dflt);
for (Label label : labels) {
referencedLabels.add(label);
}
Collections.addAll(referencedLabels, labels);
++insnCount;
}
@ -997,6 +971,9 @@ public class CheckMethodAdapter extends MethodVisitor {
checkVisitMaxsNotCalled();
checkUnqualifiedName(version, name, "name");
checkDescriptor(version, descriptor, false);
if (signature != null) {
CheckClassAdapter.checkFieldSignature(signature);
}
checkLabel(start, true, START_LABEL);
checkLabel(end, true, END_LABEL);
checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
@ -1130,7 +1107,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|| value == Opcodes.NULL
|| value == Opcodes.UNINITIALIZED_THIS) {
return;
} else if (value instanceof String) {
}
if (value instanceof String) {
checkInternalName(version, (String) value, "Invalid stack frame value");
} else if (value instanceof Label) {
referencedLabels.add((Label) value);
@ -1314,7 +1292,7 @@ public class CheckMethodAdapter extends MethodVisitor {
* @param message the message to use in case of error.
*/
static void checkMethodIdentifier(final int version, final String name, final String message) {
if (name == null || name.isEmpty()) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
}
if ((version & 0xFFFF) >= Opcodes.V1_5) {
@ -1347,7 +1325,7 @@ public class CheckMethodAdapter extends MethodVisitor {
* @param message the message to use in case of error.
*/
static void checkInternalName(final int version, final String name, final String message) {
if (name == null || name.isEmpty()) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
}
if (name.charAt(0) == '[') {
@ -1370,10 +1348,10 @@ public class CheckMethodAdapter extends MethodVisitor {
int startIndex = 0;
int slashIndex;
while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
CheckMethodAdapter.checkIdentifier(version, name, startIndex, slashIndex, null);
checkIdentifier(version, name, startIndex, slashIndex, null);
startIndex = slashIndex + 1;
}
CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
checkIdentifier(version, name, startIndex, name.length(), null);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException(
INVALID + message + " (must be an internal class name): " + name, e);
@ -1457,7 +1435,7 @@ public class CheckMethodAdapter extends MethodVisitor {
* @param descriptor the string to be checked.
*/
static void checkMethodDescriptor(final int version, final String descriptor) {
if (descriptor == null || descriptor.isEmpty()) {
if (descriptor == null || descriptor.length() == 0) {
throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
}
if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {

@ -102,7 +102,7 @@ public class CheckModuleAdapter extends ModuleVisitor {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
this(Opcodes.ASM7, moduleVisitor, isOpen);
this(/* latest api = */ Opcodes.ASM8, moduleVisitor, isOpen);
if (getClass() != CheckModuleAdapter.class) {
throw new IllegalStateException();
}
@ -112,7 +112,8 @@ public class CheckModuleAdapter extends ModuleVisitor {
* Constructs a new {@link CheckModuleAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param moduleVisitor the module visitor to which this adapter must delegate calls.
* @param isOpen whether the visited module is open. Open modules have their {@link
* Opcodes#ACC_OPEN} access flag set in {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitModule}.
@ -231,12 +232,12 @@ public class CheckModuleAdapter extends ModuleVisitor {
NameSet(final String type) {
this.type = type;
this.names = new HashSet<String>();
this.names = new HashSet<>();
}
void checkNameNotAlreadyDeclared(final String name) {
if (!names.add(name)) {
throw new IllegalArgumentException(type + " " + name + " already declared");
throw new IllegalArgumentException(type + " '" + name + "' already declared");
}
}
}

@ -0,0 +1,151 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.util;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/**
* A {@link RecordComponentVisitor} that checks that its methods are properly used.
*
* @author Eric Bruneton
* @author Remi Forax
*/
public class CheckRecordComponentAdapter extends RecordComponentVisitor {
/** Whether the {@link #visitEnd()} method has been called. */
private boolean visitEndCalled;
/**
* Constructs a new {@link CheckRecordComponentAdapter}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #CheckRecordComponentAdapter(int,
* RecordComponentVisitor)} version.
*
* @param recordComponentVisitor the record component visitor to which this adapter must delegate
* calls.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public CheckRecordComponentAdapter(final RecordComponentVisitor recordComponentVisitor) {
this(/* latest api =*/ Opcodes.ASM8, recordComponentVisitor);
if (getClass() != CheckRecordComponentAdapter.class) {
throw new IllegalStateException();
}
}
/**
* Constructs a new {@link CheckRecordComponentAdapter}.
*
* @param api the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM8}.
* @param recordComponentVisitor the record component visitor to which this adapter must delegate
* calls.
*/
protected CheckRecordComponentAdapter(
final int api, final RecordComponentVisitor recordComponentVisitor) {
super(api, recordComponentVisitor);
}
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
checkVisitEndNotCalled();
// Annotations can only appear in V1_5 or more classes.
CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
return new CheckAnnotationAdapter(super.visitAnnotation(descriptor, visible));
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
checkVisitEndNotCalled();
int sort = new TypeReference(typeRef).getSort();
if (sort != TypeReference.FIELD) {
throw new IllegalArgumentException(
"Invalid type reference sort 0x" + Integer.toHexString(sort));
}
CheckClassAdapter.checkTypeRef(typeRef);
CheckMethodAdapter.checkDescriptor(Opcodes.V1_5, descriptor, false);
return new CheckAnnotationAdapter(
super.visitTypeAnnotation(typeRef, typePath, descriptor, visible));
}
@Override
public void visitAttribute(final Attribute attribute) {
checkVisitEndNotCalled();
if (attribute == null) {
throw new IllegalArgumentException("Invalid attribute (must not be null)");
}
super.visitAttribute(attribute);
}
@Override
public void visitEnd() {
checkVisitEndNotCalled();
visitEndCalled = true;
super.visitEnd();
}
private void checkVisitEndNotCalled() {
if (visitEndCalled) {
throw new IllegalStateException("Cannot call a visit method after visitEnd has been called");
}
}
}

@ -154,14 +154,15 @@ public class CheckSignatureAdapter extends SignatureVisitor {
* null}.
*/
public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
this(Opcodes.ASM7, type, signatureVisitor);
this(/* latest api = */ Opcodes.ASM8, type, signatureVisitor);
}
/**
* Constructs a new {@link CheckSignatureAdapter}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
* #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
* @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
@ -202,7 +203,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
@Override
public SignatureVisitor visitInterfaceBound() {
if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
throw new IllegalArgumentException();
throw new IllegalStateException();
}
return new CheckSignatureAdapter(
TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
@ -213,7 +214,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
@Override
public SignatureVisitor visitSuperclass() {
if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
throw new IllegalArgumentException();
throw new IllegalStateException();
}
state = State.SUPER;
return new CheckSignatureAdapter(
@ -234,7 +235,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
@Override
public SignatureVisitor visitParameterType() {
if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
throw new IllegalArgumentException();
throw new IllegalStateException();
}
state = State.PARAM;
return new CheckSignatureAdapter(
@ -244,7 +245,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
@Override
public SignatureVisitor visitReturnType() {
if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
throw new IllegalArgumentException();
throw new IllegalStateException();
}
state = State.RETURN;
CheckSignatureAdapter checkSignatureAdapter =
@ -272,11 +273,11 @@ public class CheckSignatureAdapter extends SignatureVisitor {
}
if (descriptor == 'V') {
if (!canBeVoid) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Base type descriptor can't be V");
}
} else {
if ("ZCBSIFJD".indexOf(descriptor) == -1) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Base type descriptor must be one of ZCBSIFJD");
}
}
state = State.SIMPLE_TYPE;
@ -346,7 +347,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
throw new IllegalStateException();
}
if ("+-=".indexOf(wildcard) == -1) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("Wildcard must be one of +-=");
}
return new CheckSignatureAdapter(
TYPE_SIGNATURE,
@ -365,7 +366,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
}
private void checkClassName(final String name, final String message) {
if (name == null || name.isEmpty()) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
}
for (int i = 0; i < name.length(); ++i) {
@ -377,7 +378,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
}
private void checkIdentifier(final String name, final String message) {
if (name == null || name.isEmpty()) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
}
for (int i = 0; i < name.length(); ++i) {

@ -72,6 +72,7 @@ import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/**
* An abstract converter from visit events to text.
@ -326,13 +327,6 @@ public abstract class Printer {
*/
protected final int api;
/**
* A buffer that can be used to create strings.
*
* @deprecated use {@link #stringBuilder} instead.
*/
@Deprecated protected final StringBuffer buf;
/** The builder used to build strings in the various visit methods. */
protected final StringBuilder stringBuilder;
@ -360,9 +354,8 @@ public abstract class Printer {
*/
protected Printer(final int api) {
this.api = api;
this.buf = null;
this.stringBuilder = new StringBuilder();
this.text = new ArrayList<Object>();
this.text = new ArrayList<>();
}
// -----------------------------------------------------------------------------------------------
@ -491,6 +484,22 @@ public abstract class Printer {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>.
*
* <p>Visits a permitted subtypes. A permitted subtypes is one of the allowed subtypes of the
* current class. See {@link
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubtypeExperimental(String)}.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Class inner name. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}.
*
@ -505,6 +514,22 @@ public abstract class Printer {
*/
public abstract void visitInnerClass(String name, String outerName, String innerName, int access);
/**
* Visits a record component of the class. See {@link
* jdk.internal.org.objectweb.asm.ClassVisitor#visitRecordComponent(String, String, String)}.
*
* @param name the field's name.
* @param descriptor the record component descriptor (see {@link Type}).
* @param signature the record component signature. May be {@literal null} if the record component
* type does not use generic types.
* @return a visitor to visit this record component annotations and attributes, or {@literal null}
* if this class visitor is not interested in visiting these annotations and attributes.
*/
public Printer visitRecordComponent(
final String name, final String descriptor, final String signature) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Class field. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}.
*
@ -676,6 +701,63 @@ public abstract class Printer {
/** Annotation end. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnd}. */
public abstract void visitAnnotationEnd();
// -----------------------------------------------------------------------------------------------
// Record components
// -----------------------------------------------------------------------------------------------
/**
* Visits an annotation of the record component. See {@link
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitAnnotation}.
*
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
public Printer visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Visits an annotation on a type in the record component signature. See {@link
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitTypeAnnotation}.
*
* @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
* {@link TypeReference}.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
public Printer visitRecordComponentTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Visits a non standard attribute of the record component. See {@link
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitAttribute}.
*
* @param attribute an attribute.
*/
public void visitRecordComponentAttribute(final Attribute attribute) {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
/**
* Visits the end of the record component. See {@link
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitEnd}. This method, which is the last one to be
* called, is used to inform the visitor that everything have been visited.
*/
public void visitRecordComponentEnd() {
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
// -----------------------------------------------------------------------------------------------
// Fields
// -----------------------------------------------------------------------------------------------
@ -723,7 +805,7 @@ public abstract class Printer {
/**
* Method parameter. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}.
*
* @param name parameter name or null if none is provided.
* @param name parameter name or {@literal null} if none is provided.
* @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
* or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
*/
@ -913,12 +995,10 @@ public abstract class Printer {
@Deprecated
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
// This method was abstract before ASM5, and was therefore always overridden (without any
// call to 'super'). Thus, at this point we necessarily have api >= ASM5, and we must then
// redirect the method call to the ASM5 visitMethodInsn() method.
visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
/**
@ -938,13 +1018,6 @@ public abstract class Printer {
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM 5");
}
visitMethodInsn(opcode, owner, name, descriptor);
return;
}
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
}
@ -1194,20 +1267,6 @@ public abstract class Printer {
}
}
/**
* Appends a quoted string to the given string buffer.
*
* @param stringBuffer the buffer where the string must be added.
* @param string the string to be added.
* @deprecated use {@link #appendString(StringBuilder, String)} instead.
*/
@Deprecated
public static void appendString(final StringBuffer stringBuffer, final String string) {
StringBuilder stringBuilder = new StringBuilder();
appendString(stringBuilder, string);
stringBuffer.append(stringBuilder.toString());
}
/**
* Appends a quoted string to the given string builder.
*
@ -1244,24 +1303,30 @@ public abstract class Printer {
}
/**
* Prints a the given class to the standard output.
* Prints a the given class to the given output.
*
* <p>Command line arguments: [-debug] &lt;binary class name or class file name &gt;
*
* @param args the command line arguments.
* @param usage the help message to show when command line arguments are incorrect.
* @param printer the printer to convert the class into text.
* @param args the command line arguments.
* @param output where to print the result.
* @param logger where to log errors.
* @throws IOException if the class cannot be found, or if an IOException occurs.
*/
static void main(final String usage, final Printer printer, final String[] args)
static void main(
final String[] args,
final String usage,
final Printer printer,
final PrintWriter output,
final PrintWriter logger)
throws IOException {
if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) {
System.err.println(usage);
logger.println(usage);
return;
}
TraceClassVisitor traceClassVisitor =
new TraceClassVisitor(null, printer, new PrintWriter(System.out));
TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, output);
String className;
int parsingOptions;

@ -59,7 +59,11 @@
package jdk.internal.org.objectweb.asm.util;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle;
@ -77,6 +81,11 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader;
*/
public class Textifier extends Printer {
/** The help message shown when command line arguments are incorrect. */
private static final String USAGE =
"Prints a disassembled view of the given class.\n"
+ "Usage: Textifier [-debug] <fully qualified class name or class file name>";
/** The type of internal names. See {@link #appendDescriptor}. */
public static final int INTERNAL_NAME = 0;
@ -95,34 +104,17 @@ public class Textifier extends Printer {
/** The type of class signatures. See {@link #appendDescriptor}. */
public static final int CLASS_SIGNATURE = 5;
/**
* Deprecated.
*
* @deprecated this constant has never been used.
*/
@Deprecated public static final int TYPE_DECLARATION = 6;
/**
* Deprecated.
*
* @deprecated this constant has never been used.
*/
@Deprecated public static final int CLASS_DECLARATION = 7;
/**
* Deprecated.
*
* @deprecated this constant has never been used.
*/
@Deprecated public static final int PARAMETERS_DECLARATION = 8;
/** The type of method handle descriptors. See {@link #appendDescriptor}. */
public static final int HANDLE_DESCRIPTOR = 9;
private static final String CLASS_SUFFIX = ".class";
private static final String DEPRECATED = "// DEPRECATED\n";
private static final String RECORD = "// RECORD\n";
private static final String INVISIBLE = " // invisible\n";
private static final List<String> FRAME_TYPES =
Collections.unmodifiableList(Arrays.asList("T", "I", "F", "D", "J", "N", "U"));
/** The indentation of class members at depth level 1 (e.g. fields, methods). */
protected String tab = " ";
@ -151,7 +143,7 @@ public class Textifier extends Printer {
* @throws IllegalStateException If a subclass calls this constructor.
*/
public Textifier() {
this(Opcodes.ASM7);
this(/* latest api = */ Opcodes.ASM8);
if (getClass() != Textifier.class) {
throw new IllegalStateException();
}
@ -161,7 +153,8 @@ public class Textifier extends Printer {
* Constructs a new {@link Textifier}.
*
* @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}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
*/
protected Textifier(final int api) {
super(api);
@ -176,10 +169,22 @@ public class Textifier extends Printer {
* @throws IOException if the class cannot be found, or if an IOException occurs.
*/
public static void main(final String[] args) throws IOException {
String usage =
"Prints a disassembled view of the given class.\n"
+ "Usage: Textifier [-debug] <fully qualified class name or class file name>";
main(usage, new Textifier(), args);
main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
}
/**
* Prints a disassembled view of the given class to the given output.
*
* <p>Usage: Textifier [-debug] &lt;binary class name or class file name &gt;
*
* @param args the command line arguments.
* @param output where to print the result.
* @param logger where to log errors.
* @throws IOException if the class cannot be found, or if an IOException occurs.
*/
static void main(final String[] args, final PrintWriter output, final PrintWriter logger)
throws IOException {
main(args, USAGE, new Textifier(), output, logger);
}
// -----------------------------------------------------------------------------------------------
@ -213,6 +218,9 @@ public class Textifier extends Printer {
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
stringBuilder.append(DEPRECATED);
}
if ((access & Opcodes.ACC_RECORD) != 0) {
stringBuilder.append(RECORD);
}
appendRawAccess(access);
appendDescriptor(CLASS_SIGNATURE, signature);
@ -329,6 +337,22 @@ public class Textifier extends Printer {
text.add(stringBuilder.toString());
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("PERMITTEDSUBTYPE ");
appendDescriptor(INTERNAL_NAME, permittedSubtype);
stringBuilder.append('\n');
text.add(stringBuilder.toString());
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
@ -347,6 +371,28 @@ public class Textifier extends Printer {
text.add(stringBuilder.toString());
}
@Override
public Printer visitRecordComponent(
final String name, final String descriptor, final String signature) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("RECORDCOMPONENT ");
if (signature != null) {
stringBuilder.append(tab);
appendDescriptor(FIELD_SIGNATURE, signature);
stringBuilder.append(tab);
appendJavaDeclaration(name, signature);
}
stringBuilder.append(tab);
appendDescriptor(FIELD_DESCRIPTOR, descriptor);
stringBuilder.append(' ').append(name);
stringBuilder.append('\n');
text.add(stringBuilder.toString());
return addNewTextifier(null);
}
@Override
public Textifier visitField(
final int access,
@ -482,30 +528,20 @@ public class Textifier extends Printer {
}
@Override
public void visitExport(final String export, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("exports ");
stringBuilder.append(export);
if (modules != null && modules.length > 0) {
stringBuilder.append(" to");
} else {
stringBuilder.append(';');
}
appendRawAccess(access);
if (modules != null && modules.length > 0) {
for (int i = 0; i < modules.length; ++i) {
stringBuilder.append(tab2).append(modules[i]);
stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
}
}
text.add(stringBuilder.toString());
public void visitExport(final String packaze, final int access, final String... modules) {
visitExportOrOpen("exports ", packaze, access, modules);
}
@Override
public void visitOpen(final String export, final int access, final String... modules) {
public void visitOpen(final String packaze, final int access, final String... modules) {
visitExportOrOpen("opens ", packaze, access, modules);
}
private void visitExportOrOpen(
final String method, final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("opens ");
stringBuilder.append(export);
stringBuilder.append(tab).append(method);
stringBuilder.append(packaze);
if (modules != null && modules.length > 0) {
stringBuilder.append(" to");
} else {
@ -712,6 +748,31 @@ public class Textifier extends Printer {
}
}
// -----------------------------------------------------------------------------------------------
// Record components
// -----------------------------------------------------------------------------------------------
@Override
public Textifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
return visitAnnotation(descriptor, visible);
}
@Override
public Printer visitRecordComponentTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
@Override
public void visitRecordComponentAttribute(final Attribute attribute) {
visitAttribute(attribute);
}
@Override
public void visitRecordComponentEnd() {
// Nothing to do.
}
// -----------------------------------------------------------------------------------------------
// Fields
// -----------------------------------------------------------------------------------------------
@ -796,19 +857,7 @@ public class Textifier extends Printer {
@Override
public void visitMethodAttribute(final Attribute attribute) {
stringBuilder.setLength(0);
stringBuilder.append(tab).append("ATTRIBUTE ");
appendDescriptor(-1, attribute.type);
if (attribute instanceof Textifiable) {
StringBuffer stringBuffer = new StringBuffer();
((Textifiable) attribute).textify(stringBuffer, labelNames);
stringBuilder.append(stringBuffer.toString());
} else {
stringBuilder.append(" : unknown\n");
}
text.add(stringBuilder.toString());
visitAttribute(attribute);
}
@Override
@ -904,37 +953,8 @@ public class Textifier extends Printer {
text.add(stringBuilder.toString());
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(
final int opcode,
final String owner,
final String name,
@ -1261,10 +1281,11 @@ public class Textifier extends Printer {
stringBuilder.append(tab).append("ATTRIBUTE ");
appendDescriptor(-1, attribute.type);
if (attribute instanceof Textifiable) {
StringBuffer stringBuffer = new StringBuffer();
((Textifiable) attribute).textify(stringBuffer, null);
stringBuilder.append(stringBuffer.toString());
if (attribute instanceof TextifierSupport) {
if (labelNames == null) {
labelNames = new HashMap<>();
}
((TextifierSupport) attribute).textify(stringBuilder, labelNames);
} else {
stringBuilder.append(" : unknown\n");
}
@ -1340,8 +1361,7 @@ public class Textifier extends Printer {
*
* @param type the type of 'value'. Must be one of {@link #INTERNAL_NAME}, {@link
* #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link
* #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE}, {@link #TYPE_DECLARATION}, {@link
* #CLASS_DECLARATION}, {@link #PARAMETERS_DECLARATION} of {@link #HANDLE_DESCRIPTOR}.
* #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE} or {@link #HANDLE_DESCRIPTOR}.
* @param value an internal name, type descriptor or a type signature. May be {@literal null}.
*/
protected void appendDescriptor(final int type, final String value) {
@ -1384,7 +1404,7 @@ public class Textifier extends Printer {
*/
protected void appendLabel(final Label label) {
if (labelNames == null) {
labelNames = new HashMap<Label, String>();
labelNames = new HashMap<>();
}
String name = labelNames.get(label);
if (name == null) {
@ -1587,31 +1607,7 @@ public class Textifier extends Printer {
appendDescriptor(INTERNAL_NAME, descriptor);
}
} else if (frameTypes[i] instanceof Integer) {
switch (((Integer) frameTypes[i]).intValue()) {
case 0:
appendDescriptor(FIELD_DESCRIPTOR, "T");
break;
case 1:
appendDescriptor(FIELD_DESCRIPTOR, "I");
break;
case 2:
appendDescriptor(FIELD_DESCRIPTOR, "F");
break;
case 3:
appendDescriptor(FIELD_DESCRIPTOR, "D");
break;
case 4:
appendDescriptor(FIELD_DESCRIPTOR, "J");
break;
case 5:
appendDescriptor(FIELD_DESCRIPTOR, "N");
break;
case 6:
appendDescriptor(FIELD_DESCRIPTOR, "U");
break;
default:
throw new IllegalArgumentException();
}
stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue()));
} else {
appendLabel((Label) frameTypes[i]);
}
@ -1639,6 +1635,6 @@ public class Textifier extends Printer {
* @return a new {@link Textifier}.
*/
protected Textifier createTextifier() {
return new Textifier();
return new Textifier(api);
}
}

@ -0,0 +1,78 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.util;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Label;
/**
* An {@link jdk.internal.org.objectweb.asm.Attribute} that can print a readable representation of itself.
*
* @author Eugene Kuleshov
*/
public interface TextifierSupport {
/**
* Generates a human readable representation of this attribute.
*
* @param outputBuilder where the human representation of this attribute must be appended.
* @param labelNames the human readable names of the labels.
*/
void textify(StringBuilder outputBuilder, Map<Label, String> labelNames);
}

@ -88,7 +88,7 @@ public final class TraceAnnotationVisitor extends AnnotationVisitor {
* @param printer the printer to convert the visited annotation into text.
*/
public TraceAnnotationVisitor(final AnnotationVisitor annotationVisitor, final Printer printer) {
super(Opcodes.ASM7, annotationVisitor);
super(/* latest api = */ Opcodes.ASM8, annotationVisitor);
this.printer = printer;
}

@ -66,6 +66,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
@ -147,9 +148,10 @@ public final class TraceClassVisitor extends ClassVisitor {
* @param printer the printer to convert the visited class into text.
* @param printWriter the print writer to be used to print the class. May be {@literal null}.
*/
@SuppressWarnings("deprecation")
public TraceClassVisitor(
final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) {
super(Opcodes.ASM7, classVisitor);
super(/* latest api = */ Opcodes.ASM9_EXPERIMENTAL, classVisitor);
this.printWriter = printWriter;
this.p = printer;
}
@ -217,6 +219,19 @@ public final class TraceClassVisitor extends ClassVisitor {
super.visitNestMember(nestMember);
}
/**
* <b>Experimental, use at your own risk.</b>.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
p.visitPermittedSubtypeExperimental(permittedSubtype);
super.visitPermittedSubtypeExperimental(permittedSubtype);
}
@Override
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
@ -224,6 +239,14 @@ public final class TraceClassVisitor extends ClassVisitor {
super.visitInnerClass(name, outerName, innerName, access);
}
@Override
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
Printer recordComponentPrinter = p.visitRecordComponent(name, descriptor, signature);
return new TraceRecordComponentVisitor(
super.visitRecordComponent(name, descriptor, signature), recordComponentPrinter);
}
@Override
public FieldVisitor visitField(
final int access,

@ -91,7 +91,7 @@ public final class TraceFieldVisitor extends FieldVisitor {
* @param printer the printer to convert the visited field into text.
*/
public TraceFieldVisitor(final FieldVisitor fieldVisitor, final Printer printer) {
super(Opcodes.ASM7, fieldVisitor);
super(/* latest api = */ Opcodes.ASM8, fieldVisitor);
this.p = printer;
}

@ -93,7 +93,7 @@ public final class TraceMethodVisitor extends MethodVisitor {
* @param printer the printer to convert the visited method into text.
*/
public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) {
super(Opcodes.ASM7, methodVisitor);
super(/* latest api = */ Opcodes.ASM8, methodVisitor);
this.p = printer;
}
@ -192,37 +192,27 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, descriptor);
}
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
p.visitMethodInsn(opcode, owner, name, descriptor);
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor);
}
}
@Override
@SuppressWarnings("deprecation")
public void visitMethodInsn(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
// Call the method that p is supposed to implement, depending on its api version.
if (p.api < Opcodes.ASM5) {
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM5");
}
// If p is an ASMifier (resp. Textifier), or a subclass that does not override the old
// visitMethodInsn method, the default implementation in Printer will redirect this to the
// new method in ASMifier (resp. Textifier). In all other cases, p overrides the old method
// and this call executes it.
p.visitMethodInsn(opcode, owner, name, descriptor);
} else {
p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}

@ -88,7 +88,7 @@ public final class TraceModuleVisitor extends ModuleVisitor {
* @param printer the printer to convert the visited module into text.
*/
public TraceModuleVisitor(final ModuleVisitor moduleVisitor, final Printer printer) {
super(Opcodes.ASM7, moduleVisitor);
super(/* latest api = */ Opcodes.ASM8, moduleVisitor);
this.p = printer;
}

@ -0,0 +1,127 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm.util;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link RecordComponentVisitor} that prints the record components it visits with a {@link
* Printer}.
*
* @author Remi Forax
*/
public final class TraceRecordComponentVisitor extends RecordComponentVisitor {
/** The printer to convert the visited record component into text. */
public final Printer printer;
/**
* Constructs a new {@link TraceRecordComponentVisitor}.
*
* @param printer the printer to convert the visited record component into text.
*/
public TraceRecordComponentVisitor(final Printer printer) {
this(null, printer);
}
/**
* Constructs a new {@link TraceRecordComponentVisitor}.
*
* @param recordComponentVisitor the record component visitor to which to delegate calls. May be
* {@literal null}.
* @param printer the printer to convert the visited record component into text.
*/
public TraceRecordComponentVisitor(
final RecordComponentVisitor recordComponentVisitor, final Printer printer) {
super(/* latest api ='*/ Opcodes.ASM8, recordComponentVisitor);
this.printer = printer;
}
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
Printer annotationPrinter = printer.visitRecordComponentAnnotation(descriptor, visible);
return new TraceAnnotationVisitor(
super.visitAnnotation(descriptor, visible), annotationPrinter);
}
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
Printer annotationPrinter =
printer.visitRecordComponentTypeAnnotation(typeRef, typePath, descriptor, visible);
return new TraceAnnotationVisitor(
super.visitTypeAnnotation(typeRef, typePath, descriptor, visible), annotationPrinter);
}
@Override
public void visitAttribute(final Attribute attribute) {
printer.visitRecordComponentAttribute(attribute);
super.visitAttribute(attribute);
}
@Override
public void visitEnd() {
printer.visitRecordComponentEnd();
super.visitEnd();
}
}

@ -58,6 +58,9 @@
*/
package jdk.internal.org.objectweb.asm.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
@ -74,6 +77,22 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
private static final String EXTENDS_SEPARATOR = " extends ";
private static final String IMPLEMENTS_SEPARATOR = " implements ";
private static final Map<Character, String> BASE_TYPES;
static {
HashMap<Character, String> baseTypes = new HashMap<>();
baseTypes.put('Z', "boolean");
baseTypes.put('B', "byte");
baseTypes.put('C', "char");
baseTypes.put('S', "short");
baseTypes.put('I', "int");
baseTypes.put('J', "long");
baseTypes.put('F', "float");
baseTypes.put('D', "double");
baseTypes.put('V', "void");
BASE_TYPES = Collections.unmodifiableMap(baseTypes);
}
/** Whether the visited signature is a class signature of a Java interface. */
private final boolean isInterface;
@ -121,13 +140,13 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
* @param accessFlags for class type signatures, the access flags of the class.
*/
public TraceSignatureVisitor(final int accessFlags) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0;
this.declaration = new StringBuilder();
}
private TraceSignatureVisitor(final StringBuilder stringBuilder) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.isInterface = false;
this.declaration = stringBuilder;
}
@ -212,37 +231,11 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
@Override
public void visitBaseType(final char descriptor) {
switch (descriptor) {
case 'V':
declaration.append("void");
break;
case 'B':
declaration.append("byte");
break;
case 'J':
declaration.append("long");
break;
case 'Z':
declaration.append("boolean");
break;
case 'I':
declaration.append("int");
break;
case 'S':
declaration.append("short");
break;
case 'C':
declaration.append("char");
break;
case 'F':
declaration.append("float");
break;
case 'D':
declaration.append("double");
break;
default:
throw new IllegalArgumentException();
String baseType = BASE_TYPES.get(descriptor);
if (baseType == null) {
throw new IllegalArgumentException();
}
declaration.append(baseType);
endType();
}

@ -1,2 +1,2 @@
ASM_7_0
ASM_8_0_1
origin http://gitlab.ow2.org/asm/asm.git (fetch)

@ -1,4 +1,4 @@
## ASM Bytecode Manipulation Framework v7.0
## ASM Bytecode Manipulation Framework v8.0.1
### ASM License
<pre>

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -217,7 +217,7 @@ public class BadCanonicalCtrTest {
static class RemoveCanonicalCtrVisitor extends ClassVisitor {
static final String CTR_NAME = "<init>";
RemoveCanonicalCtrVisitor(ClassVisitor cv) {
super(ASM7, cv);
super(ASM8, cv);
}
volatile boolean foundCanonicalCtr;
@Override
@ -250,7 +250,7 @@ public class BadCanonicalCtrTest {
/** Replaces whatever <init> method it finds with <init>(Ljava/lang/Object;)V. */
static class ModifyCanonicalCtrVisitor extends ClassVisitor {
ModifyCanonicalCtrVisitor(ClassVisitor cv) {
super(ASM7, cv);
super(ASM8, cv);
}
boolean foundCanonicalCtr;
String className;

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -246,7 +246,7 @@ public class ProhibitedMethods {
static abstract class AbstractVisitor extends ClassVisitor {
final String nameOfMethodToAdd;
AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) {
super(ASM7, cv);
super(ASM8, cv);
this.nameOfMethodToAdd = nameOfMethodToAdd;
}
@Override

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -237,7 +237,7 @@ public class SerialPersistentFieldsTest {
final ObjectStreamField[] spf;
String className;
SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) {
super(ASM7, cv);
super(ASM8, cv);
this.spf = spf;
}
@Override