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

View file

@ -74,7 +74,10 @@ public abstract class AnnotationVisitor {
*/ */
protected final int api; 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; 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 * @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} or {@link Opcodes#ASM7}.
* @param annotationVisitor the annotation visitor to which this visitor must delegate method * @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) { public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) { if (api != Opcodes.ASM8
throw new IllegalArgumentException(); && 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.api = api;
this.av = annotationVisitor; this.av = annotationVisitor;

View file

@ -122,7 +122,7 @@ final class AnnotationWriter extends AnnotationVisitor {
private AnnotationWriter nextAnnotation; 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 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). * the structure except the last one (the element_value_pairs array).
* @param previousAnnotation the previously visited annotation of the * @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
* other cases (e.g. nested or array annotations). * {@literal null} in other cases (e.g. nested or array annotations).
*/ */
AnnotationWriter( AnnotationWriter(
final SymbolTable symbolTable, final SymbolTable symbolTable,
final boolean useNamedValues, final boolean useNamedValues,
final ByteVector annotation, final ByteVector annotation,
final AnnotationWriter previousAnnotation) { final AnnotationWriter previousAnnotation) {
super(Opcodes.ASM7); super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.useNamedValues = useNamedValues; this.useNamedValues = useNamedValues;
this.annotation = annotation; 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 symbolTable where the constants used in this AnnotationWriter must be stored.
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to * @param descriptor the class descriptor of the annotation class.
* 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 * @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in * Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
* other cases (e.g. nested or array annotations). * {@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 SymbolTable symbolTable,
final ByteVector annotation, final String descriptor,
final AnnotationWriter previousAnnotation) { 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. // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0); annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
return new AnnotationWriter(symbolTable, annotation, null); return new AnnotationWriter(symbolTable, /* useNamedValues = */ true, annotation, null);
} }
@Override @Override
@ -315,7 +355,7 @@ final class AnnotationWriter extends AnnotationVisitor {
* and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name * and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
* to the constant pool of the class (if not null). * 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 * @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 * annotation and all its predecessors. This includes the size of the attribute_name_index and
* attribute_length fields. * attribute_length fields.
@ -334,6 +374,56 @@ final class AnnotationWriter extends AnnotationVisitor {
return attributeSize; 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 * 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 * <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 * 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 * annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the

View file

@ -59,7 +59,7 @@
package jdk.internal.org.objectweb.asm; 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). * Specification (JVMS).
* *
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">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 * 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; 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() { public boolean isCodeAttribute() {
return false; return false;
@ -123,7 +123,7 @@ public class Attribute {
* Returns the labels corresponding to this attribute. * Returns the labels corresponding to this attribute.
* *
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not * @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() { protected Label[] getLabels() {
return new Label[0]; return new Label[0];
@ -135,18 +135,18 @@ public class Attribute {
* ClassReader. * ClassReader.
* *
* @param classReader the class that contains the attribute to be read. * @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 * @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
* 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into * attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here. * account here.
* @param length the length of the attribute's content (excluding the 6 attribute header bytes). * @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 * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
* 'charBuffer' parameter. * 'charBuffer' parameter.
* @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute * @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 * attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here. * account here.
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read * @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. * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
*/ */
protected Attribute read( protected Attribute read(
@ -158,7 +158,7 @@ public class Attribute {
final Label[] labels) { final Label[] labels) {
Attribute attribute = new Attribute(type); Attribute attribute = new Attribute(type);
attribute.content = new byte[length]; 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; 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 * @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. * 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} * @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 * if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
* attribute. * attribute.
* @param codeLength the length of the bytecode of the method corresponding to this code * @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. * field of the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or * @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
* -1 if this attribute is not a code attribute. * -1 if this attribute is not a Code attribute.
* @param maxLocals the maximum number of local variables of the method corresponding to this code * @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. * @return the byte array form of this attribute.
*/ */
protected ByteVector write( protected ByteVector write(
@ -228,16 +228,16 @@ public class Attribute {
* attribute_length) per attribute. Also adds the attribute type names to the constant pool. * 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 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 * @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 * null} if they are not Code attributes. Corresponds to the 'code' field of the Code
* attribute. * attribute.
* @param codeLength the length of the bytecode of the method corresponding to these code * @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. * the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
* -1 if they are not code attributes. * -1 if they are not Code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these * @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 * @return the size of all the attributes in this attribute list. This size includes the size of
* the attribute headers. * the attribute headers.
*/ */
@ -258,6 +258,42 @@ public class Attribute {
return size; 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 * 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 * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
@ -280,16 +316,16 @@ public class Attribute {
* attribute. * attribute.
* *
* @param symbolTable where the constants used in the attributes must be stored. * @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 * @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 * null} if they are not Code attributes. Corresponds to the 'code' field of the Code
* attribute. * attribute.
* @param codeLength the length of the bytecode of the method corresponding to these code * @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. * the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or * @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
* -1 if they are not code attributes. * -1 if they are not Code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these * @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. * @param output where the attributes must be written.
*/ */
final void putAttributes( 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). */ /** A set of attribute prototypes (attributes with the same type are considered equal). */
static final class Set { static final class Set {

View file

@ -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: * 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 * {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code * visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} | * visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
* {@code visitMethod} )* {@code visitEnd}. * visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
@ -75,7 +75,7 @@ public abstract class ClassVisitor {
*/ */
protected final int api; 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; protected ClassVisitor cv;
/** /**
@ -92,13 +92,23 @@ public abstract class ClassVisitor {
* Constructs a new {@link ClassVisitor}. * Constructs a new {@link ClassVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null. * null.
*/ */
@SuppressWarnings("deprecation")
public ClassVisitor(final int api, final ClassVisitor classVisitor) { public ClassVisitor(final int api, final ClassVisitor classVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) { if (api != Opcodes.ASM8
throw new IllegalArgumentException(); && 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.api = api;
this.cv = classVisitor; 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, * @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. * 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 * @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 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 * @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. * 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 signature,
final String superName, final String superName,
final String[] interfaces) { final String[] interfaces) {
if (api < Opcodes.ASM8 && (access & Opcodes.ACC_RECORD) != 0) {
throw new UnsupportedOperationException("Records requires ASM8");
}
if (cv != null) { if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces); 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 * Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited. * 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. * Visits a field of the class.
* *

View file

@ -110,8 +110,8 @@ public class ClassWriter extends ClassVisitor {
/** /**
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific * 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 * access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
* ClassFile structure. * removed when generating the ClassFile structure.
*/ */
private int accessFlags; private int accessFlags;
@ -208,6 +208,26 @@ public class ClassWriter extends ClassVisitor {
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */ /** The 'classes' array of the NestMembers attribute, or {@literal null}. */
private ByteVector nestMemberClasses; 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 * The first non standard attribute of this class. The next ones can be accessed with the {@link
* Attribute#nextAttribute} field. May be {@literal null}. * 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>. * maximum stack size nor the stack frames will be computed for these methods</i>.
*/ */
public ClassWriter(final ClassReader classReader, final int flags) { 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); symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
if ((flags & COMPUTE_FRAMES) != 0) { if ((flags & COMPUTE_FRAMES) != 0) {
this.compute = MethodWriter.COMPUTE_ALL_FRAMES; this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
@ -329,7 +349,7 @@ public class ClassWriter extends ClassVisitor {
} }
@Override @Override
public void visitNestHost(final String nestHost) { public final void visitNestHost(final String nestHost) {
nestHostClassIndex = symbolTable.addConstantClass(nestHost).index; nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
} }
@ -344,37 +364,26 @@ public class ClassWriter extends ClassVisitor {
@Override @Override
public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleAnnotation = return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else { } else {
return lastRuntimeInvisibleAnnotation = return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
} }
} }
@Override @Override
public final AnnotationVisitor visitTypeAnnotation( public final AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleTypeAnnotation = return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else { } else {
return lastRuntimeInvisibleTypeAnnotation = return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
} }
} }
@ -386,7 +395,7 @@ public class ClassWriter extends ClassVisitor {
} }
@Override @Override
public void visitNestMember(final String nestMember) { public final void visitNestMember(final String nestMember) {
if (nestMemberClasses == null) { if (nestMemberClasses == null) {
nestMemberClasses = new ByteVector(); nestMemberClasses = new ByteVector();
} }
@ -394,6 +403,22 @@ public class ClassWriter extends ClassVisitor {
nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index); 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 @Override
public final void visitInnerClass( public final void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) { 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? // 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 @Override
public final FieldVisitor visitField( public final FieldVisitor visitField(
final int access, 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 ClassTooLargeException if the constant pool of the class is too large.
* @throws MethodTooLargeException if the Code attribute of a method 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. // First step: compute the size in bytes of the ClassFile structure.
// The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version, // 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, // 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(); size += methodWriter.computeMethodInfoSize();
methodWriter = (MethodWriter) methodWriter.mv; methodWriter = (MethodWriter) methodWriter.mv;
} }
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
int attributesCount = 0; int attributesCount = 0;
if (innerClasses != null) { if (innerClasses != null) {
@ -568,6 +607,24 @@ public class ClassWriter extends ClassVisitor {
size += 8 + nestMemberClasses.length; size += 8 + nestMemberClasses.length;
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS); 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) { if (firstAttribute != null) {
attributesCount += firstAttribute.getAttributeCount(); attributesCount += firstAttribute.getAttributeCount();
size += firstAttribute.computeAttributesSize(symbolTable); size += firstAttribute.computeAttributesSize(symbolTable);
@ -648,22 +705,13 @@ public class ClassWriter extends ClassVisitor {
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) { if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0); result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
} }
if (lastRuntimeVisibleAnnotation != null) { AnnotationWriter.putAnnotations(
lastRuntimeVisibleAnnotation.putAnnotations( symbolTable,
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result); lastRuntimeVisibleAnnotation,
} lastRuntimeInvisibleAnnotation,
if (lastRuntimeInvisibleAnnotation != null) { lastRuntimeVisibleTypeAnnotation,
lastRuntimeInvisibleAnnotation.putAnnotations( lastRuntimeInvisibleTypeAnnotation,
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result); 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);
}
symbolTable.putBootstrapMethods(result); symbolTable.putBootstrapMethods(result);
if (moduleWriter != null) { if (moduleWriter != null) {
moduleWriter.putAttributes(result); moduleWriter.putAttributes(result);
@ -681,6 +729,24 @@ public class ClassWriter extends ClassVisitor {
.putShort(numberOfNestMemberClasses) .putShort(numberOfNestMemberClasses)
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length); .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) { if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, result); firstAttribute.putAttributes(symbolTable, result);
} }
@ -717,6 +783,10 @@ public class ClassWriter extends ClassVisitor {
nestHostClassIndex = 0; nestHostClassIndex = 0;
numberOfNestMemberClasses = 0; numberOfNestMemberClasses = 0;
nestMemberClasses = null; nestMemberClasses = null;
numberOfPermittedSubtypeClasses = 0;
permittedSubtypeClasses = null;
firstRecordComponent = null;
lastRecordComponent = null;
firstAttribute = null; firstAttribute = null;
compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING; compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
new ClassReader(classFile, 0, /* checkClassVersion = */ false) new ClassReader(classFile, 0, /* checkClassVersion = */ false)
@ -745,6 +815,11 @@ public class ClassWriter extends ClassVisitor {
methodWriter.collectAttributePrototypes(attributePrototypes); methodWriter.collectAttributePrototypes(attributePrototypes);
methodWriter = (MethodWriter) methodWriter.mv; methodWriter = (MethodWriter) methodWriter.mv;
} }
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
recordComponentWriter.collectAttributePrototypes(attributePrototypes);
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
return attributePrototypes.toArray(); return attributePrototypes.toArray();
} }

View file

@ -58,6 +58,11 @@
*/ */
package jdk.internal.org.objectweb.asm; 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 * Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
* API. * 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> * @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
* @author Eric Bruneton * @author Eric Bruneton
*/ */
final class Constants implements Opcodes { final class Constants {
// The ClassFile attribute names, in the order they are defined in // 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. // 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 MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost"; static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers"; static final String NEST_MEMBERS = "NestMembers";
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
static final String RECORD = "Record";
// ASM specific access flags. // ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard // 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. // Constants to convert between normal and wide jump instructions.
// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP. // 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. // 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. // ASM specific opcodes, used for long forward jump instructions.
static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA; static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA; static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA; static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA; static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA; static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA; static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA; static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA; static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA; static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA; static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
static final int ASM_JSR = JSR + ASM_OPCODE_DELTA; static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA; static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA; static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_GOTO_W = 220; static final int ASM_GOTO_W = 220;
private Constants() {} 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");
}
}
} }

View file

@ -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 * 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; 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; protected FieldVisitor fv;
/** /**
* Constructs a new {@link FieldVisitor}. * Constructs a new {@link FieldVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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) { public FieldVisitor(final int api) {
this(api, null); this(api, null);
@ -90,13 +92,23 @@ public abstract class FieldVisitor {
* Constructs a new {@link FieldVisitor}. * Constructs a new {@link FieldVisitor}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 * @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
* null. * null.
*/ */
@SuppressWarnings("deprecation")
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) { public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) { if (api != Opcodes.ASM8
throw new IllegalArgumentException(); && 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.api = api;
this.fv = fieldVisitor; this.fv = fieldVisitor;

View file

@ -155,7 +155,7 @@ final class FieldWriter extends FieldVisitor {
final String descriptor, final String descriptor,
final String signature, final String signature,
final Object constantValue) { final Object constantValue) {
super(Opcodes.ASM7); super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.accessFlags = access; this.accessFlags = access;
this.nameIndex = symbolTable.addConstantUtf8(name); this.nameIndex = symbolTable.addConstantUtf8(name);
@ -174,37 +174,26 @@ final class FieldWriter extends FieldVisitor {
@Override @Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleAnnotation = return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else { } else {
return lastRuntimeInvisibleAnnotation = return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
} }
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation( public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleTypeAnnotation = return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else { } else {
return lastRuntimeInvisibleTypeAnnotation = 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); symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
size += 8; size += 8;
} }
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute. size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
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 += size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize( AnnotationWriter.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS); lastRuntimeVisibleAnnotation,
} lastRuntimeInvisibleAnnotation,
if (lastRuntimeInvisibleAnnotation != null) { lastRuntimeVisibleTypeAnnotation,
size += lastRuntimeInvisibleTypeAnnotation);
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);
}
if (firstAttribute != null) { if (firstAttribute != null) {
size += firstAttribute.computeAttributesSize(symbolTable); size += firstAttribute.computeAttributesSize(symbolTable);
} }
@ -333,34 +291,14 @@ final class FieldWriter extends FieldVisitor {
.putInt(2) .putInt(2)
.putShort(constantValueIndex); .putShort(constantValueIndex);
} }
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); AnnotationWriter.putAnnotations(
} symbolTable,
if (signatureIndex != 0) { lastRuntimeVisibleAnnotation,
output lastRuntimeInvisibleAnnotation,
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) lastRuntimeVisibleTypeAnnotation,
.putInt(2) lastRuntimeInvisibleTypeAnnotation,
.putShort(signatureIndex); output);
}
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);
}
if (firstAttribute != null) { if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, output); firstAttribute.putAttributes(symbolTable, output);
} }

View file

@ -85,19 +85,19 @@ package jdk.internal.org.objectweb.asm;
* *
* <pre> * <pre>
* ===================================== * =====================================
* |.DIM|KIND|FLAG|...............VALUE| * |...DIM|KIND|.F|...............VALUE|
* ===================================== * =====================================
* </pre> * </pre>
* *
* <ul> * <ul>
* <li>the DIM field, stored in the 4 most significant bits, is a signed number of array * <li>the DIM field, stored in the 6 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 * dimensions (from -32 to 31, included). It can be retrieved with {@link #DIM_MASK} and a
* shift of {@link #DIM_SHIFT}. * 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 * <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 * 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} * #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
* or {@link #STACK_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}. * is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
* <li>the VALUE field, stored in the remaining 20 bits, contains either * <li>the VALUE field, stored in the remaining 20 bits, contains either
* <ul> * <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 * <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 * 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 * 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 * UNINITIALIZED_KIND abstract types of positive or {@literal null} array dimension. In all cases
* table contains only internal type names (array type descriptors are forbidden - array dimensions * the type table contains only internal type names (array type descriptors are forbidden - array
* must be represented through the DIM field). * 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 + * <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 * 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_CHAR = 11;
private static final int ITEM_ASM_SHORT = 12; 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. // Bitmasks to get each field of an abstract type.
private static final int DIM_MASK = 0xF0000000; private static final int DIM_MASK = ((1 << DIM_SIZE) - 1) << DIM_SHIFT;
private static final int KIND_MASK = 0x0F000000; private static final int KIND_MASK = ((1 << KIND_SIZE) - 1) << KIND_SHIFT;
private static final int FLAGS_MASK = 0x00F00000; private static final int VALUE_MASK = (1 << VALUE_SIZE) - 1;
private static final int VALUE_MASK = 0x000FFFFF;
// Constants to manipulate the DIM field of an abstract type. // 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. */ /** 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; 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. // Possible values for the KIND field of an abstract type.
private static final int CONSTANT_KIND = 0x01000000; private static final int CONSTANT_KIND = 1 << KIND_SHIFT;
private static final int REFERENCE_KIND = 0x02000000; private static final int REFERENCE_KIND = 2 << KIND_SHIFT;
private static final int UNINITIALIZED_KIND = 0x03000000; private static final int UNINITIALIZED_KIND = 3 << KIND_SHIFT;
private static final int LOCAL_KIND = 0x04000000; private static final int LOCAL_KIND = 4 << KIND_SHIFT;
private static final int STACK_KIND = 0x05000000; private static final int STACK_KIND = 5 << KIND_SHIFT;
// Possible flags for the FLAGS field of an abstract type. // 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 * concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been
* partially overridden with an xSTORE instruction). * 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). // 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). * @param descriptor a type or method descriptor (in which case its return type is pushed).
*/ */
private void push(final SymbolTable symbolTable, final String descriptor) { 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); int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset);
if (abstractType != 0) { if (abstractType != 0) {
push(abstractType); push(abstractType);
@ -1134,6 +1142,42 @@ class Frame {
// Frame merging methods, used in the second step of the stack map frame computation algorithm // 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 * 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 * {@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. // value at the beginning of the block.
concreteOutputType = inputLocals[i]; concreteOutputType = inputLocals[i];
} else { } else {
int dim = abstractOutputType & DIM_MASK; concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
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;
}
} }
} else { } else {
// If the local variable has never been assigned in this basic block, it is equal to its // 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 // 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). // same as the one above for local variables).
for (int i = 0; i < outputStackTop; ++i) { for (int i = 0; i < outputStackTop; ++i) {
int concreteOutputType;
int abstractOutputType = outputStack[i]; int abstractOutputType = outputStack[i];
int dim = abstractOutputType & DIM_MASK; int concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
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;
}
if (initializations != null) { if (initializations != null) {
concreteOutputType = getInitializedType(symbolTable, concreteOutputType); 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 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. * @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 * 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}, * @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 * {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or {@literal
* dimensions. * null} array dimensions.
* @param dstIndex the index of the type that must be merged in dstTypes. * @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. * @return {@literal true} if the type array has been modified by this operation.
*/ */

View file

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

View file

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

View file

@ -623,7 +623,7 @@ final class MethodWriter extends MethodVisitor {
final String signature, final String signature,
final String[] exceptions, final String[] exceptions,
final int compute) { final int compute) {
super(Opcodes.ASM7); super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable; this.symbolTable = symbolTable;
this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access; this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
this.nameIndex = symbolTable.addConstantUtf8(name); this.nameIndex = symbolTable.addConstantUtf8(name);
@ -685,37 +685,26 @@ final class MethodWriter extends MethodVisitor {
@Override @Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleAnnotation = return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
} else { } else {
return lastRuntimeInvisibleAnnotation = return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation); AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
} }
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation( public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 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) { if (visible) {
return lastRuntimeVisibleTypeAnnotation = return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
} else { } else {
return lastRuntimeInvisibleTypeAnnotation = return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
} }
} }
@ -731,27 +720,24 @@ final class MethodWriter extends MethodVisitor {
@Override @Override
public AnnotationVisitor visitParameterAnnotation( public AnnotationVisitor visitParameterAnnotation(
final int parameter, final String annotationDescriptor, final boolean visible) { 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 (visible) {
if (lastRuntimeVisibleParameterAnnotations == null) { if (lastRuntimeVisibleParameterAnnotations == null) {
lastRuntimeVisibleParameterAnnotations = lastRuntimeVisibleParameterAnnotations =
new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
} }
return lastRuntimeVisibleParameterAnnotations[parameter] = return lastRuntimeVisibleParameterAnnotations[parameter] =
new AnnotationWriter( AnnotationWriter.create(
symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]); symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
} else { } else {
if (lastRuntimeInvisibleParameterAnnotations == null) { if (lastRuntimeInvisibleParameterAnnotations == null) {
lastRuntimeInvisibleParameterAnnotations = lastRuntimeInvisibleParameterAnnotations =
new AnnotationWriter[Type.getArgumentTypes(descriptor).length]; new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
} }
return lastRuntimeInvisibleParameterAnnotations[parameter] = return lastRuntimeInvisibleParameterAnnotations[parameter] =
new AnnotationWriter( AnnotationWriter.create(
symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]); symbolTable,
annotationDescriptor,
lastRuntimeInvisibleParameterAnnotations[parameter]);
} }
} }
@ -820,6 +806,9 @@ final class MethodWriter extends MethodVisitor {
} }
visitFrameEnd(); visitFrameEnd();
} else { } else {
if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
}
int offsetDelta; int offsetDelta;
if (stackMapTableEntries == null) { if (stackMapTableEntries == null) {
stackMapTableEntries = new ByteVector(); stackMapTableEntries = new ByteVector();
@ -1446,20 +1435,22 @@ final class MethodWriter extends MethodVisitor {
@Override @Override
public AnnotationVisitor visitInsnAnnotation( public AnnotationVisitor visitInsnAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 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) { if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation = return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); AnnotationWriter.create(
symbolTable,
(typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
typePath,
descriptor,
lastCodeRuntimeVisibleTypeAnnotation);
} else { } else {
return lastCodeRuntimeInvisibleTypeAnnotation = 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 @Override
public AnnotationVisitor visitTryCatchAnnotation( public AnnotationVisitor visitTryCatchAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { 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) { if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation = return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); AnnotationWriter.create(
symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
} else { } else {
return lastCodeRuntimeInvisibleTypeAnnotation = 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); typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) { if (visible) {
return lastCodeRuntimeVisibleTypeAnnotation = return lastCodeRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation); new AnnotationWriter(
symbolTable,
/* useNamedValues = */ true,
typeAnnotation,
lastCodeRuntimeVisibleTypeAnnotation);
} else { } else {
return lastCodeRuntimeInvisibleTypeAnnotation = 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. * 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 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 * @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
* of this method might be copied contains a Synthetic attribute. * of this method might be copied contains a Synthetic attribute.
* @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes * @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
@ -2055,8 +2044,6 @@ final class MethodWriter extends MethodVisitor {
*/ */
boolean canCopyMethodAttributes( boolean canCopyMethodAttributes(
final ClassReader source, final ClassReader source,
final int methodInfoOffset,
final int methodInfoLength,
final boolean hasSyntheticAttribute, final boolean hasSyntheticAttribute,
final boolean hasDeprecatedAttribute, final boolean hasDeprecatedAttribute,
final int descriptorIndex, final int descriptorIndex,
@ -2091,12 +2078,23 @@ final class MethodWriter extends MethodVisitor {
currentExceptionOffset += 2; 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 // 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 // they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
// of the method_info JVMS structure. // of the method_info JVMS structure.
this.sourceOffset = methodInfoOffset + 6; this.sourceOffset = methodInfoOffset + 6;
this.sourceLength = methodInfoLength - 6; this.sourceLength = methodInfoLength - 6;
return true;
} }
/** /**
@ -2164,29 +2162,13 @@ final class MethodWriter extends MethodVisitor {
symbolTable.addConstantUtf8(Constants.EXCEPTIONS); symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
size += 8 + 2 * numberOfExceptions; size += 8 + 2 * numberOfExceptions;
} }
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5; size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
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 += size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize( AnnotationWriter.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS); lastRuntimeVisibleAnnotation,
} lastRuntimeInvisibleAnnotation,
if (lastRuntimeInvisibleAnnotation != null) { lastRuntimeVisibleTypeAnnotation,
size += lastRuntimeInvisibleTypeAnnotation);
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
}
if (lastRuntimeVisibleParameterAnnotations != null) { if (lastRuntimeVisibleParameterAnnotations != null) {
size += size +=
AnnotationWriter.computeParameterAnnotationsSize( AnnotationWriter.computeParameterAnnotationsSize(
@ -2205,16 +2187,6 @@ final class MethodWriter extends MethodVisitor {
? lastRuntimeInvisibleParameterAnnotations.length ? lastRuntimeInvisibleParameterAnnotations.length
: invisibleAnnotableParameterCount); : 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) { if (defaultValue != null) {
symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT); symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
size += 6 + defaultValue.length; size += 6 + defaultValue.length;
@ -2242,7 +2214,7 @@ final class MethodWriter extends MethodVisitor {
output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex); 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 this method_info must be copied from an existing one, copy it now and return early.
if (sourceOffset != 0) { if (sourceOffset != 0) {
output.putByteArray(symbolTable.getSource().b, sourceOffset, sourceLength); output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength);
return; return;
} }
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS. // 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); output.putShort(exceptionIndex);
} }
} }
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) { Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0); AnnotationWriter.putAnnotations(
} symbolTable,
if (signatureIndex != 0) { lastRuntimeVisibleAnnotation,
output lastRuntimeInvisibleAnnotation,
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE)) lastRuntimeVisibleTypeAnnotation,
.putInt(2) lastRuntimeInvisibleTypeAnnotation,
.putShort(signatureIndex); output);
}
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 (lastRuntimeVisibleParameterAnnotations != null) { if (lastRuntimeVisibleParameterAnnotations != null) {
AnnotationWriter.putParameterAnnotations( AnnotationWriter.putParameterAnnotations(
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS), symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
@ -2434,14 +2394,6 @@ final class MethodWriter extends MethodVisitor {
: invisibleAnnotableParameterCount, : invisibleAnnotableParameterCount,
output); 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) { if (defaultValue != null) {
output output
.putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT)) .putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))

View file

@ -73,7 +73,9 @@ public abstract class ModuleVisitor {
*/ */
protected final int api; 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; 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 * @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
* be null. * be null.
*/ */
@SuppressWarnings("deprecation")
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) { public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM7) { if (api != Opcodes.ASM8
throw new IllegalArgumentException(); && 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.api = api;
this.mv = moduleVisitor; this.mv = moduleVisitor;

View file

@ -125,7 +125,7 @@ final class ModuleWriter extends ModuleVisitor {
private int mainClassIndex; private int mainClassIndex;
ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) { 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.symbolTable = symbolTable;
this.moduleNameIndex = name; this.moduleNameIndex = name;
this.moduleFlags = access; this.moduleFlags = access;

View file

@ -78,9 +78,222 @@ public interface Opcodes {
int ASM5 = 5 << 16 | 0 << 8; int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8; int ASM6 = 6 << 16 | 0 << 8;
int ASM7 = 7 << 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). // major version in the 16 least significant bits).
int V1_1 = 3 << 16 | 45; int V1_1 = 3 << 16 | 45;
@ -134,7 +347,7 @@ public interface Opcodes {
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module * int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
int ACC_ANNOTATION = 0x2000; // class int ACC_ANNOTATION = 0x2000; // class
int ACC_ENUM = 0x4000; // class(?) field inner 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 int ACC_MODULE = 0x8000; // class
// ASM specific access flags. // 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 // 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). // 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 int ACC_DEPRECATED = 0x20000; // class, field, method
// Possible values for the type operand of the NEWARRAY instruction. // Possible values for the type operand of the NEWARRAY instruction.

View file

@ -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();
}
}
}

View file

@ -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);
}
}

View file

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

View file

@ -336,7 +336,8 @@ public final class Type {
} }
if (methodDescriptor.charAt(currentOffset++) == 'L') { if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content. // Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
} }
++numArgumentTypes; ++numArgumentTypes;
} }
@ -354,7 +355,8 @@ public final class Type {
} }
if (methodDescriptor.charAt(currentOffset++) == 'L') { if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content. // Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
} }
argumentTypes[currentArgumentTypeIndex++] = argumentTypes[currentArgumentTypeIndex++] =
getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset); 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. * @return the {@link Type} corresponding to the return type of the given method descriptor.
*/ */
public static Type getReturnType(final String methodDescriptor) { public static Type getReturnType(final String methodDescriptor) {
// Skip the first character, which is always a '('. return getTypeInternal(
int currentOffset = 1; methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length());
// 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());
} }
/** /**
@ -419,6 +410,29 @@ public final class Type {
return getType(method.getReturnType()); 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. * Returns the {@link Type} corresponding to the given field or method descriptor.
* *
@ -536,11 +550,7 @@ public final class Type {
if (sort == OBJECT) { if (sort == OBJECT) {
return valueBuffer.substring(valueBegin - 1, valueEnd + 1); return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
} else if (sort == INTERNAL) { } else if (sort == INTERNAL) {
return new StringBuilder() return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';';
.append('L')
.append(valueBuffer, valueBegin, valueEnd)
.append(';')
.toString();
} else { } else {
return valueBuffer.substring(valueBegin, valueEnd); return valueBuffer.substring(valueBegin, valueEnd);
} }
@ -662,14 +672,7 @@ public final class Type {
} }
stringBuilder.append(descriptor); stringBuilder.append(descriptor);
} else { } else {
stringBuilder.append('L'); stringBuilder.append('L').append(getInternalName(currentClass)).append(';');
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(';');
} }
} }
@ -768,7 +771,8 @@ public final class Type {
} }
if (methodDescriptor.charAt(currentOffset++) == 'L') { if (methodDescriptor.charAt(currentOffset++) == 'L') {
// Skip the argument descriptor content. // Skip the argument descriptor content.
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1; int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
} }
argumentsSize += 1; argumentsSize += 1;
} }

View file

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

View file

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

View file

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

View file

@ -79,15 +79,16 @@ public class AnnotationRemapper extends AnnotationVisitor {
* @param remapper the remapper to use to remap the types in the visited annotation. * @param remapper the remapper to use to remap the types in the visited annotation.
*/ */
public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) { 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}. * Constructs a new {@link AnnotationRemapper}.
* *
* @param api the ASM API version supported by this remapper. Must be one of {@link * @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#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@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 annotationVisitor the annotation visitor this remapper must deleted to. * @param annotationVisitor the annotation visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited annotation. * @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) { if (annotationVisitor == null) {
return null; return null;
} else { } else {
return annotationVisitor == av return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
} }
@ -125,9 +124,18 @@ public class AnnotationRemapper extends AnnotationVisitor {
if (annotationVisitor == null) { if (annotationVisitor == null) {
return null; return null;
} else { } else {
return annotationVisitor == av return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
} }
/**
* 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);
}
} }

View file

@ -66,11 +66,26 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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.TypePath;
/** /**
* A {@link ClassVisitor} that remaps types with a {@link Remapper}. * 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 * @author Eugene Kuleshov
*/ */
public class ClassRemapper extends ClassVisitor { 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. * @param remapper the remapper to use to remap the types in the visited class.
*/ */
public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) { 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 * @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#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 classVisitor the class visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited class. * @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); 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 @Override
public FieldVisitor visitField( public FieldVisitor visitField(
final int access, final int access,
@ -220,6 +249,18 @@ public class ClassRemapper extends ClassVisitor {
super.visitNestMember(remapper.mapType(nestMember)); 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 * Constructs a new remapper for fields. The default implementation of this method returns a new
* {@link FieldRemapper}. * {@link FieldRemapper}.
@ -263,4 +304,16 @@ public class ClassRemapper extends ClassVisitor {
protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) { protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
return new ModuleRemapper(api, moduleVisitor, remapper); 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);
}
} }

View file

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

View file

@ -81,15 +81,15 @@ public class FieldRemapper extends FieldVisitor {
* @param remapper the remapper to use to remap the types in the visited field. * @param remapper the remapper to use to remap the types in the visited field.
*/ */
public FieldRemapper(final FieldVisitor fieldVisitor, final Remapper remapper) { 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}. * Constructs a new {@link FieldRemapper}.
* *
* @param api the ASM API version supported by this remapper. Must be one of {@link * @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#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}. * 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 fieldVisitor the field visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited field. * @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) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor = AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
? null
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
@ -112,8 +110,17 @@ public class FieldRemapper extends FieldVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor = AnnotationVisitor annotationVisitor =
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
? null }
: new AnnotationRemapper(api, annotationVisitor, remapper);
/**
* 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);
} }
} }

View file

@ -214,7 +214,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
private final Type[] argumentTypes; private final Type[] argumentTypes;
/** The types of the local variables of the visited method. */ /** 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>. * 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 int access,
final String name, final String name,
final String descriptor) { final String descriptor) {
this(Opcodes.ASM7, methodVisitor, access, name, descriptor); this(/* latest api = */ Opcodes.ASM8, methodVisitor, access, name, descriptor);
if (getClass() != GeneratorAdapter.class) { if (getClass() != GeneratorAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -242,7 +242,8 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* Constructs a new {@link GeneratorAdapter}. * Constructs a new {@link GeneratorAdapter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 methodVisitor the method visitor to which this adapter delegates calls.
* @param access the method's access flags (see {@link Opcodes}). * @param access the method's access flags (see {@link Opcodes}).
* @param name the method's name. * @param name the method's name.
@ -300,7 +301,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
method.getName(), method.getName(),
method.getDescriptor(), method.getDescriptor(),
signature, 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. * @return the internal names of the given types.
*/ */
private static String[] getInternalNames(final Type[] types) { private static String[] getInternalNames(final Type[] types) {
if (types == null) {
return null;
}
String[] names = new String[types.length]; String[] names = new String[types.length];
for (int i = 0; i < names.length; ++i) { for (int i = 0; i < names.length; ++i) {
names[i] = types[i].getInternalName(); names[i] = types[i].getInternalName();
@ -792,48 +790,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|| to.getSort() > Type.DOUBLE) { || to.getSort() > Type.DOUBLE) {
throw new IllegalArgumentException("Cannot cast from " + from + " to " + to); throw new IllegalArgumentException("Cannot cast from " + from + " to " + to);
} }
if (from == Type.DOUBLE_TYPE) { InstructionAdapter.cast(mv, from, to);
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);
}
}
} }
} }
@ -1350,37 +1307,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* @param type the type of the array elements. * @param type the type of the array elements.
*/ */
public void newArray(final Type type) { public void newArray(final Type type) {
int arrayType; InstructionAdapter.newarray(mv, type);
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);
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------

View file

@ -83,7 +83,7 @@ public class InstructionAdapter extends MethodVisitor {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public InstructionAdapter(final MethodVisitor methodVisitor) { public InstructionAdapter(final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, methodVisitor); this(/* latest api = */ Opcodes.ASM8, methodVisitor);
if (getClass() != InstructionAdapter.class) { if (getClass() != InstructionAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -93,7 +93,8 @@ public class InstructionAdapter extends MethodVisitor {
* Constructs a new {@link InstructionAdapter}. * Constructs a new {@link InstructionAdapter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 methodVisitor the method visitor to which this adapter delegates calls.
*/ */
protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) { 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 @Override
public void visitMethodInsn( public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) { final int opcodeAndSource,
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 owner,
final String name, final String name,
final String descriptor, final String descriptor,
final boolean isInterface) { final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); // Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return; 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) { switch (opcode) {
case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESPECIAL:
invokespecial(owner, name, descriptor, isInterface); invokespecial(owner, name, descriptor, isInterface);
@ -673,7 +652,7 @@ public class InstructionAdapter extends MethodVisitor {
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) { || (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException("This feature requires ASM5"); 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"); throw new UnsupportedOperationException("This feature requires ASM7");
} }
if (value instanceof Integer) { if (value instanceof Integer) {
@ -947,47 +926,58 @@ public class InstructionAdapter extends MethodVisitor {
* @param to a Type. * @param to a Type.
*/ */
public void cast(final Type from, final Type to) { 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 != to) {
if (from == Type.DOUBLE_TYPE) { if (from == Type.DOUBLE_TYPE) {
if (to == Type.FLOAT_TYPE) { if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.D2F); methodVisitor.visitInsn(Opcodes.D2F);
} else if (to == Type.LONG_TYPE) { } else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.D2L); methodVisitor.visitInsn(Opcodes.D2L);
} else { } else {
mv.visitInsn(Opcodes.D2I); methodVisitor.visitInsn(Opcodes.D2I);
cast(Type.INT_TYPE, to); cast(methodVisitor, Type.INT_TYPE, to);
} }
} else if (from == Type.FLOAT_TYPE) { } else if (from == Type.FLOAT_TYPE) {
if (to == Type.DOUBLE_TYPE) { if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.F2D); methodVisitor.visitInsn(Opcodes.F2D);
} else if (to == Type.LONG_TYPE) { } else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.F2L); methodVisitor.visitInsn(Opcodes.F2L);
} else { } else {
mv.visitInsn(Opcodes.F2I); methodVisitor.visitInsn(Opcodes.F2I);
cast(Type.INT_TYPE, to); cast(methodVisitor, Type.INT_TYPE, to);
} }
} else if (from == Type.LONG_TYPE) { } else if (from == Type.LONG_TYPE) {
if (to == Type.DOUBLE_TYPE) { if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.L2D); methodVisitor.visitInsn(Opcodes.L2D);
} else if (to == Type.FLOAT_TYPE) { } else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.L2F); methodVisitor.visitInsn(Opcodes.L2F);
} else { } else {
mv.visitInsn(Opcodes.L2I); methodVisitor.visitInsn(Opcodes.L2I);
cast(Type.INT_TYPE, to); cast(methodVisitor, Type.INT_TYPE, to);
} }
} else { } else {
if (to == Type.BYTE_TYPE) { if (to == Type.BYTE_TYPE) {
mv.visitInsn(Opcodes.I2B); methodVisitor.visitInsn(Opcodes.I2B);
} else if (to == Type.CHAR_TYPE) { } else if (to == Type.CHAR_TYPE) {
mv.visitInsn(Opcodes.I2C); methodVisitor.visitInsn(Opcodes.I2C);
} else if (to == Type.DOUBLE_TYPE) { } else if (to == Type.DOUBLE_TYPE) {
mv.visitInsn(Opcodes.I2D); methodVisitor.visitInsn(Opcodes.I2D);
} else if (to == Type.FLOAT_TYPE) { } else if (to == Type.FLOAT_TYPE) {
mv.visitInsn(Opcodes.I2F); methodVisitor.visitInsn(Opcodes.I2F);
} else if (to == Type.LONG_TYPE) { } else if (to == Type.LONG_TYPE) {
mv.visitInsn(Opcodes.I2L); methodVisitor.visitInsn(Opcodes.I2L);
} else if (to == Type.SHORT_TYPE) { } 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. * @param type an array Type.
*/ */
public void newarray(final Type 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; int arrayType;
switch (type.getSort()) { switch (type.getSort()) {
case Type.BOOLEAN: case Type.BOOLEAN:
@ -1283,10 +1283,10 @@ public class InstructionAdapter extends MethodVisitor {
arrayType = Opcodes.T_DOUBLE; arrayType = Opcodes.T_DOUBLE;
break; break;
default: default:
mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName()); methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
return; return;
} }
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType); methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType);
} }
public void arraylength() { public void arraylength() {

View file

@ -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 * instruction, bit i of the corresponding BitSet in this map is set iff instruction at index i
* belongs to this subroutine. * 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 * 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 descriptor,
final String signature, final String signature,
final String[] exceptions) { 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) { if (getClass() != JSRInlinerAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -139,7 +146,8 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
* Constructs a new {@link JSRInlinerAdapter}. * Constructs a new {@link JSRInlinerAdapter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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> * @param methodVisitor the method visitor to send the resulting inlined method code to, or <code>
* null</code>. * null</code>.
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if * @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. * fully elaborated.
*/ */
private void emitCode() { 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. // Create an instantiation of the main "subroutine", which is just the main routine.
worklist.add(new Instantiation(null, mainSubroutineInsns)); worklist.add(new Instantiation(null, mainSubroutineInsns));
// Emit instantiations of each subroutine we encounter, including the main subroutine. // Emit instantiations of each subroutine we encounter, including the main subroutine.
InsnList newInstructions = new InsnList(); InsnList newInstructions = new InsnList();
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>(); List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<>();
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>(); List<LocalVariableNode> newLocalVariables = new ArrayList<>();
while (!worklist.isEmpty()) { while (!worklist.isEmpty()) {
Instantiation instantiation = worklist.removeFirst(); Instantiation instantiation = worklist.removeFirst();
emitInstantiation( emitInstantiation(
@ -486,7 +494,7 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
this.parent = parent; this.parent = parent;
this.subroutineInsns = subroutineInsns; this.subroutineInsns = subroutineInsns;
this.returnLabel = parent == null ? null : new LabelNode(); 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 // 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. // labels which point at the same instruction into one.

View file

@ -112,7 +112,7 @@ public class LocalVariablesSorter extends MethodVisitor {
*/ */
public LocalVariablesSorter( public LocalVariablesSorter(
final int access, final String descriptor, final MethodVisitor methodVisitor) { 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) { if (getClass() != LocalVariablesSorter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -122,7 +122,8 @@ public class LocalVariablesSorter extends MethodVisitor {
* Constructs a new {@link LocalVariablesSorter}. * Constructs a new {@link LocalVariablesSorter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 access access flags of the adapted method.
* @param descriptor the method's descriptor (see {@link Type}). * @param descriptor the method's descriptor (see {@link Type}).
* @param methodVisitor the method visitor to which this adapter delegates calls. * @param methodVisitor the method visitor to which this adapter delegates calls.

View file

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

View file

@ -83,7 +83,7 @@ public class MethodRemapper extends MethodVisitor {
* @param remapper the remapper to use to remap the types in the visited method. * @param remapper the remapper to use to remap the types in the visited method.
*/ */
public MethodRemapper(final MethodVisitor methodVisitor, final Remapper remapper) { 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 * @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#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 methodVisitor the method visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited method. * @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(); AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -115,7 +116,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitAnnotation(remapper.mapDesc(descriptor), visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -125,7 +126,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -135,7 +136,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible); super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -180,54 +181,25 @@ public class MethodRemapper extends MethodVisitor {
remapper.mapDesc(descriptor)); remapper.mapDesc(descriptor));
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override @Override
public void visitMethodInsn( public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) { final int opcodeAndSource,
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 owner,
final String name, final String name,
final String descriptor, final String descriptor,
final boolean isInterface) { final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); // Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface); super.visitMethodInsn(
} opcodeAndSource,
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.mapType(owner),
remapper.mapMethodName(owner, name, descriptor), remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor), remapper.mapMethodDesc(descriptor),
isInterface); isInterface);
} }
}
@Override @Override
public void visitInvokeDynamicInsn( public void visitInvokeDynamicInsn(
@ -268,7 +240,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -284,7 +256,7 @@ public class MethodRemapper extends MethodVisitor {
super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible); super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper); : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
@ -318,6 +290,17 @@ public class MethodRemapper extends MethodVisitor {
typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible); typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null return annotationVisitor == null
? annotationVisitor ? 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);
} }
} }

View file

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

View file

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

View file

@ -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);
}
}

View file

@ -140,8 +140,7 @@ public abstract class Remapper {
String remappedInternalName = mapType(internalName); String remappedInternalName = mapType(internalName);
if (remappedInternalName != null) { if (remappedInternalName != null) {
if (remappedInternalNames == null) { if (remappedInternalNames == null) {
remappedInternalNames = new String[internalNames.length]; remappedInternalNames = internalNames.clone();
System.arraycopy(internalNames, 0, remappedInternalNames, 0, internalNames.length);
} }
remappedInternalNames[i] = remappedInternalName; remappedInternalNames[i] = remappedInternalName;
} }
@ -281,7 +280,12 @@ public abstract class Remapper {
final String name, final String ownerName, final String innerName) { final String name, final String ownerName, final String innerName) {
final String remappedInnerName = this.mapType(name); final String remappedInnerName = this.mapType(name);
if (remappedInnerName.contains("$")) { 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 { } else {
return innerName; return innerName;
} }
@ -312,6 +316,20 @@ public abstract class Remapper {
return name; 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 * Maps a field name to its new name. The default implementation of this method returns the given
* name, unchanged. Subclasses can override. * name, unchanged. Subclasses can override.

View file

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

View file

@ -73,7 +73,7 @@ public class SignatureRemapper extends SignatureVisitor {
private final Remapper remapper; 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>. * 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. * @param remapper the remapper to use to remap the types in the visited signature.
*/ */
public SignatureRemapper(final SignatureVisitor signatureVisitor, final Remapper remapper) { 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}. * Constructs a new {@link SignatureRemapper}.
* *
* @param api the ASM API version supported by this remapper. Must be one of {@link * @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#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5},{@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 signatureVisitor the signature visitor this remapper must deleted to. * @param signatureVisitor the signature visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited signature. * @param remapper the remapper to use to remap the types in the visited signature.
*/ */

View file

@ -92,14 +92,15 @@ public class StaticInitMerger extends ClassVisitor {
* null. * null.
*/ */
public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) { 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}. * Constructs a new {@link StaticInitMerger}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 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 * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null. * null.

View file

@ -100,7 +100,14 @@ public class TryCatchBlockSorter extends MethodNode {
final String descriptor, final String descriptor,
final String signature, final String signature,
final String[] exceptions) { 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) { if (getClass() != TryCatchBlockSorter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }

View file

@ -102,9 +102,15 @@ public abstract class SignatureVisitor {
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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} or {@link Opcodes#ASM7}.
*/ */
@SuppressWarnings("deprecation")
public SignatureVisitor(final int api) { public SignatureVisitor(final int api) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) { if (api != Opcodes.ASM8
throw new IllegalArgumentException(); && 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; this.api = api;
} }

View file

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

View file

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

View file

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

View file

@ -67,6 +67,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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.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'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; 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}. */ /** The internal names of the nest members of this class. May be {@literal null}. */
public List<String> nestMembers; 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. */ /** The fields of this class. */
public List<FieldNode> fields; public List<FieldNode> fields;
@ -170,7 +183,7 @@ public class ClassNode extends ClassVisitor {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public ClassNode() { public ClassNode() {
this(Opcodes.ASM7); this(Opcodes.ASM8);
if (getClass() != ClassNode.class) { if (getClass() != ClassNode.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -180,14 +193,15 @@ public class ClassNode extends ClassVisitor {
* Constructs a new {@link ClassNode}. * Constructs a new {@link ClassNode}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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) { public ClassNode(final int api) {
super(api); super(api);
this.interfaces = new ArrayList<String>(); this.interfaces = new ArrayList<>();
this.innerClasses = new ArrayList<InnerClassNode>(); this.innerClasses = new ArrayList<>();
this.fields = new ArrayList<FieldNode>(); this.fields = new ArrayList<>();
this.methods = new ArrayList<MethodNode>(); this.methods = new ArrayList<>();
} }
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -238,15 +252,9 @@ public class ClassNode extends ClassVisitor {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationNode annotation = new AnnotationNode(descriptor); AnnotationNode annotation = new AnnotationNode(descriptor);
if (visible) { if (visible) {
if (visibleAnnotations == null) { visibleAnnotations = Util.add(visibleAnnotations, annotation);
visibleAnnotations = new ArrayList<AnnotationNode>(1);
}
visibleAnnotations.add(annotation);
} else { } else {
if (invisibleAnnotations == null) { invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(annotation);
} }
return annotation; return annotation;
} }
@ -256,33 +264,33 @@ public class ClassNode extends ClassVisitor {
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor); TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
if (visible) { if (visible) {
if (visibleTypeAnnotations == null) { visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
visibleTypeAnnotations.add(typeAnnotation);
} else { } else {
if (invisibleTypeAnnotations == null) { invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(typeAnnotation);
} }
return typeAnnotation; return typeAnnotation;
} }
@Override @Override
public void visitAttribute(final Attribute attribute) { public void visitAttribute(final Attribute attribute) {
if (attrs == null) { attrs = Util.add(attrs, attribute);
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attribute);
} }
@Override @Override
public void visitNestMember(final String nestMember) { public void visitNestMember(final String nestMember) {
if (nestMembers == null) { nestMembers = Util.add(nestMembers, nestMember);
nestMembers = new ArrayList<String>();
} }
nestMembers.add(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 @Override
@ -292,6 +300,14 @@ public class ClassNode extends ClassVisitor {
innerClasses.add(innerClass); 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 @Override
public FieldVisitor visitField( public FieldVisitor visitField(
final int access, final int access,
@ -331,9 +347,16 @@ public class ClassNode extends ClassVisitor {
* in more recent versions of the ASM API than the given version. * 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}, * @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) { 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)) { if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
throw new UnsupportedClassVersionException(); throw new UnsupportedClassVersionException();
} }
@ -369,6 +392,11 @@ public class ClassNode extends ClassVisitor {
invisibleTypeAnnotations.get(i).check(api); 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) { for (int i = fields.size() - 1; i >= 0; --i) {
fields.get(i).check(api); fields.get(i).check(api);
} }
@ -382,6 +410,7 @@ public class ClassNode extends ClassVisitor {
* *
* @param classVisitor a class visitor. * @param classVisitor a class visitor.
*/ */
@SuppressWarnings("deprecation")
public void accept(final ClassVisitor classVisitor) { public void accept(final ClassVisitor classVisitor) {
// Visit the header. // Visit the header.
String[] interfacesArray = new String[this.interfaces.size()]; String[] interfacesArray = new String[this.interfaces.size()];
@ -444,10 +473,22 @@ public class ClassNode extends ClassVisitor {
classVisitor.visitNestMember(nestMembers.get(i)); 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. // Visit the inner classes.
for (int i = 0, n = innerClasses.size(); i < n; ++i) { for (int i = 0, n = innerClasses.size(); i < n; ++i) {
innerClasses.get(i).accept(classVisitor); 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. // Visit the fields.
for (int i = 0, n = fields.size(); i < n; ++i) { for (int i = 0, n = fields.size(); i < n; ++i) {
fields.get(i).accept(classVisitor); fields.get(i).accept(classVisitor);

View file

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

View file

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

View file

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

View file

@ -114,14 +114,15 @@ public class LocalVariableAnnotationNode extends TypeAnnotationNode {
final LabelNode[] end, final LabelNode[] end,
final int[] index, final int[] index,
final String descriptor) { 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}. * Constructs a new {@link LocalVariableAnnotationNode}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 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 * @param start the fist instructions corresponding to the continuous ranges that make the scope
* of this local variable (inclusive). * of this local variable (inclusive).

View file

@ -96,9 +96,7 @@ public class MethodInsnNode extends AbstractInsnNode {
* jdk.internal.org.objectweb.asm.Type#getInternalName()}). * jdk.internal.org.objectweb.asm.Type#getInternalName()}).
* @param name the method's name. * @param name the method's name.
* @param descriptor the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). * @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( public MethodInsnNode(
final int opcode, final String owner, final String name, final String descriptor) { final int opcode, final String owner, final String name, final String descriptor) {
this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE); this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);

View file

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

View file

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

View file

@ -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();
}
}

View file

@ -90,7 +90,7 @@ public class TypeAnnotationNode extends AnnotationNode {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) { 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) { if (getClass() != TypeAnnotationNode.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -100,7 +100,8 @@ public class TypeAnnotationNode extends AnnotationNode {
* Constructs a new {@link AnnotationNode}. * Constructs a new {@link AnnotationNode}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 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 * @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 * static inner type within 'typeRef'. May be {@literal null} if the annotation targets

View file

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

View file

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

View file

@ -92,7 +92,7 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
* version. * version.
*/ */
public BasicInterpreter() { public BasicInterpreter() {
super(ASM7); super(/* latest api = */ ASM8);
if (getClass() != BasicInterpreter.class) { if (getClass() != BasicInterpreter.class) {
throw new IllegalStateException(); 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 * @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#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) { protected BasicInterpreter(final int api) {
super(api); super(api);

View file

@ -78,7 +78,7 @@ public class BasicVerifier extends BasicInterpreter {
* use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version. * use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
*/ */
public BasicVerifier() { public BasicVerifier() {
super(ASM7); super(/* latest api = */ ASM8);
if (getClass() != BasicVerifier.class) { if (getClass() != BasicVerifier.class) {
throw new IllegalStateException(); 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 * @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#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) { protected BasicVerifier(final int api) {
super(api); super(api);

View file

@ -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 * this frame corresponds to the successor of the jump instruction (i.e. the next instruction
* in the instructions sequence). * 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. * 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) { public V getLocal(final int index) {
if (index >= numLocals) { 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]; return values[index];
} }
@ -204,7 +206,7 @@ public class Frame<V extends Value> {
*/ */
public void setLocal(final int index, final V value) { public void setLocal(final int index, final V value) {
if (index >= numLocals) { 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; values[index] = value;
} }
@ -237,7 +239,7 @@ public class Frame<V extends Value> {
* @param value the new value of the stack slot. * @param value the new value of the stack slot.
* @throws IndexOutOfBoundsException if the stack slot does not exist. * @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; values[numLocals + index] = value;
} }
@ -379,24 +381,9 @@ public class Frame<V extends Value> {
break; break;
case Opcodes.DUP_X2: case Opcodes.DUP_X2:
value1 = pop(); value1 = pop();
if (value1.getSize() == 1) { if (value1.getSize() == 1 && executeDupX2(insn, value1, interpreter)) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break; break;
} }
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
}
throw new AnalyzerException(insn, "Illegal use of DUP_X2"); throw new AnalyzerException(insn, "Illegal use of DUP_X2");
case Opcodes.DUP2: case Opcodes.DUP2:
value1 = pop(); value1 = pop();
@ -466,24 +453,9 @@ public class Frame<V extends Value> {
break; break;
} }
} }
} else { } else if (executeDupX2(insn, value1, interpreter)) {
value2 = pop();
if (value2.getSize() == 1) {
value3 = pop();
if (value3.getSize() == 1) {
push(interpreter.copyOperation(insn, value1));
push(value3);
push(value2);
push(value1);
break; break;
} }
} else {
push(interpreter.copyOperation(insn, value1));
push(value2);
push(value1);
break;
}
}
throw new AnalyzerException(insn, "Illegal use of DUP2_X2"); throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
case Opcodes.SWAP: case Opcodes.SWAP:
value2 = pop(); value2 = pop();
@ -629,36 +601,11 @@ public class Frame<V extends Value> {
case Opcodes.INVOKESPECIAL: case Opcodes.INVOKESPECIAL:
case Opcodes.INVOKESTATIC: case Opcodes.INVOKESTATIC:
case Opcodes.INVOKEINTERFACE: case Opcodes.INVOKEINTERFACE:
{ executeInvokeInsn(insn, ((MethodInsnNode) insn).desc, interpreter);
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; break;
}
case Opcodes.INVOKEDYNAMIC: case Opcodes.INVOKEDYNAMIC:
{ executeInvokeInsn(insn, ((InvokeDynamicInsnNode) insn).desc, interpreter);
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; break;
}
case Opcodes.NEW: case Opcodes.NEW:
push(interpreter.newOperation(insn)); push(interpreter.newOperation(insn));
break; break;
@ -679,7 +626,7 @@ public class Frame<V extends Value> {
interpreter.unaryOperation(insn, pop()); interpreter.unaryOperation(insn, pop());
break; break;
case Opcodes.MULTIANEWARRAY: case Opcodes.MULTIANEWARRAY:
List<V> valueList = new ArrayList<V>(); List<V> valueList = new ArrayList<>();
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) { for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
valueList.add(0, pop()); 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. * Merges the given frame into this frame.
* *

View file

@ -124,7 +124,12 @@ public class SimpleVerifier extends BasicVerifier {
final Type currentSuperClass, final Type currentSuperClass,
final List<Type> currentClassInterfaces, final List<Type> currentClassInterfaces,
final boolean isInterface) { final boolean isInterface) {
this(ASM7, currentClass, currentSuperClass, currentClassInterfaces, isInterface); this(
/* latest api = */ ASM8,
currentClass,
currentSuperClass,
currentClassInterfaces,
isInterface);
if (getClass() != SimpleVerifier.class) { if (getClass() != SimpleVerifier.class) {
throw new IllegalStateException(); 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 * @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#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 currentClass the type of the class to be verified.
* @param currentSuperClass the type of the super class 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 * @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(); type1 = type1.getElementType();
type2 = type2.getElementType(); type2 = type2.getElementType();
} }
do { while (true) {
if (type1 == null || isInterface(type1)) { if (type1 == null || isInterface(type1)) {
return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions); return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
} }
@ -293,7 +299,7 @@ public class SimpleVerifier extends BasicVerifier {
if (isAssignableFrom(type1, type2)) { if (isAssignableFrom(type1, type2)) {
return newArrayValue(type1, numDimensions); return newArrayValue(type1, numDimensions);
} }
} while (true); }
} }
return BasicValue.UNINITIALIZED_VALUE; return BasicValue.UNINITIALIZED_VALUE;
} }

View file

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

View file

@ -82,7 +82,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
* version. * version.
*/ */
public SourceInterpreter() { public SourceInterpreter() {
super(ASM7); super(/* latest api = */ ASM8);
if (getClass() != SourceInterpreter.class) { if (getClass() != SourceInterpreter.class) {
throw new IllegalStateException(); 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 * @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#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) { protected SourceInterpreter(final int api) {
super(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)) { 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(value1.insns);
setUnion.addAll(value2.insns); setUnion.addAll(value2.insns);
return new SourceValue(Math.min(value1.size, value2.size), setUnion); return new SourceValue(Math.min(value1.size, value2.size), setUnion);

View file

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

View file

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

View file

@ -59,8 +59,11 @@
package jdk.internal.org.objectweb.asm.util; package jdk.internal.org.objectweb.asm.util;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ConstantDynamic; 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). // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public class ASMifier extends Printer { 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. */ /** A pseudo access flag used to distinguish class access flags. */
private static final int ACCESS_CLASS = 0x40000; 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_VISITOR = "annotationVisitor";
private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = "; 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_ARRAY = " });\n";
private static final String END_PARAMETERS = ");\n\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 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; private static final Map<Integer, String> CLASS_VERSIONS;
static { 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_1, "V1_1");
classVersions.put(Opcodes.V1_2, "V1_2"); classVersions.put(Opcodes.V1_2, "V1_2");
classVersions.put(Opcodes.V1_3, "V1_3"); classVersions.put(Opcodes.V1_3, "V1_3");
@ -113,6 +133,9 @@ public class ASMifier extends Printer {
classVersions.put(Opcodes.V10, "V10"); classVersions.put(Opcodes.V10, "V10");
classVersions.put(Opcodes.V11, "V11"); classVersions.put(Opcodes.V11, "V11");
classVersions.put(Opcodes.V12, "V12"); 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); CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
} }
@ -132,7 +155,7 @@ public class ASMifier extends Printer {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public ASMifier() { public ASMifier() {
this(Opcodes.ASM7, "classWriter", 0); this(/* latest api = */ Opcodes.ASM8, "classWriter", 0);
if (getClass() != ASMifier.class) { if (getClass() != ASMifier.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -142,7 +165,7 @@ public class ASMifier extends Printer {
* Constructs a new {@link ASMifier}. * Constructs a new {@link ASMifier}.
* *
* @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4}, * @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 visitorVariableName the name of the visitor variable in the produced code.
* @param annotationVisitorId identifier of the annotation 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. * @throws IOException if the class cannot be found, or if an IOException occurs.
*/ */
public static void main(final String[] args) throws IOException { public static void main(final String[] args) throws IOException {
String usage = main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
"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); /**
* 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; simpleName = name;
} else { } else {
text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n"); 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"); 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.Label;\n");
text.add("import jdk.internal.org.objectweb.asm.MethodVisitor;\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.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.Type;\n");
text.add("import jdk.internal.org.objectweb.asm.TypePath;\n"); text.add("import jdk.internal.org.objectweb.asm.TypePath;\n");
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n"); text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
text.add("public static byte[] dump () throws Exception {\n\n"); text.add("public static byte[] dump () throws Exception {\n\n");
text.add("ClassWriter classWriter = new ClassWriter(0);\n"); text.add("ClassWriter classWriter = new ClassWriter(0);\n");
text.add("FieldVisitor fieldVisitor;\n"); text.add("FieldVisitor fieldVisitor;\n");
text.add("RecordComponentVisitor recordComponentVisitor;\n");
text.add("MethodVisitor methodVisitor;\n"); text.add("MethodVisitor methodVisitor;\n");
text.add("AnnotationVisitor annotationVisitor0;\n\n"); text.add("AnnotationVisitor annotationVisitor0;\n\n");
@ -275,7 +312,7 @@ public class ASMifier extends Printer {
stringBuilder.setLength(0); stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestHost("); stringBuilder.append("classWriter.visitNestHost(");
appendConstant(nestHost); appendConstant(nestHost);
stringBuilder.append(");\n\n"); stringBuilder.append(END_PARAMETERS);
text.add(stringBuilder.toString()); text.add(stringBuilder.toString());
} }
@ -313,7 +350,23 @@ public class ASMifier extends Printer {
stringBuilder.setLength(0); stringBuilder.setLength(0);
stringBuilder.append("classWriter.visitNestMember("); stringBuilder.append("classWriter.visitNestMember(");
appendConstant(nestMember); 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()); text.add(stringBuilder.toString());
} }
@ -333,6 +386,25 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString()); 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 @Override
public ASMifier visitField( public ASMifier visitField(
final int access, final int access,
@ -441,27 +513,18 @@ public class ASMifier extends Printer {
@Override @Override
public void visitExport(final String packaze, final int access, final String... modules) { public void visitExport(final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0); visitExportOrOpen("moduleVisitor.visitExport(", packaze, access, modules);
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());
} }
@Override @Override
public void visitOpen(final String packaze, final int access, final String... modules) { 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.setLength(0);
stringBuilder.append("moduleVisitor.visitOpen("); stringBuilder.append(visitMethod);
appendConstant(packaze); appendConstant(packaze);
stringBuilder.append(", "); stringBuilder.append(", ");
appendAccessFlags(access | ACCESS_MODULE); appendAccessFlags(access | ACCESS_MODULE);
@ -579,6 +642,33 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString()); 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 // Fields
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -805,37 +895,8 @@ public class ASMifier extends Printer {
text.add(stringBuilder.toString()); text.add(stringBuilder.toString());
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override @Override
public void visitMethodInsn( 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 int opcode,
final String owner, final String owner,
final String name, final String name,
@ -1205,14 +1266,12 @@ public class ASMifier extends Printer {
public void visitAttribute(final Attribute attribute) { public void visitAttribute(final Attribute attribute) {
stringBuilder.setLength(0); stringBuilder.setLength(0);
stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n'); stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
if (attribute instanceof ASMifiable) { if (attribute instanceof ASMifierSupport) {
if (labelNames == null) { if (labelNames == null) {
labelNames = new HashMap<Label, String>(); labelNames = new HashMap<>();
} }
stringBuilder.append("{\n"); stringBuilder.append("{\n");
StringBuffer stringBuffer = new StringBuffer(); ((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames);
((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
stringBuilder.append(stringBuffer.toString());
stringBuilder.append(name).append(".visitAttribute(attribute);\n"); stringBuilder.append(name).append(".visitAttribute(attribute);\n");
stringBuilder.append("}\n"); stringBuilder.append("}\n");
} }
@ -1233,7 +1292,7 @@ public class ASMifier extends Printer {
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility). // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected ASMifier createASMifier( protected ASMifier createASMifier(
final String visitorVariableName, final int annotationVisitorId) { 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"); stringBuilder.append("ACC_DEPRECATED");
isEmpty = false; 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 ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
if (!isEmpty) { if (!isEmpty) {
stringBuilder.append(" | "); stringBuilder.append(" | ");
@ -1415,17 +1481,17 @@ public class ASMifier extends Printer {
stringBuilder.append("new Handle("); stringBuilder.append("new Handle(");
Handle handle = (Handle) value; Handle handle = (Handle) value;
stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \""); stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
stringBuilder.append(handle.getOwner()).append("\", \""); stringBuilder.append(handle.getOwner()).append(COMMA);
stringBuilder.append(handle.getName()).append("\", \""); stringBuilder.append(handle.getName()).append(COMMA);
stringBuilder.append(handle.getDesc()).append("\", "); stringBuilder.append(handle.getDesc()).append("\", ");
stringBuilder.append(handle.isInterface()).append(")"); stringBuilder.append(handle.isInterface()).append(")");
} else if (value instanceof ConstantDynamic) { } else if (value instanceof ConstantDynamic) {
stringBuilder.append("new ConstantDynamic(\""); stringBuilder.append("new ConstantDynamic(\"");
ConstantDynamic constantDynamic = (ConstantDynamic) value; ConstantDynamic constantDynamic = (ConstantDynamic) value;
stringBuilder.append(constantDynamic.getName()).append("\", \""); stringBuilder.append(constantDynamic.getName()).append(COMMA);
stringBuilder.append(constantDynamic.getDescriptor()).append("\", "); stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
appendConstant(constantDynamic.getBootstrapMethod()); appendConstant(constantDynamic.getBootstrapMethod());
stringBuilder.append(", new Object[] {"); stringBuilder.append(NEW_OBJECT_ARRAY);
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount(); int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) { for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
appendConstant(constantDynamic.getBootstrapMethodArgument(i)); appendConstant(constantDynamic.getBootstrapMethodArgument(i));
@ -1542,31 +1608,7 @@ public class ASMifier extends Printer {
if (frameTypes[i] instanceof String) { if (frameTypes[i] instanceof String) {
appendConstant(frameTypes[i]); appendConstant(frameTypes[i]);
} else if (frameTypes[i] instanceof Integer) { } else if (frameTypes[i] instanceof Integer) {
switch (((Integer) frameTypes[i]).intValue()) { stringBuilder.append(FRAME_TYPES.get(((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();
}
} else { } else {
appendLabel((Label) frameTypes[i]); appendLabel((Label) frameTypes[i]);
} }
@ -1582,7 +1624,7 @@ public class ASMifier extends Printer {
*/ */
protected void declareLabel(final Label label) { protected void declareLabel(final Label label) {
if (labelNames == null) { if (labelNames == null) {
labelNames = new HashMap<Label, String>(); labelNames = new HashMap<>();
} }
String labelName = labelNames.get(label); String labelName = labelNames.get(label);
if (labelName == null) { if (labelName == null) {

View file

@ -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);
}

View file

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

View file

@ -75,6 +75,7 @@ import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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.Type;
import jdk.internal.org.objectweb.asm.TypePath; import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference; 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 { 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 "; private static final String ERROR_AT = ": error at index ";
/** Whether the bytecode must be checked with a BasicVerifier. */ /** 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. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) { public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
this(Opcodes.ASM7, classVisitor, checkDataFlow); this(/* latest api = */ Opcodes.ASM8, classVisitor, checkDataFlow);
if (getClass() != CheckClassAdapter.class) { if (getClass() != CheckClassAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -209,7 +215,8 @@ public class CheckClassAdapter extends ClassVisitor {
* Constructs a new {@link CheckClassAdapter}. * Constructs a new {@link CheckClassAdapter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 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 * @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 * not perform any data flow check (see {@link CheckMethodAdapter}). This option requires
@ -218,7 +225,7 @@ public class CheckClassAdapter extends ClassVisitor {
protected CheckClassAdapter( protected CheckClassAdapter(
final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) { final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
super(api, classVisitor); super(api, classVisitor);
this.labelInsnIndices = new HashMap<Label, Integer>(); this.labelInsnIndices = new HashMap<>();
this.checkDataFlow = checkDataFlow; this.checkDataFlow = checkDataFlow;
} }
@ -250,6 +257,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_ANNOTATION | Opcodes.ACC_ANNOTATION
| Opcodes.ACC_ENUM | Opcodes.ACC_ENUM
| Opcodes.ACC_DEPRECATED | Opcodes.ACC_DEPRECATED
| Opcodes.ACC_RECORD
| Opcodes.ACC_MODULE); | Opcodes.ACC_MODULE);
if (name == null) { if (name == null) {
throw new IllegalArgumentException("Illegal class name (null)"); throw new IllegalArgumentException("Illegal class name (null)");
@ -345,6 +353,20 @@ public class CheckClassAdapter extends ClassVisitor {
super.visitNestMember(nestMember); 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 @Override
public void visitOuterClass(final String owner, final String name, final String descriptor) { public void visitOuterClass(final String owner, final String name, final String descriptor) {
checkState(); checkState();
@ -393,6 +415,19 @@ public class CheckClassAdapter extends ClassVisitor {
super.visitInnerClass(name, outerName, innerName, access); 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 @Override
public FieldVisitor visitField( public FieldVisitor visitField(
final int access, final int access,
@ -412,6 +447,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_TRANSIENT | Opcodes.ACC_TRANSIENT
| Opcodes.ACC_SYNTHETIC | Opcodes.ACC_SYNTHETIC
| Opcodes.ACC_ENUM | Opcodes.ACC_ENUM
| Opcodes.ACC_MANDATED
| Opcodes.ACC_DEPRECATED); | Opcodes.ACC_DEPRECATED);
CheckMethodAdapter.checkUnqualifiedName(version, name, "field name"); CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false); CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
@ -446,6 +482,7 @@ public class CheckClassAdapter extends ClassVisitor {
| Opcodes.ACC_ABSTRACT | Opcodes.ACC_ABSTRACT
| Opcodes.ACC_STRICT | Opcodes.ACC_STRICT
| Opcodes.ACC_SYNTHETIC | Opcodes.ACC_SYNTHETIC
| Opcodes.ACC_MANDATED
| Opcodes.ACC_DEPRECATED); | Opcodes.ACC_DEPRECATED);
if (!"<init>".equals(name) && !"<clinit>".equals(name)) { if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
CheckMethodAdapter.checkMethodIdentifier(version, name, "method 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. * @throws IOException if the class cannot be found, or if an IO exception occurs.
*/ */
public static void main(final String[] args) throws IOException { 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) { if (args.length != 1) {
System.err.println( logger.println(USAGE);
"Verifies the given class.\n"
+ "Usage: CheckClassAdapter <fully qualified class name or class file name>");
return; return;
} }
@ -995,7 +1041,7 @@ public class CheckClassAdapter extends ClassVisitor {
classReader = new ClassReader(args[0]); 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 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. * @param printWriter where the results (or the stack trace in case of error) must be printed.
*/ */
@SuppressWarnings("deprecation")
public static void verify( public static void verify(
final ClassReader classReader, final ClassReader classReader,
final ClassLoader loader, final ClassLoader loader,
@ -1026,12 +1073,13 @@ public class CheckClassAdapter extends ClassVisitor {
final PrintWriter printWriter) { final PrintWriter printWriter) {
ClassNode classNode = new ClassNode(); ClassNode classNode = new ClassNode();
classReader.accept( 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); Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
List<MethodNode> methods = classNode.methods; List<MethodNode> methods = classNode.methods;
List<Type> interfaces = new ArrayList<Type>(); List<Type> interfaces = new ArrayList<>();
for (String interfaceName : classNode.interfaces) { for (String interfaceName : classNode.interfaces) {
interfaces.add(Type.getObjectType(interfaceName)); interfaces.add(Type.getObjectType(interfaceName));
} }
@ -1043,7 +1091,7 @@ public class CheckClassAdapter extends ClassVisitor {
syperType, syperType,
interfaces, interfaces,
(classNode.access & Opcodes.ACC_INTERFACE) != 0); (classNode.access & Opcodes.ACC_INTERFACE) != 0);
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier); Analyzer<BasicValue> analyzer = new Analyzer<>(verifier);
if (loader != null) { if (loader != null) {
verifier.setClassLoader(loader); verifier.setClassLoader(loader);
} }

View file

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

View file

@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.util;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -397,7 +398,7 @@ public class CheckMethodAdapter extends MethodVisitor {
*/ */
public CheckMethodAdapter( public CheckMethodAdapter(
final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) { final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
this(Opcodes.ASM7, methodVisitor, labelInsnIndices); this(/* latest api = */ Opcodes.ASM8, methodVisitor, labelInsnIndices);
if (getClass() != CheckMethodAdapter.class) { if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -408,7 +409,8 @@ public class CheckMethodAdapter extends MethodVisitor {
* data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}). * 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 * @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 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 * @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. * (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) { final Map<Label, Integer> labelInsnIndices) {
super(api, methodVisitor); super(api, methodVisitor);
this.labelInsnIndices = labelInsnIndices; this.labelInsnIndices = labelInsnIndices;
this.referencedLabels = new HashSet<Label>(); this.referencedLabels = new HashSet<>();
this.handlers = new ArrayList<Label>(); this.handlers = new ArrayList<>();
} }
/** /**
@ -443,7 +445,8 @@ public class CheckMethodAdapter extends MethodVisitor {
final String descriptor, final String descriptor,
final MethodVisitor methodVisitor, final MethodVisitor methodVisitor,
final Map<Label, Integer> labelInsnIndices) { 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) { if (getClass() != CheckMethodAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -455,7 +458,8 @@ public class CheckMethodAdapter extends MethodVisitor {
* instruction IRETURN, or the invalid sequence IADD L2I will be detected. * 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 * @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 access the method's access flags.
* @param name the method's name. * @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}). * @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) { new MethodNode(api, access, name, descriptor, null, null) {
@Override @Override
public void visitEnd() { public void visitEnd() {
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier()); Analyzer<BasicValue> analyzer = new Analyzer<>(new BasicVerifier());
try { try {
analyzer.analyze("dummy", this); analyzer.analyze("dummy", this);
} catch (IndexOutOfBoundsException e) { } catch (IndexOutOfBoundsException e) {
@ -488,8 +492,10 @@ public class CheckMethodAdapter extends MethodVisitor {
} catch (AnalyzerException e) { } catch (AnalyzerException e) {
throwError(analyzer, e); throwError(analyzer, e);
} }
if (methodVisitor != null) {
accept(methodVisitor); accept(methodVisitor);
} }
}
private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) { private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
StringWriter stringWriter = new StringWriter(); StringWriter stringWriter = new StringWriter();
@ -735,42 +741,20 @@ public class CheckMethodAdapter extends MethodVisitor {
++insnCount; ++insnCount;
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override @Override
public void visitMethodInsn( public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) { final int opcodeAndSource,
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 owner,
final String name, final String name,
final String descriptor, final String descriptor,
final boolean isInterface) { final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); // Redirect the call to the deprecated version of this method.
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
return; 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(); checkVisitCodeCalled();
checkVisitMaxsNotCalled(); checkVisitMaxsNotCalled();
checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN); checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
@ -789,13 +773,7 @@ public class CheckMethodAdapter extends MethodVisitor {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"INVOKESPECIAL can't be used with interfaces prior to Java 8"); "INVOKESPECIAL can't be used with interfaces prior to Java 8");
} }
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, 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, owner, name, descriptor, isInterface);
}
++insnCount; ++insnCount;
} }
@ -879,9 +857,7 @@ public class CheckMethodAdapter extends MethodVisitor {
checkLabel(labels[i], false, "label at index " + i); checkLabel(labels[i], false, "label at index " + i);
} }
super.visitTableSwitchInsn(min, max, dflt, labels); super.visitTableSwitchInsn(min, max, dflt, labels);
for (Label label : labels) { Collections.addAll(referencedLabels, labels);
referencedLabels.add(label);
}
++insnCount; ++insnCount;
} }
@ -898,9 +874,7 @@ public class CheckMethodAdapter extends MethodVisitor {
} }
super.visitLookupSwitchInsn(dflt, keys, labels); super.visitLookupSwitchInsn(dflt, keys, labels);
referencedLabels.add(dflt); referencedLabels.add(dflt);
for (Label label : labels) { Collections.addAll(referencedLabels, labels);
referencedLabels.add(label);
}
++insnCount; ++insnCount;
} }
@ -997,6 +971,9 @@ public class CheckMethodAdapter extends MethodVisitor {
checkVisitMaxsNotCalled(); checkVisitMaxsNotCalled();
checkUnqualifiedName(version, name, "name"); checkUnqualifiedName(version, name, "name");
checkDescriptor(version, descriptor, false); checkDescriptor(version, descriptor, false);
if (signature != null) {
CheckClassAdapter.checkFieldSignature(signature);
}
checkLabel(start, true, START_LABEL); checkLabel(start, true, START_LABEL);
checkLabel(end, true, END_LABEL); checkLabel(end, true, END_LABEL);
checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX); checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
@ -1130,7 +1107,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|| value == Opcodes.NULL || value == Opcodes.NULL
|| value == Opcodes.UNINITIALIZED_THIS) { || value == Opcodes.UNINITIALIZED_THIS) {
return; return;
} else if (value instanceof String) { }
if (value instanceof String) {
checkInternalName(version, (String) value, "Invalid stack frame value"); checkInternalName(version, (String) value, "Invalid stack frame value");
} else if (value instanceof Label) { } else if (value instanceof Label) {
referencedLabels.add((Label) value); referencedLabels.add((Label) value);
@ -1314,7 +1292,7 @@ public class CheckMethodAdapter extends MethodVisitor {
* @param message the message to use in case of error. * @param message the message to use in case of error.
*/ */
static void checkMethodIdentifier(final int version, final String name, final String message) { 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); throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
} }
if ((version & 0xFFFF) >= Opcodes.V1_5) { 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. * @param message the message to use in case of error.
*/ */
static void checkInternalName(final int version, final String name, final String message) { 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); throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
} }
if (name.charAt(0) == '[') { if (name.charAt(0) == '[') {
@ -1370,10 +1348,10 @@ public class CheckMethodAdapter extends MethodVisitor {
int startIndex = 0; int startIndex = 0;
int slashIndex; int slashIndex;
while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) { while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
CheckMethodAdapter.checkIdentifier(version, name, startIndex, slashIndex, null); checkIdentifier(version, name, startIndex, slashIndex, null);
startIndex = slashIndex + 1; startIndex = slashIndex + 1;
} }
CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null); checkIdentifier(version, name, startIndex, name.length(), null);
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
INVALID + message + " (must be an internal class name): " + name, e); 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. * @param descriptor the string to be checked.
*/ */
static void checkMethodDescriptor(final int version, final String descriptor) { 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)"); throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
} }
if (descriptor.charAt(0) != '(' || descriptor.length() < 3) { if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {

View file

@ -102,7 +102,7 @@ public class CheckModuleAdapter extends ModuleVisitor {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) { public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
this(Opcodes.ASM7, moduleVisitor, isOpen); this(/* latest api = */ Opcodes.ASM8, moduleVisitor, isOpen);
if (getClass() != CheckModuleAdapter.class) { if (getClass() != CheckModuleAdapter.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -112,7 +112,8 @@ public class CheckModuleAdapter extends ModuleVisitor {
* Constructs a new {@link CheckModuleAdapter}. * Constructs a new {@link CheckModuleAdapter}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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 moduleVisitor the module visitor to which this adapter must delegate calls.
* @param isOpen whether the visited module is open. Open modules have their {@link * @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}. * 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) { NameSet(final String type) {
this.type = type; this.type = type;
this.names = new HashSet<String>(); this.names = new HashSet<>();
} }
void checkNameNotAlreadyDeclared(final String name) { void checkNameNotAlreadyDeclared(final String name) {
if (!names.add(name)) { if (!names.add(name)) {
throw new IllegalArgumentException(type + " " + name + " already declared"); throw new IllegalArgumentException(type + " '" + name + "' already declared");
} }
} }
} }

View file

@ -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");
}
}
}

View file

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

View file

@ -72,6 +72,7 @@ import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath; import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/** /**
* An abstract converter from visit events to text. * An abstract converter from visit events to text.
@ -326,13 +327,6 @@ public abstract class Printer {
*/ */
protected final int api; 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. */ /** The builder used to build strings in the various visit methods. */
protected final StringBuilder stringBuilder; protected final StringBuilder stringBuilder;
@ -360,9 +354,8 @@ public abstract class Printer {
*/ */
protected Printer(final int api) { protected Printer(final int api) {
this.api = api; this.api = api;
this.buf = null;
this.stringBuilder = new StringBuilder(); 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); 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}. * 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); 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}. * 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}. */ /** Annotation end. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnd}. */
public abstract void visitAnnotationEnd(); 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 // Fields
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -723,7 +805,7 @@ public abstract class Printer {
/** /**
* Method parameter. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}. * 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} * @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
* or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}). * or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
*/ */
@ -913,12 +995,10 @@ public abstract class Printer {
@Deprecated @Deprecated
public void visitMethodInsn( public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) { final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) { // This method was abstract before ASM5, and was therefore always overridden (without any
boolean isInterface = opcode == Opcodes.INVOKEINTERFACE; // call to 'super'). Thus, at this point we necessarily have api >= ASM5, and we must then
visitMethodInsn(opcode, owner, name, descriptor, isInterface); // redirect the method call to the ASM5 visitMethodInsn() method.
return; visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
} }
/** /**
@ -938,13 +1018,6 @@ public abstract class Printer {
final String name, final String name,
final String descriptor, final String descriptor,
final boolean isInterface) { 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); 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. * 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; * <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 usage the help message to show when command line arguments are incorrect.
* @param printer the printer to convert the class into text. * @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. * @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 { throws IOException {
if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) { if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) {
System.err.println(usage); logger.println(usage);
return; return;
} }
TraceClassVisitor traceClassVisitor = TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, output);
new TraceClassVisitor(null, printer, new PrintWriter(System.out));
String className; String className;
int parsingOptions; int parsingOptions;

View file

@ -59,7 +59,11 @@
package jdk.internal.org.objectweb.asm.util; package jdk.internal.org.objectweb.asm.util;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.Handle; import jdk.internal.org.objectweb.asm.Handle;
@ -77,6 +81,11 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader;
*/ */
public class Textifier extends Printer { 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}. */ /** The type of internal names. See {@link #appendDescriptor}. */
public static final int INTERNAL_NAME = 0; public static final int INTERNAL_NAME = 0;
@ -95,34 +104,17 @@ public class Textifier extends Printer {
/** The type of class signatures. See {@link #appendDescriptor}. */ /** The type of class signatures. See {@link #appendDescriptor}. */
public static final int CLASS_SIGNATURE = 5; 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}. */ /** The type of method handle descriptors. See {@link #appendDescriptor}. */
public static final int HANDLE_DESCRIPTOR = 9; public static final int HANDLE_DESCRIPTOR = 9;
private static final String CLASS_SUFFIX = ".class"; private static final String CLASS_SUFFIX = ".class";
private static final String DEPRECATED = "// DEPRECATED\n"; private static final String DEPRECATED = "// DEPRECATED\n";
private static final String RECORD = "// RECORD\n";
private static final String INVISIBLE = " // invisible\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). */ /** The indentation of class members at depth level 1 (e.g. fields, methods). */
protected String tab = " "; protected String tab = " ";
@ -151,7 +143,7 @@ public class Textifier extends Printer {
* @throws IllegalStateException If a subclass calls this constructor. * @throws IllegalStateException If a subclass calls this constructor.
*/ */
public Textifier() { public Textifier() {
this(Opcodes.ASM7); this(/* latest api = */ Opcodes.ASM8);
if (getClass() != Textifier.class) { if (getClass() != Textifier.class) {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -161,7 +153,8 @@ public class Textifier extends Printer {
* Constructs a new {@link Textifier}. * Constructs a new {@link Textifier}.
* *
* @param api the ASM API version implemented by this visitor. Must be one of {@link * @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) { protected Textifier(final int api) {
super(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. * @throws IOException if the class cannot be found, or if an IOException occurs.
*/ */
public static void main(final String[] args) throws IOException { public static void main(final String[] args) throws IOException {
String usage = main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
"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); /**
* 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) { if ((access & Opcodes.ACC_DEPRECATED) != 0) {
stringBuilder.append(DEPRECATED); stringBuilder.append(DEPRECATED);
} }
if ((access & Opcodes.ACC_RECORD) != 0) {
stringBuilder.append(RECORD);
}
appendRawAccess(access); appendRawAccess(access);
appendDescriptor(CLASS_SIGNATURE, signature); appendDescriptor(CLASS_SIGNATURE, signature);
@ -329,6 +337,22 @@ public class Textifier extends Printer {
text.add(stringBuilder.toString()); 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 @Override
public void visitInnerClass( public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) { 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()); 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 @Override
public Textifier visitField( public Textifier visitField(
final int access, final int access,
@ -482,30 +528,20 @@ public class Textifier extends Printer {
} }
@Override @Override
public void visitExport(final String export, final int access, final String... modules) { public void visitExport(final String packaze, final int access, final String... modules) {
stringBuilder.setLength(0); visitExportOrOpen("exports ", packaze, access, modules);
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());
} }
@Override @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.setLength(0);
stringBuilder.append(tab).append("opens "); stringBuilder.append(tab).append(method);
stringBuilder.append(export); stringBuilder.append(packaze);
if (modules != null && modules.length > 0) { if (modules != null && modules.length > 0) {
stringBuilder.append(" to"); stringBuilder.append(" to");
} else { } 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 // Fields
// ----------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------
@ -796,19 +857,7 @@ public class Textifier extends Printer {
@Override @Override
public void visitMethodAttribute(final Attribute attribute) { public void visitMethodAttribute(final Attribute attribute) {
stringBuilder.setLength(0); visitAttribute(attribute);
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());
} }
@Override @Override
@ -904,37 +953,8 @@ public class Textifier extends Printer {
text.add(stringBuilder.toString()); text.add(stringBuilder.toString());
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated
@Override @Override
public void visitMethodInsn( 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 int opcode,
final String owner, final String owner,
final String name, final String name,
@ -1261,10 +1281,11 @@ public class Textifier extends Printer {
stringBuilder.append(tab).append("ATTRIBUTE "); stringBuilder.append(tab).append("ATTRIBUTE ");
appendDescriptor(-1, attribute.type); appendDescriptor(-1, attribute.type);
if (attribute instanceof Textifiable) { if (attribute instanceof TextifierSupport) {
StringBuffer stringBuffer = new StringBuffer(); if (labelNames == null) {
((Textifiable) attribute).textify(stringBuffer, null); labelNames = new HashMap<>();
stringBuilder.append(stringBuffer.toString()); }
((TextifierSupport) attribute).textify(stringBuilder, labelNames);
} else { } else {
stringBuilder.append(" : unknown\n"); 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 * @param type the type of 'value'. Must be one of {@link #INTERNAL_NAME}, {@link
* #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link * #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link
* #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE}, {@link #TYPE_DECLARATION}, {@link * #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE} or {@link #HANDLE_DESCRIPTOR}.
* #CLASS_DECLARATION}, {@link #PARAMETERS_DECLARATION} of {@link #HANDLE_DESCRIPTOR}.
* @param value an internal name, type descriptor or a type signature. May be {@literal null}. * @param value an internal name, type descriptor or a type signature. May be {@literal null}.
*/ */
protected void appendDescriptor(final int type, final String value) { protected void appendDescriptor(final int type, final String value) {
@ -1384,7 +1404,7 @@ public class Textifier extends Printer {
*/ */
protected void appendLabel(final Label label) { protected void appendLabel(final Label label) {
if (labelNames == null) { if (labelNames == null) {
labelNames = new HashMap<Label, String>(); labelNames = new HashMap<>();
} }
String name = labelNames.get(label); String name = labelNames.get(label);
if (name == null) { if (name == null) {
@ -1587,31 +1607,7 @@ public class Textifier extends Printer {
appendDescriptor(INTERNAL_NAME, descriptor); appendDescriptor(INTERNAL_NAME, descriptor);
} }
} else if (frameTypes[i] instanceof Integer) { } else if (frameTypes[i] instanceof Integer) {
switch (((Integer) frameTypes[i]).intValue()) { stringBuilder.append(FRAME_TYPES.get(((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();
}
} else { } else {
appendLabel((Label) frameTypes[i]); appendLabel((Label) frameTypes[i]);
} }
@ -1639,6 +1635,6 @@ public class Textifier extends Printer {
* @return a new {@link Textifier}. * @return a new {@link Textifier}.
*/ */
protected Textifier createTextifier() { protected Textifier createTextifier() {
return new Textifier(); return new Textifier(api);
} }
} }

View file

@ -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);
}

View file

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

View file

@ -66,6 +66,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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.TypePath;
/** /**
@ -147,9 +148,10 @@ public final class TraceClassVisitor extends ClassVisitor {
* @param printer the printer to convert the visited class into text. * @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}. * @param printWriter the print writer to be used to print the class. May be {@literal null}.
*/ */
@SuppressWarnings("deprecation")
public TraceClassVisitor( public TraceClassVisitor(
final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) { final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) {
super(Opcodes.ASM7, classVisitor); super(/* latest api = */ Opcodes.ASM9_EXPERIMENTAL, classVisitor);
this.printWriter = printWriter; this.printWriter = printWriter;
this.p = printer; this.p = printer;
} }
@ -217,6 +219,19 @@ public final class TraceClassVisitor extends ClassVisitor {
super.visitNestMember(nestMember); 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 @Override
public void visitInnerClass( public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) { 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); 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 @Override
public FieldVisitor visitField( public FieldVisitor visitField(
final int access, final int access,

View file

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

View file

@ -93,7 +93,7 @@ public final class TraceMethodVisitor extends MethodVisitor {
* @param printer the printer to convert the visited method into text. * @param printer the printer to convert the visited method into text.
*/ */
public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) { public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) {
super(Opcodes.ASM7, methodVisitor); super(/* latest api = */ Opcodes.ASM8, methodVisitor);
this.p = printer; this.p = printer;
} }
@ -192,37 +192,27 @@ public final class TraceMethodVisitor extends MethodVisitor {
super.visitFieldInsn(opcode, owner, name, descriptor); 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 @Override
@SuppressWarnings("deprecation")
public void visitMethodInsn( public void visitMethodInsn(
final int opcode, final int opcode,
final String owner, final String owner,
final String name, final String name,
final String descriptor, final String descriptor,
final boolean isInterface) { final boolean isInterface) {
if (api < Opcodes.ASM5) { // Call the method that p is supposed to implement, depending on its api version.
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); if (p.api < Opcodes.ASM5) {
return; 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) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface); mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
} }

View file

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

View file

@ -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();
}
}

View file

@ -58,6 +58,9 @@
*/ */
package jdk.internal.org.objectweb.asm.util; 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.Opcodes;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; 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 EXTENDS_SEPARATOR = " extends ";
private static final String IMPLEMENTS_SEPARATOR = " implements "; 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. */ /** Whether the visited signature is a class signature of a Java interface. */
private final boolean isInterface; 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. * @param accessFlags for class type signatures, the access flags of the class.
*/ */
public TraceSignatureVisitor(final int accessFlags) { public TraceSignatureVisitor(final int accessFlags) {
super(Opcodes.ASM7); super(/* latest api = */ Opcodes.ASM8);
this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0; this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0;
this.declaration = new StringBuilder(); this.declaration = new StringBuilder();
} }
private TraceSignatureVisitor(final StringBuilder stringBuilder) { private TraceSignatureVisitor(final StringBuilder stringBuilder) {
super(Opcodes.ASM7); super(/* latest api = */ Opcodes.ASM8);
this.isInterface = false; this.isInterface = false;
this.declaration = stringBuilder; this.declaration = stringBuilder;
} }
@ -212,37 +231,11 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
@Override @Override
public void visitBaseType(final char descriptor) { public void visitBaseType(final char descriptor) {
switch (descriptor) { String baseType = BASE_TYPES.get(descriptor);
case 'V': if (baseType == null) {
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(); throw new IllegalArgumentException();
} }
declaration.append(baseType);
endType(); endType();
} }

View file

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

View file

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

View file

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

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 { static abstract class AbstractVisitor extends ClassVisitor {
final String nameOfMethodToAdd; final String nameOfMethodToAdd;
AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) { AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) {
super(ASM7, cv); super(ASM8, cv);
this.nameOfMethodToAdd = nameOfMethodToAdd; this.nameOfMethodToAdd = nameOfMethodToAdd;
} }
@Override @Override

View file

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -237,7 +237,7 @@ public class SerialPersistentFieldsTest {
final ObjectStreamField[] spf; final ObjectStreamField[] spf;
String className; String className;
SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) { SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) {
super(ASM7, cv); super(ASM8, cv);
this.spf = spf; this.spf = spf;
} }
@Override @Override