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:
parent
c7ae195a03
commit
78a0baa57c
src/java.base/share
classes/jdk/internal/org/objectweb/asm
AnnotationVisitor.javaAnnotationWriter.javaAttribute.javaClassReader.javaClassVisitor.javaClassWriter.javaConstants.javaFieldVisitor.javaFieldWriter.javaFrame.javaLabel.javaMethodVisitor.javaMethodWriter.javaModuleVisitor.javaModuleWriter.javaOpcodes.javaRecordComponentVisitor.javaRecordComponentWriter.javaSymbolTable.javaType.javaTypePath.java
commons
AdviceAdapter.javaAnalyzerAdapter.javaAnnotationRemapper.javaClassRemapper.javaCodeSizeEvaluator.javaFieldRemapper.javaGeneratorAdapter.javaInstructionAdapter.javaJSRInlinerAdapter.javaLocalVariablesSorter.javaMethod.javaMethodRemapper.javaModuleHashesAttribute.javaModuleRemapper.javaRecordComponentRemapper.javaRemapper.javaSerialVersionUIDAdder.javaSignatureRemapper.javaStaticInitMerger.javaTryCatchBlockSorter.java
signature
tree
AbstractInsnNode.javaAnnotationNode.javaClassNode.javaFieldNode.javaFrameNode.javaInsnList.javaLocalVariableAnnotationNode.javaMethodInsnNode.javaMethodNode.javaModuleNode.javaRecordComponentNode.javaTypeAnnotationNode.javaUtil.java
analysis
util
ASMifier.javaASMifierSupport.javaCheckAnnotationAdapter.javaCheckClassAdapter.javaCheckFieldAdapter.javaCheckMethodAdapter.javaCheckModuleAdapter.javaCheckRecordComponentAdapter.javaCheckSignatureAdapter.javaPrinter.javaTextifier.javaTextifierSupport.javaTraceAnnotationVisitor.javaTraceClassVisitor.javaTraceFieldVisitor.javaTraceMethodVisitor.javaTraceModuleVisitor.javaTraceRecordComponentVisitor.javaTraceSignatureVisitor.java
version.txtlegal
test/jdk/java/io/Serializable/records
@ -74,7 +74,10 @@ public abstract class AnnotationVisitor {
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
|
||||
/**
|
||||
* The annotation visitor to which this visitor must delegate method calls. May be {@literal
|
||||
* null}.
|
||||
*/
|
||||
protected AnnotationVisitor av;
|
||||
|
||||
/**
|
||||
@ -93,11 +96,20 @@ public abstract class AnnotationVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* @param annotationVisitor the annotation visitor to which this visitor must delegate method
|
||||
* calls. May be null.
|
||||
* calls. May be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
if (api == Opcodes.ASM9_EXPERIMENTAL) {
|
||||
Constants.checkAsmExperimental(this);
|
||||
}
|
||||
this.api = api;
|
||||
this.av = annotationVisitor;
|
||||
|
@ -122,7 +122,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
private AnnotationWriter nextAnnotation;
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// Constructors and factories
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@ -135,15 +135,15 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
* the visited content must be stored. This ByteVector must already contain all the fields of
|
||||
* the structure except the last one (the element_value_pairs array).
|
||||
* @param previousAnnotation the previously visited annotation of the
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
|
||||
* other cases (e.g. nested or array annotations).
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
|
||||
* {@literal null} in other cases (e.g. nested or array annotations).
|
||||
*/
|
||||
AnnotationWriter(
|
||||
final SymbolTable symbolTable,
|
||||
final boolean useNamedValues,
|
||||
final ByteVector annotation,
|
||||
final AnnotationWriter previousAnnotation) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.symbolTable = symbolTable;
|
||||
this.useNamedValues = useNamedValues;
|
||||
this.annotation = annotation;
|
||||
@ -156,21 +156,61 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationWriter} using named values.
|
||||
* Creates a new {@link AnnotationWriter} using named values.
|
||||
*
|
||||
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
|
||||
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
|
||||
* the visited content must be stored. This ByteVector must already contain all the fields of
|
||||
* the structure except the last one (the element_value_pairs array).
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param previousAnnotation the previously visited annotation of the
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
|
||||
* other cases (e.g. nested or array annotations).
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
|
||||
* {@literal null} in other cases (e.g. nested or array annotations).
|
||||
* @return a new {@link AnnotationWriter} for the given annotation descriptor.
|
||||
*/
|
||||
AnnotationWriter(
|
||||
static AnnotationWriter create(
|
||||
final SymbolTable symbolTable,
|
||||
final ByteVector annotation,
|
||||
final String descriptor,
|
||||
final AnnotationWriter previousAnnotation) {
|
||||
this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
return new AnnotationWriter(
|
||||
symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AnnotationWriter} using named values.
|
||||
*
|
||||
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
|
||||
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
|
||||
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
|
||||
* 'typeRef' as a whole.
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param previousAnnotation the previously visited annotation of the
|
||||
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or
|
||||
* {@literal null} in other cases (e.g. nested or array annotations).
|
||||
* @return a new {@link AnnotationWriter} for the given type annotation reference and descriptor.
|
||||
*/
|
||||
static AnnotationWriter create(
|
||||
final SymbolTable symbolTable,
|
||||
final int typeRef,
|
||||
final TypePath typePath,
|
||||
final String descriptor,
|
||||
final AnnotationWriter previousAnnotation) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
return new AnnotationWriter(
|
||||
symbolTable, /* useNamedValues = */ true, typeAnnotation, previousAnnotation);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -275,7 +315,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
}
|
||||
// Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
|
||||
annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
return new AnnotationWriter(symbolTable, annotation, null);
|
||||
return new AnnotationWriter(symbolTable, /* useNamedValues = */ true, annotation, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -315,7 +355,7 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
* and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
|
||||
* to the constant pool of the class (if not null).
|
||||
*
|
||||
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
|
||||
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or {@literal null}.
|
||||
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
|
||||
* annotation and all its predecessors. This includes the size of the attribute_name_index and
|
||||
* attribute_length fields.
|
||||
@ -334,6 +374,56 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
return attributeSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the Runtime[In]Visible[Type]Annotations attributes containing the given
|
||||
* annotations and all their <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the
|
||||
* attribute names to the constant pool of the class (if not null).
|
||||
*
|
||||
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or
|
||||
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be
|
||||
* {@literal null}.
|
||||
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field,
|
||||
* method or class. The previous ones can be accessed with the {@link #previousAnnotation}
|
||||
* field. May be {@literal null}.
|
||||
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a
|
||||
* field, method or class. The previous ones can be accessed with the {@link
|
||||
* #previousAnnotation} field. May be {@literal null}.
|
||||
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a
|
||||
* field, method or class field. The previous ones can be accessed with the {@link
|
||||
* #previousAnnotation} field. May be {@literal null}.
|
||||
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing the
|
||||
* given annotations and all their predecessors. This includes the size of the
|
||||
* attribute_name_index and attribute_length fields.
|
||||
*/
|
||||
static int computeAnnotationsSize(
|
||||
final AnnotationWriter lastRuntimeVisibleAnnotation,
|
||||
final AnnotationWriter lastRuntimeInvisibleAnnotation,
|
||||
final AnnotationWriter lastRuntimeVisibleTypeAnnotation,
|
||||
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation) {
|
||||
int size = 0;
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
|
||||
* <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
|
||||
@ -366,6 +456,51 @@ final class AnnotationWriter extends AnnotationVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts the Runtime[In]Visible[Type]Annotations attributes containing the given annotations and
|
||||
* all their <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector.
|
||||
* Annotations are put in the same order they have been visited.
|
||||
*
|
||||
* @param symbolTable where the constants used in the AnnotationWriter instances are stored.
|
||||
* @param lastRuntimeVisibleAnnotation The last runtime visible annotation of a field, method or
|
||||
* class. The previous ones can be accessed with the {@link #previousAnnotation} field. May be
|
||||
* {@literal null}.
|
||||
* @param lastRuntimeInvisibleAnnotation The last runtime invisible annotation of this a field,
|
||||
* method or class. The previous ones can be accessed with the {@link #previousAnnotation}
|
||||
* field. May be {@literal null}.
|
||||
* @param lastRuntimeVisibleTypeAnnotation The last runtime visible type annotation of this a
|
||||
* field, method or class. The previous ones can be accessed with the {@link
|
||||
* #previousAnnotation} field. May be {@literal null}.
|
||||
* @param lastRuntimeInvisibleTypeAnnotation The last runtime invisible type annotation of a
|
||||
* field, method or class field. The previous ones can be accessed with the {@link
|
||||
* #previousAnnotation} field. May be {@literal null}.
|
||||
* @param output where the attributes must be put.
|
||||
*/
|
||||
static void putAnnotations(
|
||||
final SymbolTable symbolTable,
|
||||
final AnnotationWriter lastRuntimeVisibleAnnotation,
|
||||
final AnnotationWriter lastRuntimeInvisibleAnnotation,
|
||||
final AnnotationWriter lastRuntimeVisibleTypeAnnotation,
|
||||
final AnnotationWriter lastRuntimeInvisibleTypeAnnotation,
|
||||
final ByteVector output) {
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
lastRuntimeVisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
lastRuntimeInvisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
lastRuntimeVisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
|
||||
* annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
|
||||
|
@ -59,7 +59,7 @@
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
/**
|
||||
* A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
|
||||
* A non standard class, field, method or Code attribute, as defined in the Java Virtual Machine
|
||||
* Specification (JVMS).
|
||||
*
|
||||
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
|
||||
@ -83,7 +83,7 @@ public class Attribute {
|
||||
|
||||
/**
|
||||
* The next attribute in this attribute list (Attribute instances can be linked via this field to
|
||||
* store a list of class, field, method or code attributes). May be {@literal null}.
|
||||
* store a list of class, field, method or Code attributes). May be {@literal null}.
|
||||
*/
|
||||
Attribute nextAttribute;
|
||||
|
||||
@ -111,9 +111,9 @@ public class Attribute {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@literal true} if this type of attribute is a code attribute.
|
||||
* Returns {@literal true} if this type of attribute is a Code attribute.
|
||||
*
|
||||
* @return {@literal true} if this type of attribute is a code attribute.
|
||||
* @return {@literal true} if this type of attribute is a Code attribute.
|
||||
*/
|
||||
public boolean isCodeAttribute() {
|
||||
return false;
|
||||
@ -123,7 +123,7 @@ public class Attribute {
|
||||
* Returns the labels corresponding to this attribute.
|
||||
*
|
||||
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
|
||||
* a code attribute that contains labels.
|
||||
* a Code attribute that contains labels.
|
||||
*/
|
||||
protected Label[] getLabels() {
|
||||
return new Label[0];
|
||||
@ -135,18 +135,18 @@ public class Attribute {
|
||||
* ClassReader.
|
||||
*
|
||||
* @param classReader the class that contains the attribute to be read.
|
||||
* @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
|
||||
* 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
|
||||
* @param offset index of the first byte of the attribute's content in {@link ClassReader}. The 6
|
||||
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
|
||||
* account here.
|
||||
* @param length the length of the attribute's content (excluding the 6 attribute header bytes).
|
||||
* @param charBuffer the buffer to be used to call the ClassReader methods requiring a
|
||||
* 'charBuffer' parameter.
|
||||
* @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
|
||||
* in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
|
||||
* in {@link ClassReader}, or -1 if the attribute to be read is not a Code attribute. The 6
|
||||
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
|
||||
* account here.
|
||||
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read
|
||||
* is not a code attribute.
|
||||
* is not a Code attribute.
|
||||
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
|
||||
*/
|
||||
protected Attribute read(
|
||||
@ -158,7 +158,7 @@ public class Attribute {
|
||||
final Label[] labels) {
|
||||
Attribute attribute = new Attribute(type);
|
||||
attribute.content = new byte[length];
|
||||
System.arraycopy(classReader.b, offset, attribute.content, 0, length);
|
||||
System.arraycopy(classReader.classFileBuffer, offset, attribute.content, 0, length);
|
||||
return attribute;
|
||||
}
|
||||
|
||||
@ -169,16 +169,16 @@ public class Attribute {
|
||||
*
|
||||
* @param classWriter the class to which this attribute must be added. This parameter can be used
|
||||
* to add the items that corresponds to this attribute to the constant pool of this class.
|
||||
* @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
|
||||
* if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
|
||||
* @param code the bytecode of the method corresponding to this Code attribute, or {@literal null}
|
||||
* if this attribute is not a Code attribute. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to this code
|
||||
* attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
|
||||
* attribute, or 0 if this attribute is not a Code attribute. Corresponds to the 'code_length'
|
||||
* field of the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or
|
||||
* -1 if this attribute is not a code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to this Code attribute, or
|
||||
* -1 if this attribute is not a Code attribute.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to this code
|
||||
* attribute, or -1 if this attribute is not a code attribute.
|
||||
* attribute, or -1 if this attribute is not a Code attribute.
|
||||
* @return the byte array form of this attribute.
|
||||
*/
|
||||
protected ByteVector write(
|
||||
@ -228,16 +228,16 @@ public class Attribute {
|
||||
* attribute_length) per attribute. Also adds the attribute type names to the constant pool.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
|
||||
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
|
||||
* @param code the bytecode of the method corresponding to these Code attributes, or {@literal
|
||||
* null} if they are not Code attributes. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to these code
|
||||
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
|
||||
* attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of
|
||||
* the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
|
||||
* -1 if they are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
|
||||
* -1 if they are not Code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these
|
||||
* code attributes, or -1 if they are not code attribute.
|
||||
* Code attributes, or -1 if they are not Code attribute.
|
||||
* @return the size of all the attributes in this attribute list. This size includes the size of
|
||||
* the attribute headers.
|
||||
*/
|
||||
@ -258,6 +258,42 @@ public class Attribute {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total size in bytes of all the attributes that correspond to the given field,
|
||||
* method or class access flags and signature. This size includes the 6 header bytes
|
||||
* (attribute_name_index and attribute_length) per attribute. Also adds the attribute type names
|
||||
* to the constant pool.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param accessFlags some field, method or class access flags.
|
||||
* @param signatureIndex the constant pool index of a field, method of class signature.
|
||||
* @return the size of all the attributes in bytes. This size includes the size of the attribute
|
||||
* headers.
|
||||
*/
|
||||
static int computeAttributesSize(
|
||||
final SymbolTable symbolTable, final int accessFlags, final int signatureIndex) {
|
||||
int size = 0;
|
||||
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
|
||||
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
|
||||
// Synthetic attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
|
||||
size += 6;
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
// Signature attributes always use 8 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SIGNATURE);
|
||||
size += 8;
|
||||
}
|
||||
// ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
// Deprecated attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.DEPRECATED);
|
||||
size += 6;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts all the attributes of the attribute list that begins with this attribute, in the given
|
||||
* byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
|
||||
@ -280,16 +316,16 @@ public class Attribute {
|
||||
* attribute.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
|
||||
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
|
||||
* @param code the bytecode of the method corresponding to these Code attributes, or {@literal
|
||||
* null} if they are not Code attributes. Corresponds to the 'code' field of the Code
|
||||
* attribute.
|
||||
* @param codeLength the length of the bytecode of the method corresponding to these code
|
||||
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
|
||||
* attributes, or 0 if they are not Code attributes. Corresponds to the 'code_length' field of
|
||||
* the Code attribute.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
|
||||
* -1 if they are not code attributes.
|
||||
* @param maxStack the maximum stack size of the method corresponding to these Code attributes, or
|
||||
* -1 if they are not Code attributes.
|
||||
* @param maxLocals the maximum number of local variables of the method corresponding to these
|
||||
* code attributes, or -1 if they are not code attribute.
|
||||
* Code attributes, or -1 if they are not Code attribute.
|
||||
* @param output where the attributes must be written.
|
||||
*/
|
||||
final void putAttributes(
|
||||
@ -311,6 +347,37 @@ public class Attribute {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts all the attributes that correspond to the given field, method or class access flags and
|
||||
* signature, in the given byte vector. This includes the 6 header bytes (attribute_name_index and
|
||||
* attribute_length) per attribute.
|
||||
*
|
||||
* @param symbolTable where the constants used in the attributes must be stored.
|
||||
* @param accessFlags some field, method or class access flags.
|
||||
* @param signatureIndex the constant pool index of a field, method of class signature.
|
||||
* @param output where the attributes must be written.
|
||||
*/
|
||||
static void putAttributes(
|
||||
final SymbolTable symbolTable,
|
||||
final int accessFlags,
|
||||
final int signatureIndex,
|
||||
final ByteVector output) {
|
||||
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
|
||||
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
|
||||
.putInt(2)
|
||||
.putShort(signatureIndex);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
/** A set of attribute prototypes (attributes with the same type are considered equal). */
|
||||
static final class Set {
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -61,9 +61,9 @@ package jdk.internal.org.objectweb.asm;
|
||||
/**
|
||||
* A visitor to visit a Java class. The methods of this class must be called in the following order:
|
||||
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
|
||||
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
|
||||
* visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
|
||||
* {@code visitMethod} )* {@code visitEnd}.
|
||||
* visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
|
||||
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
|
||||
* visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
@ -75,7 +75,7 @@ public abstract class ClassVisitor {
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The class visitor to which this visitor must delegate method calls. May be null. */
|
||||
/** The class visitor to which this visitor must delegate method calls. May be {@literal null}. */
|
||||
protected ClassVisitor cv;
|
||||
|
||||
/**
|
||||
@ -92,13 +92,23 @@ public abstract class ClassVisitor {
|
||||
* Constructs a new {@link ClassVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
if (api == Opcodes.ASM9_EXPERIMENTAL) {
|
||||
Constants.checkAsmExperimental(this);
|
||||
}
|
||||
this.api = api;
|
||||
this.cv = classVisitor;
|
||||
@ -110,7 +120,8 @@ public abstract class ClassVisitor {
|
||||
* @param version the class version. The minor version is stored in the 16 most significant bits,
|
||||
* and the major version in the 16 least significant bits.
|
||||
* @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
* the class is deprecated.
|
||||
* the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link
|
||||
* Opcodes#ACC_RECORD}.
|
||||
* @param name the internal name of the class (see {@link Type#getInternalName()}).
|
||||
* @param signature the signature of this class. May be {@literal null} if the class is not a
|
||||
* generic one, and does not extend or implement generic classes or interfaces.
|
||||
@ -127,6 +138,9 @@ public abstract class ClassVisitor {
|
||||
final String signature,
|
||||
final String superName,
|
||||
final String[] interfaces) {
|
||||
if (api < Opcodes.ASM8 && (access & Opcodes.ACC_RECORD) != 0) {
|
||||
throw new UnsupportedOperationException("Records requires ASM8");
|
||||
}
|
||||
if (cv != null) {
|
||||
cv.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
@ -271,6 +285,24 @@ public abstract class ClassVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
|
||||
* of the allowed subtypes of the current class.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
if (api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
|
||||
}
|
||||
if (cv != null) {
|
||||
cv.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits information about an inner class. This inner class is not necessarily a member of the
|
||||
* class being visited.
|
||||
@ -290,6 +322,27 @@ public abstract class ClassVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a record component of the class.
|
||||
*
|
||||
* @param name the record component name.
|
||||
* @param descriptor the record component descriptor (see {@link Type}).
|
||||
* @param signature the record component signature. May be {@literal null} if the record component
|
||||
* type does not use generic types.
|
||||
* @return a visitor to visit this record component annotations and attributes, or {@literal null}
|
||||
* if this class visitor is not interested in visiting these annotations and attributes.
|
||||
*/
|
||||
public RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
if (api < Opcodes.ASM8) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM8");
|
||||
}
|
||||
if (cv != null) {
|
||||
return cv.visitRecordComponent(name, descriptor, signature);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a field of the class.
|
||||
*
|
||||
|
@ -110,8 +110,8 @@ public class ClassWriter extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* The access_flags field of the JVMS ClassFile structure. This field can contain ASM specific
|
||||
* access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
|
||||
* ClassFile structure.
|
||||
* access flags, such as {@link Opcodes#ACC_DEPRECATED} or {}@link Opcodes#ACC_RECORD}, which are
|
||||
* removed when generating the ClassFile structure.
|
||||
*/
|
||||
private int accessFlags;
|
||||
|
||||
@ -208,6 +208,26 @@ public class ClassWriter extends ClassVisitor {
|
||||
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */
|
||||
private ByteVector nestMemberClasses;
|
||||
|
||||
/** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
|
||||
private int numberOfPermittedSubtypeClasses;
|
||||
|
||||
/** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
|
||||
private ByteVector permittedSubtypeClasses;
|
||||
|
||||
/**
|
||||
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
|
||||
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the first
|
||||
* element of this list.
|
||||
*/
|
||||
private RecordComponentWriter firstRecordComponent;
|
||||
|
||||
/**
|
||||
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
|
||||
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the last
|
||||
* element of this list.
|
||||
*/
|
||||
private RecordComponentWriter lastRecordComponent;
|
||||
|
||||
/**
|
||||
* The first non standard attribute of this class. The next ones can be accessed with the {@link
|
||||
* Attribute#nextAttribute} field. May be {@literal null}.
|
||||
@ -265,7 +285,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
* maximum stack size nor the stack frames will be computed for these methods</i>.
|
||||
*/
|
||||
public ClassWriter(final ClassReader classReader, final int flags) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
|
||||
if ((flags & COMPUTE_FRAMES) != 0) {
|
||||
this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
|
||||
@ -329,7 +349,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestHost(final String nestHost) {
|
||||
public final void visitNestHost(final String nestHost) {
|
||||
nestHostClassIndex = symbolTable.addConstantClass(nestHost).index;
|
||||
}
|
||||
|
||||
@ -344,37 +364,26 @@ public class ClassWriter extends ClassVisitor {
|
||||
|
||||
@Override
|
||||
public final AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,7 +395,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestMember(final String nestMember) {
|
||||
public final void visitNestMember(final String nestMember) {
|
||||
if (nestMemberClasses == null) {
|
||||
nestMemberClasses = new ByteVector();
|
||||
}
|
||||
@ -394,6 +403,22 @@ public class ClassWriter extends ClassVisitor {
|
||||
nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
if (permittedSubtypeClasses == null) {
|
||||
permittedSubtypeClasses = new ByteVector();
|
||||
}
|
||||
++numberOfPermittedSubtypeClasses;
|
||||
permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void visitInnerClass(
|
||||
final String name, final String outerName, final String innerName, final int access) {
|
||||
@ -419,6 +444,19 @@ public class ClassWriter extends ClassVisitor {
|
||||
// and throw an exception if there is a difference?
|
||||
}
|
||||
|
||||
@Override
|
||||
public final RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
RecordComponentWriter recordComponentWriter =
|
||||
new RecordComponentWriter(symbolTable, name, descriptor, signature);
|
||||
if (firstRecordComponent == null) {
|
||||
firstRecordComponent = recordComponentWriter;
|
||||
} else {
|
||||
lastRecordComponent.delegate = recordComponentWriter;
|
||||
}
|
||||
return lastRecordComponent = recordComponentWriter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final FieldVisitor visitField(
|
||||
final int access,
|
||||
@ -469,7 +507,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
* @throws ClassTooLargeException if the constant pool of the class is too large.
|
||||
* @throws MethodTooLargeException if the Code attribute of a method is too large.
|
||||
*/
|
||||
public byte[] toByteArray() throws ClassTooLargeException, MethodTooLargeException {
|
||||
public byte[] toByteArray() {
|
||||
// First step: compute the size in bytes of the ClassFile structure.
|
||||
// The magic field uses 4 bytes, 10 mandatory fields (minor_version, major_version,
|
||||
// constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count,
|
||||
@ -489,6 +527,7 @@ public class ClassWriter extends ClassVisitor {
|
||||
size += methodWriter.computeMethodInfoSize();
|
||||
methodWriter = (MethodWriter) methodWriter.mv;
|
||||
}
|
||||
|
||||
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
|
||||
int attributesCount = 0;
|
||||
if (innerClasses != null) {
|
||||
@ -568,6 +607,24 @@ public class ClassWriter extends ClassVisitor {
|
||||
size += 8 + nestMemberClasses.length;
|
||||
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
|
||||
}
|
||||
if (permittedSubtypeClasses != null) {
|
||||
++attributesCount;
|
||||
size += 8 + permittedSubtypeClasses.length;
|
||||
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
|
||||
}
|
||||
int recordComponentCount = 0;
|
||||
int recordSize = 0;
|
||||
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
|
||||
RecordComponentWriter recordComponentWriter = firstRecordComponent;
|
||||
while (recordComponentWriter != null) {
|
||||
++recordComponentCount;
|
||||
recordSize += recordComponentWriter.computeRecordComponentInfoSize();
|
||||
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
|
||||
}
|
||||
++attributesCount;
|
||||
size += 8 + recordSize;
|
||||
symbolTable.addConstantUtf8(Constants.RECORD);
|
||||
}
|
||||
if (firstAttribute != null) {
|
||||
attributesCount += firstAttribute.getAttributeCount();
|
||||
size += firstAttribute.computeAttributesSize(symbolTable);
|
||||
@ -648,22 +705,13 @@ public class ClassWriter extends ClassVisitor {
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
result.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
|
||||
}
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
lastRuntimeVisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), result);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
lastRuntimeInvisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), result);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
lastRuntimeVisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), result);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), result);
|
||||
}
|
||||
AnnotationWriter.putAnnotations(
|
||||
symbolTable,
|
||||
lastRuntimeVisibleAnnotation,
|
||||
lastRuntimeInvisibleAnnotation,
|
||||
lastRuntimeVisibleTypeAnnotation,
|
||||
lastRuntimeInvisibleTypeAnnotation,
|
||||
result);
|
||||
symbolTable.putBootstrapMethods(result);
|
||||
if (moduleWriter != null) {
|
||||
moduleWriter.putAttributes(result);
|
||||
@ -681,6 +729,24 @@ public class ClassWriter extends ClassVisitor {
|
||||
.putShort(numberOfNestMemberClasses)
|
||||
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
|
||||
}
|
||||
if (permittedSubtypeClasses != null) {
|
||||
result
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
|
||||
.putInt(permittedSubtypeClasses.length + 2)
|
||||
.putShort(numberOfPermittedSubtypeClasses)
|
||||
.putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_RECORD) != 0 || firstRecordComponent != null) {
|
||||
result
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.RECORD))
|
||||
.putInt(recordSize + 2)
|
||||
.putShort(recordComponentCount);
|
||||
RecordComponentWriter recordComponentWriter = firstRecordComponent;
|
||||
while (recordComponentWriter != null) {
|
||||
recordComponentWriter.putRecordComponentInfo(result);
|
||||
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
|
||||
}
|
||||
}
|
||||
if (firstAttribute != null) {
|
||||
firstAttribute.putAttributes(symbolTable, result);
|
||||
}
|
||||
@ -717,6 +783,10 @@ public class ClassWriter extends ClassVisitor {
|
||||
nestHostClassIndex = 0;
|
||||
numberOfNestMemberClasses = 0;
|
||||
nestMemberClasses = null;
|
||||
numberOfPermittedSubtypeClasses = 0;
|
||||
permittedSubtypeClasses = null;
|
||||
firstRecordComponent = null;
|
||||
lastRecordComponent = null;
|
||||
firstAttribute = null;
|
||||
compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
|
||||
new ClassReader(classFile, 0, /* checkClassVersion = */ false)
|
||||
@ -745,6 +815,11 @@ public class ClassWriter extends ClassVisitor {
|
||||
methodWriter.collectAttributePrototypes(attributePrototypes);
|
||||
methodWriter = (MethodWriter) methodWriter.mv;
|
||||
}
|
||||
RecordComponentWriter recordComponentWriter = firstRecordComponent;
|
||||
while (recordComponentWriter != null) {
|
||||
recordComponentWriter.collectAttributePrototypes(attributePrototypes);
|
||||
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
|
||||
}
|
||||
return attributePrototypes.toArray();
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,11 @@
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
|
||||
* API.
|
||||
@ -65,7 +70,7 @@ package jdk.internal.org.objectweb.asm;
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
final class Constants implements Opcodes {
|
||||
final class Constants {
|
||||
|
||||
// The ClassFile attribute names, in the order they are defined in
|
||||
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
|
||||
@ -99,6 +104,8 @@ final class Constants implements Opcodes {
|
||||
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
|
||||
static final String NEST_HOST = "NestHost";
|
||||
static final String NEST_MEMBERS = "NestMembers";
|
||||
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
|
||||
static final String RECORD = "Record";
|
||||
|
||||
// ASM specific access flags.
|
||||
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
|
||||
@ -171,7 +178,7 @@ final class Constants implements Opcodes {
|
||||
// Constants to convert between normal and wide jump instructions.
|
||||
|
||||
// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
|
||||
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
|
||||
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO;
|
||||
|
||||
// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
|
||||
|
||||
@ -184,25 +191,62 @@ final class Constants implements Opcodes {
|
||||
|
||||
// ASM specific opcodes, used for long forward jump instructions.
|
||||
|
||||
static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
|
||||
static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
|
||||
static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
|
||||
static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
|
||||
static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
|
||||
static final int ASM_GOTO_W = 220;
|
||||
|
||||
private Constants() {}
|
||||
|
||||
static void checkAsmExperimental(final Object caller) {
|
||||
Class<?> callerClass = caller.getClass();
|
||||
String internalName = callerClass.getName().replace('.', '/');
|
||||
if (!isWhitelisted(internalName)) {
|
||||
checkIsPreview(callerClass.getClassLoader().getResourceAsStream(internalName + ".class"));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isWhitelisted(final String internalName) {
|
||||
if (!internalName.startsWith("jdk/internal/org/objectweb/asm/")) {
|
||||
return false;
|
||||
}
|
||||
String member = "(Annotation|Class|Field|Method|Module|RecordComponent|Signature)";
|
||||
return internalName.contains("Test$")
|
||||
|| Pattern.matches(
|
||||
"jdk/internal/org/objectweb/asm/util/Trace" + member + "Visitor(\\$.*)?", internalName)
|
||||
|| Pattern.matches(
|
||||
"jdk/internal/org/objectweb/asm/util/Check" + member + "Adapter(\\$.*)?", internalName);
|
||||
}
|
||||
|
||||
static void checkIsPreview(final InputStream classInputStream) {
|
||||
if (classInputStream == null) {
|
||||
throw new IllegalStateException("Bytecode not available, can't check class version");
|
||||
}
|
||||
int minorVersion;
|
||||
try (DataInputStream callerClassStream = new DataInputStream(classInputStream); ) {
|
||||
callerClassStream.readInt();
|
||||
minorVersion = callerClassStream.readUnsignedShort();
|
||||
} catch (IOException ioe) {
|
||||
throw new IllegalStateException("I/O error, can't check class version", ioe);
|
||||
}
|
||||
if (minorVersion != 0xFFFF) {
|
||||
throw new IllegalStateException(
|
||||
"ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -69,18 +69,20 @@ public abstract class FieldVisitor {
|
||||
|
||||
/**
|
||||
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The field visitor to which this visitor must delegate method calls. May be null. */
|
||||
/** The field visitor to which this visitor must delegate method calls. May be {@literal null}. */
|
||||
protected FieldVisitor fv;
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
*/
|
||||
public FieldVisitor(final int api) {
|
||||
this(api, null);
|
||||
@ -90,13 +92,23 @@ public abstract class FieldVisitor {
|
||||
* Constructs a new {@link FieldVisitor}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param fieldVisitor the field visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
if (api == Opcodes.ASM9_EXPERIMENTAL) {
|
||||
Constants.checkAsmExperimental(this);
|
||||
}
|
||||
this.api = api;
|
||||
this.fv = fieldVisitor;
|
||||
|
@ -155,7 +155,7 @@ final class FieldWriter extends FieldVisitor {
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final Object constantValue) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.symbolTable = symbolTable;
|
||||
this.accessFlags = access;
|
||||
this.nameIndex = symbolTable.addConstantUtf8(name);
|
||||
@ -174,37 +174,26 @@ final class FieldWriter extends FieldVisitor {
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,44 +228,13 @@ final class FieldWriter extends FieldVisitor {
|
||||
symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
|
||||
size += 8;
|
||||
}
|
||||
// Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
|
||||
&& symbolTable.getMajorVersion() < Opcodes.V1_5) {
|
||||
// Synthetic attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
|
||||
size += 6;
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
// Signature attributes always use 8 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.SIGNATURE);
|
||||
size += 8;
|
||||
}
|
||||
// ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
// Deprecated attributes always use 6 bytes.
|
||||
symbolTable.addConstantUtf8(Constants.DEPRECATED);
|
||||
size += 6;
|
||||
}
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
|
||||
size +=
|
||||
AnnotationWriter.computeAnnotationsSize(
|
||||
lastRuntimeVisibleAnnotation,
|
||||
lastRuntimeInvisibleAnnotation,
|
||||
lastRuntimeVisibleTypeAnnotation,
|
||||
lastRuntimeInvisibleTypeAnnotation);
|
||||
if (firstAttribute != null) {
|
||||
size += firstAttribute.computeAttributesSize(symbolTable);
|
||||
}
|
||||
@ -333,34 +291,14 @@ final class FieldWriter extends FieldVisitor {
|
||||
.putInt(2)
|
||||
.putShort(constantValueIndex);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
|
||||
.putInt(2)
|
||||
.putShort(signatureIndex);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
|
||||
}
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
lastRuntimeVisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
lastRuntimeInvisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
lastRuntimeVisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
|
||||
AnnotationWriter.putAnnotations(
|
||||
symbolTable,
|
||||
lastRuntimeVisibleAnnotation,
|
||||
lastRuntimeInvisibleAnnotation,
|
||||
lastRuntimeVisibleTypeAnnotation,
|
||||
lastRuntimeInvisibleTypeAnnotation,
|
||||
output);
|
||||
if (firstAttribute != null) {
|
||||
firstAttribute.putAttributes(symbolTable, output);
|
||||
}
|
||||
|
@ -85,19 +85,19 @@ package jdk.internal.org.objectweb.asm;
|
||||
*
|
||||
* <pre>
|
||||
* =====================================
|
||||
* |.DIM|KIND|FLAG|...............VALUE|
|
||||
* |...DIM|KIND|.F|...............VALUE|
|
||||
* =====================================
|
||||
* </pre>
|
||||
*
|
||||
* <ul>
|
||||
* <li>the DIM field, stored in the 4 most significant bits, is a signed number of array
|
||||
* dimensions (from -8 to 7, included). It can be retrieved with {@link #DIM_MASK} and a right
|
||||
* shift of {@link #DIM_SHIFT}.
|
||||
* <li>the DIM field, stored in the 6 most significant bits, is a signed number of array
|
||||
* dimensions (from -32 to 31, included). It can be retrieved with {@link #DIM_MASK} and a
|
||||
* right shift of {@link #DIM_SHIFT}.
|
||||
* <li>the KIND field, stored in 4 bits, indicates the kind of VALUE used. These 4 bits can be
|
||||
* retrieved with {@link #KIND_MASK} and, without any shift, must be equal to {@link
|
||||
* #CONSTANT_KIND}, {@link #REFERENCE_KIND}, {@link #UNINITIALIZED_KIND}, {@link #LOCAL_KIND}
|
||||
* or {@link #STACK_KIND}.
|
||||
* <li>the FLAGS field, stored in 4 bits, contains up to 4 boolean flags. Currently only one flag
|
||||
* <li>the FLAGS field, stored in 2 bits, contains up to 2 boolean flags. Currently only one flag
|
||||
* is defined, namely {@link #TOP_IF_LONG_OR_DOUBLE_FLAG}.
|
||||
* <li>the VALUE field, stored in the remaining 20 bits, contains either
|
||||
* <ul>
|
||||
@ -120,9 +120,9 @@ package jdk.internal.org.objectweb.asm;
|
||||
* <p>Output frames can contain abstract types of any kind and with a positive or negative array
|
||||
* dimension (and even unassigned types, represented by 0 - which does not correspond to any valid
|
||||
* abstract type value). Input frames can only contain CONSTANT_KIND, REFERENCE_KIND or
|
||||
* UNINITIALIZED_KIND abstract types of positive or null array dimension. In all cases the type
|
||||
* table contains only internal type names (array type descriptors are forbidden - array dimensions
|
||||
* must be represented through the DIM field).
|
||||
* UNINITIALIZED_KIND abstract types of positive or {@literal null} array dimension. In all cases
|
||||
* the type table contains only internal type names (array type descriptors are forbidden - array
|
||||
* dimensions must be represented through the DIM field).
|
||||
*
|
||||
* <p>The LONG and DOUBLE types are always represented by using two slots (LONG + TOP or DOUBLE +
|
||||
* TOP), for local variables as well as in the operand stack. This is necessary to be able to
|
||||
@ -160,18 +160,25 @@ class Frame {
|
||||
private static final int ITEM_ASM_CHAR = 11;
|
||||
private static final int ITEM_ASM_SHORT = 12;
|
||||
|
||||
// The size and offset in bits of each field of an abstract type.
|
||||
|
||||
private static final int DIM_SIZE = 6;
|
||||
private static final int KIND_SIZE = 4;
|
||||
private static final int FLAGS_SIZE = 2;
|
||||
private static final int VALUE_SIZE = 32 - DIM_SIZE - KIND_SIZE - FLAGS_SIZE;
|
||||
|
||||
private static final int DIM_SHIFT = KIND_SIZE + FLAGS_SIZE + VALUE_SIZE;
|
||||
private static final int KIND_SHIFT = FLAGS_SIZE + VALUE_SIZE;
|
||||
private static final int FLAGS_SHIFT = VALUE_SIZE;
|
||||
|
||||
// Bitmasks to get each field of an abstract type.
|
||||
|
||||
private static final int DIM_MASK = 0xF0000000;
|
||||
private static final int KIND_MASK = 0x0F000000;
|
||||
private static final int FLAGS_MASK = 0x00F00000;
|
||||
private static final int VALUE_MASK = 0x000FFFFF;
|
||||
private static final int DIM_MASK = ((1 << DIM_SIZE) - 1) << DIM_SHIFT;
|
||||
private static final int KIND_MASK = ((1 << KIND_SIZE) - 1) << KIND_SHIFT;
|
||||
private static final int VALUE_MASK = (1 << VALUE_SIZE) - 1;
|
||||
|
||||
// Constants to manipulate the DIM field of an abstract type.
|
||||
|
||||
/** The number of right shift bits to use to get the array dimensions of an abstract type. */
|
||||
private static final int DIM_SHIFT = 28;
|
||||
|
||||
/** The constant to be added to an abstract type to get one with one more array dimension. */
|
||||
private static final int ARRAY_OF = +1 << DIM_SHIFT;
|
||||
|
||||
@ -180,11 +187,11 @@ class Frame {
|
||||
|
||||
// Possible values for the KIND field of an abstract type.
|
||||
|
||||
private static final int CONSTANT_KIND = 0x01000000;
|
||||
private static final int REFERENCE_KIND = 0x02000000;
|
||||
private static final int UNINITIALIZED_KIND = 0x03000000;
|
||||
private static final int LOCAL_KIND = 0x04000000;
|
||||
private static final int STACK_KIND = 0x05000000;
|
||||
private static final int CONSTANT_KIND = 1 << KIND_SHIFT;
|
||||
private static final int REFERENCE_KIND = 2 << KIND_SHIFT;
|
||||
private static final int UNINITIALIZED_KIND = 3 << KIND_SHIFT;
|
||||
private static final int LOCAL_KIND = 4 << KIND_SHIFT;
|
||||
private static final int STACK_KIND = 5 << KIND_SHIFT;
|
||||
|
||||
// Possible flags for the FLAGS field of an abstract type.
|
||||
|
||||
@ -193,7 +200,7 @@ class Frame {
|
||||
* concrete type is LONG or DOUBLE, TOP should be used instead (because the value has been
|
||||
* partially overridden with an xSTORE instruction).
|
||||
*/
|
||||
private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 0x00100000 & FLAGS_MASK;
|
||||
private static final int TOP_IF_LONG_OR_DOUBLE_FLAG = 1 << FLAGS_SHIFT;
|
||||
|
||||
// Useful predefined abstract types (all the possible CONSTANT_KIND types).
|
||||
|
||||
@ -571,7 +578,8 @@ class Frame {
|
||||
* @param descriptor a type or method descriptor (in which case its return type is pushed).
|
||||
*/
|
||||
private void push(final SymbolTable symbolTable, final String descriptor) {
|
||||
int typeDescriptorOffset = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
|
||||
int typeDescriptorOffset =
|
||||
descriptor.charAt(0) == '(' ? Type.getReturnTypeOffset(descriptor) : 0;
|
||||
int abstractType = getAbstractTypeFromDescriptor(symbolTable, descriptor, typeDescriptorOffset);
|
||||
if (abstractType != 0) {
|
||||
push(abstractType);
|
||||
@ -1134,6 +1142,42 @@ class Frame {
|
||||
// Frame merging methods, used in the second step of the stack map frame computation algorithm
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Computes the concrete output type corresponding to a given abstract output type.
|
||||
*
|
||||
* @param abstractOutputType an abstract output type.
|
||||
* @param numStack the size of the input stack, used to resolve abstract output types of
|
||||
* STACK_KIND kind.
|
||||
* @return the concrete output type corresponding to 'abstractOutputType'.
|
||||
*/
|
||||
private int getConcreteOutputType(final int abstractOutputType, final int numStack) {
|
||||
int dim = abstractOutputType & DIM_MASK;
|
||||
int kind = abstractOutputType & KIND_MASK;
|
||||
if (kind == LOCAL_KIND) {
|
||||
// By definition, a LOCAL_KIND type designates the concrete type of a local variable at
|
||||
// the beginning of the basic block corresponding to this frame (which is known when
|
||||
// this method is called, but was not when the abstract type was computed).
|
||||
int concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
return concreteOutputType;
|
||||
} else if (kind == STACK_KIND) {
|
||||
// By definition, a STACK_KIND type designates the concrete type of a local variable at
|
||||
// the beginning of the basic block corresponding to this frame (which is known when
|
||||
// this method is called, but was not when the abstract type was computed).
|
||||
int concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
return concreteOutputType;
|
||||
} else {
|
||||
return abstractOutputType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the input frame of the given {@link Frame} with the input and output frames of this
|
||||
* {@link Frame}. Returns {@literal true} if the given frame has been changed by this operation
|
||||
@ -1168,29 +1212,7 @@ class Frame {
|
||||
// value at the beginning of the block.
|
||||
concreteOutputType = inputLocals[i];
|
||||
} else {
|
||||
int dim = abstractOutputType & DIM_MASK;
|
||||
int kind = abstractOutputType & KIND_MASK;
|
||||
if (kind == LOCAL_KIND) {
|
||||
// By definition, a LOCAL_KIND type designates the concrete type of a local variable at
|
||||
// the beginning of the basic block corresponding to this frame (which is known when
|
||||
// this method is called, but was not when the abstract type was computed).
|
||||
concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
} else if (kind == STACK_KIND) {
|
||||
// By definition, a STACK_KIND type designates the concrete type of a local variable at
|
||||
// the beginning of the basic block corresponding to this frame (which is known when
|
||||
// this method is called, but was not when the abstract type was computed).
|
||||
concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
} else {
|
||||
concreteOutputType = abstractOutputType;
|
||||
}
|
||||
concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
|
||||
}
|
||||
} else {
|
||||
// If the local variable has never been assigned in this basic block, it is equal to its
|
||||
@ -1244,25 +1266,8 @@ class Frame {
|
||||
// Then, do this for the stack operands that have pushed in the basic block (this code is the
|
||||
// same as the one above for local variables).
|
||||
for (int i = 0; i < outputStackTop; ++i) {
|
||||
int concreteOutputType;
|
||||
int abstractOutputType = outputStack[i];
|
||||
int dim = abstractOutputType & DIM_MASK;
|
||||
int kind = abstractOutputType & KIND_MASK;
|
||||
if (kind == LOCAL_KIND) {
|
||||
concreteOutputType = dim + inputLocals[abstractOutputType & VALUE_MASK];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
} else if (kind == STACK_KIND) {
|
||||
concreteOutputType = dim + inputStack[numStack - (abstractOutputType & VALUE_MASK)];
|
||||
if ((abstractOutputType & TOP_IF_LONG_OR_DOUBLE_FLAG) != 0
|
||||
&& (concreteOutputType == LONG || concreteOutputType == DOUBLE)) {
|
||||
concreteOutputType = TOP;
|
||||
}
|
||||
} else {
|
||||
concreteOutputType = abstractOutputType;
|
||||
}
|
||||
int concreteOutputType = getConcreteOutputType(abstractOutputType, numStack);
|
||||
if (initializations != null) {
|
||||
concreteOutputType = getInitializedType(symbolTable, concreteOutputType);
|
||||
}
|
||||
@ -1279,10 +1284,10 @@ class Frame {
|
||||
* @param symbolTable the type table to use to lookup and store type {@link Symbol}.
|
||||
* @param sourceType the abstract type with which the abstract type array element must be merged.
|
||||
* This type should be of {@link #CONSTANT_KIND}, {@link #REFERENCE_KIND} or {@link
|
||||
* #UNINITIALIZED_KIND} kind, with positive or null array dimensions.
|
||||
* #UNINITIALIZED_KIND} kind, with positive or {@literal null} array dimensions.
|
||||
* @param dstTypes an array of abstract types. These types should be of {@link #CONSTANT_KIND},
|
||||
* {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or null array
|
||||
* dimensions.
|
||||
* {@link #REFERENCE_KIND} or {@link #UNINITIALIZED_KIND} kind, with positive or {@literal
|
||||
* null} array dimensions.
|
||||
* @param dstIndex the index of the type that must be merged in dstTypes.
|
||||
* @return {@literal true} if the type array has been modified by this operation.
|
||||
*/
|
||||
|
@ -258,7 +258,8 @@ public class Label {
|
||||
|
||||
/**
|
||||
* The maximum height reached by the output stack, relatively to the top of the input stack, in
|
||||
* the basic block corresponding to this label. This maximum is always positive or null.
|
||||
* the basic block corresponding to this label. This maximum is always positive or {@literal
|
||||
* null}.
|
||||
*/
|
||||
short outputStackMax;
|
||||
|
||||
@ -295,12 +296,12 @@ public class Label {
|
||||
Edge outgoingEdges;
|
||||
|
||||
/**
|
||||
* The next element in the list of labels to which this label belongs, or null if it does not
|
||||
* belong to any list. All lists of labels must end with the {@link #EMPTY_LIST} sentinel, in
|
||||
* order to ensure that this field is null if and only if this label does not belong to a list of
|
||||
* labels. Note that there can be several lists of labels at the same time, but that a label can
|
||||
* belong to at most one list at a time (unless some lists share a common tail, but this is not
|
||||
* used in practice).
|
||||
* The next element in the list of labels to which this label belongs, or {@literal null} if it
|
||||
* does not belong to any list. All lists of labels must end with the {@link #EMPTY_LIST}
|
||||
* sentinel, in order to ensure that this field is null if and only if this label does not belong
|
||||
* to a list of labels. Note that there can be several lists of labels at the same time, but that
|
||||
* a label can belong to at most one list at a time (unless some lists share a common tail, but
|
||||
* this is not used in practice).
|
||||
*
|
||||
* <p>List of labels are used in {@link MethodWriter#computeAllFrames} and {@link
|
||||
* MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size,
|
||||
|
@ -87,7 +87,9 @@ public abstract class MethodVisitor {
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The method visitor to which this visitor must delegate method calls. May be null. */
|
||||
/**
|
||||
* The method visitor to which this visitor must delegate method calls. May be {@literal null}.
|
||||
*/
|
||||
protected MethodVisitor mv;
|
||||
|
||||
/**
|
||||
@ -108,9 +110,18 @@ public abstract class MethodVisitor {
|
||||
* @param methodVisitor the method visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public MethodVisitor(final int api, final MethodVisitor methodVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
if (api == Opcodes.ASM9_EXPERIMENTAL) {
|
||||
Constants.checkAsmExperimental(this);
|
||||
}
|
||||
this.api = api;
|
||||
this.mv = methodVisitor;
|
||||
@ -123,7 +134,7 @@ public abstract class MethodVisitor {
|
||||
/**
|
||||
* Visits a parameter of this method.
|
||||
*
|
||||
* @param name parameter name or null if none is provided.
|
||||
* @param name parameter name or {@literal null} if none is provided.
|
||||
* @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
|
||||
* or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
|
||||
*/
|
||||
@ -426,14 +437,8 @@ public abstract class MethodVisitor {
|
||||
@Deprecated
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
|
||||
visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
}
|
||||
int opcodeAndSource = opcode | (api < Opcodes.ASM5 ? Opcodes.SOURCE_DEPRECATED : 0);
|
||||
visitMethodInsn(opcodeAndSource, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,15 +458,15 @@ public abstract class MethodVisitor {
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
if (api < Opcodes.ASM5 && (opcode & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
|
||||
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
|
||||
throw new UnsupportedOperationException("INVOKESPECIAL/STATIC on interfaces requires ASM5");
|
||||
}
|
||||
visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
mv.visitMethodInsn(opcode & ~Opcodes.SOURCE_MASK, owner, name, descriptor, isInterface);
|
||||
}
|
||||
}
|
||||
|
||||
@ -569,7 +574,7 @@ public abstract class MethodVisitor {
|
||||
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
|
||||
throw new UnsupportedOperationException(REQUIRES_ASM5);
|
||||
}
|
||||
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
|
||||
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM7");
|
||||
}
|
||||
if (mv != null) {
|
||||
|
@ -623,7 +623,7 @@ final class MethodWriter extends MethodVisitor {
|
||||
final String signature,
|
||||
final String[] exceptions,
|
||||
final int compute) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.symbolTable = symbolTable;
|
||||
this.accessFlags = "<init>".equals(name) ? access | Constants.ACC_CONSTRUCTOR : access;
|
||||
this.nameIndex = symbolTable.addConstantUtf8(name);
|
||||
@ -685,37 +685,26 @@ final class MethodWriter extends MethodVisitor {
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeVisibleAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleAnnotation =
|
||||
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
|
||||
AnnotationWriter.create(symbolTable, descriptor, lastRuntimeInvisibleAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisitor visitTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -731,27 +720,24 @@ final class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public AnnotationVisitor visitParameterAnnotation(
|
||||
final int parameter, final String annotationDescriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold an 'annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
|
||||
ByteVector annotation = new ByteVector();
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
annotation.putShort(symbolTable.addConstantUtf8(annotationDescriptor)).putShort(0);
|
||||
if (visible) {
|
||||
if (lastRuntimeVisibleParameterAnnotations == null) {
|
||||
lastRuntimeVisibleParameterAnnotations =
|
||||
new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
|
||||
}
|
||||
return lastRuntimeVisibleParameterAnnotations[parameter] =
|
||||
new AnnotationWriter(
|
||||
symbolTable, annotation, lastRuntimeVisibleParameterAnnotations[parameter]);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, annotationDescriptor, lastRuntimeVisibleParameterAnnotations[parameter]);
|
||||
} else {
|
||||
if (lastRuntimeInvisibleParameterAnnotations == null) {
|
||||
lastRuntimeInvisibleParameterAnnotations =
|
||||
new AnnotationWriter[Type.getArgumentTypes(descriptor).length];
|
||||
}
|
||||
return lastRuntimeInvisibleParameterAnnotations[parameter] =
|
||||
new AnnotationWriter(
|
||||
symbolTable, annotation, lastRuntimeInvisibleParameterAnnotations[parameter]);
|
||||
AnnotationWriter.create(
|
||||
symbolTable,
|
||||
annotationDescriptor,
|
||||
lastRuntimeInvisibleParameterAnnotations[parameter]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,6 +806,9 @@ final class MethodWriter extends MethodVisitor {
|
||||
}
|
||||
visitFrameEnd();
|
||||
} else {
|
||||
if (symbolTable.getMajorVersion() < Opcodes.V1_6) {
|
||||
throw new IllegalArgumentException("Class versions V1_5 or less must use F_NEW frames.");
|
||||
}
|
||||
int offsetDelta;
|
||||
if (stackMapTableEntries == null) {
|
||||
stackMapTableEntries = new ByteVector();
|
||||
@ -1446,20 +1435,22 @@ final class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public AnnotationVisitor visitInsnAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget((typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8), typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastCodeRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable,
|
||||
(typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
|
||||
typePath,
|
||||
descriptor,
|
||||
lastCodeRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastCodeRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable,
|
||||
(typeRef & 0xFF0000FF) | (lastBytecodeOffset << 8),
|
||||
typePath,
|
||||
descriptor,
|
||||
lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1480,20 +1471,14 @@ final class MethodWriter extends MethodVisitor {
|
||||
@Override
|
||||
public AnnotationVisitor visitTryCatchAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
// Create a ByteVector to hold a 'type_annotation' JVMS structure.
|
||||
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
|
||||
ByteVector typeAnnotation = new ByteVector();
|
||||
// Write target_type, target_info, and target_path.
|
||||
TypeReference.putTarget(typeRef, typeAnnotation);
|
||||
TypePath.put(typePath, typeAnnotation);
|
||||
// Write type_index and reserve space for num_element_value_pairs.
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastCodeRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastCodeRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
AnnotationWriter.create(
|
||||
symbolTable, typeRef, typePath, descriptor, lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1561,10 +1546,18 @@ final class MethodWriter extends MethodVisitor {
|
||||
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
|
||||
if (visible) {
|
||||
return lastCodeRuntimeVisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeVisibleTypeAnnotation);
|
||||
new AnnotationWriter(
|
||||
symbolTable,
|
||||
/* useNamedValues = */ true,
|
||||
typeAnnotation,
|
||||
lastCodeRuntimeVisibleTypeAnnotation);
|
||||
} else {
|
||||
return lastCodeRuntimeInvisibleTypeAnnotation =
|
||||
new AnnotationWriter(symbolTable, typeAnnotation, lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
new AnnotationWriter(
|
||||
symbolTable,
|
||||
/* useNamedValues = */ true,
|
||||
typeAnnotation,
|
||||
lastCodeRuntimeInvisibleTypeAnnotation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2035,10 +2028,6 @@ final class MethodWriter extends MethodVisitor {
|
||||
* attribute) are the same as the corresponding attributes in the given method.
|
||||
*
|
||||
* @param source the source ClassReader from which the attributes of this method might be copied.
|
||||
* @param methodInfoOffset the offset in 'source.b' of the method_info JVMS structure from which
|
||||
* the attributes of this method might be copied.
|
||||
* @param methodInfoLength the length in 'source.b' of the method_info JVMS structure from which
|
||||
* the attributes of this method might be copied.
|
||||
* @param hasSyntheticAttribute whether the method_info JVMS structure from which the attributes
|
||||
* of this method might be copied contains a Synthetic attribute.
|
||||
* @param hasDeprecatedAttribute whether the method_info JVMS structure from which the attributes
|
||||
@ -2055,8 +2044,6 @@ final class MethodWriter extends MethodVisitor {
|
||||
*/
|
||||
boolean canCopyMethodAttributes(
|
||||
final ClassReader source,
|
||||
final int methodInfoOffset,
|
||||
final int methodInfoLength,
|
||||
final boolean hasSyntheticAttribute,
|
||||
final boolean hasDeprecatedAttribute,
|
||||
final int descriptorIndex,
|
||||
@ -2091,12 +2078,23 @@ final class MethodWriter extends MethodVisitor {
|
||||
currentExceptionOffset += 2;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the source from which the attributes of this method will be copied.
|
||||
*
|
||||
* @param methodInfoOffset the offset in 'symbolTable.getSource()' of the method_info JVMS
|
||||
* structure from which the attributes of this method will be copied.
|
||||
* @param methodInfoLength the length in 'symbolTable.getSource()' of the method_info JVMS
|
||||
* structure from which the attributes of this method will be copied.
|
||||
*/
|
||||
void setMethodAttributesSource(final int methodInfoOffset, final int methodInfoLength) {
|
||||
// Don't copy the attributes yet, instead store their location in the source class reader so
|
||||
// they can be copied later, in {@link #putMethodInfo}. Note that we skip the 6 header bytes
|
||||
// of the method_info JVMS structure.
|
||||
this.sourceOffset = methodInfoOffset + 6;
|
||||
this.sourceLength = methodInfoLength - 6;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2164,29 +2162,13 @@ final class MethodWriter extends MethodVisitor {
|
||||
symbolTable.addConstantUtf8(Constants.EXCEPTIONS);
|
||||
size += 8 + 2 * numberOfExceptions;
|
||||
}
|
||||
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
|
||||
symbolTable.addConstantUtf8(Constants.SYNTHETIC);
|
||||
size += 6;
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
symbolTable.addConstantUtf8(Constants.SIGNATURE);
|
||||
size += 8;
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
symbolTable.addConstantUtf8(Constants.DEPRECATED);
|
||||
size += 6;
|
||||
}
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
|
||||
}
|
||||
size += Attribute.computeAttributesSize(symbolTable, accessFlags, signatureIndex);
|
||||
size +=
|
||||
AnnotationWriter.computeAnnotationsSize(
|
||||
lastRuntimeVisibleAnnotation,
|
||||
lastRuntimeInvisibleAnnotation,
|
||||
lastRuntimeVisibleTypeAnnotation,
|
||||
lastRuntimeInvisibleTypeAnnotation);
|
||||
if (lastRuntimeVisibleParameterAnnotations != null) {
|
||||
size +=
|
||||
AnnotationWriter.computeParameterAnnotationsSize(
|
||||
@ -2205,16 +2187,6 @@ final class MethodWriter extends MethodVisitor {
|
||||
? lastRuntimeInvisibleParameterAnnotations.length
|
||||
: invisibleAnnotableParameterCount);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
size +=
|
||||
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
|
||||
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
|
||||
}
|
||||
if (defaultValue != null) {
|
||||
symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT);
|
||||
size += 6 + defaultValue.length;
|
||||
@ -2242,7 +2214,7 @@ final class MethodWriter extends MethodVisitor {
|
||||
output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
|
||||
// If this method_info must be copied from an existing one, copy it now and return early.
|
||||
if (sourceOffset != 0) {
|
||||
output.putByteArray(symbolTable.getSource().b, sourceOffset, sourceLength);
|
||||
output.putByteArray(symbolTable.getSource().classFileBuffer, sourceOffset, sourceLength);
|
||||
return;
|
||||
}
|
||||
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
|
||||
@ -2396,26 +2368,14 @@ final class MethodWriter extends MethodVisitor {
|
||||
output.putShort(exceptionIndex);
|
||||
}
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
|
||||
}
|
||||
if (signatureIndex != 0) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
|
||||
.putInt(2)
|
||||
.putShort(signatureIndex);
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
|
||||
}
|
||||
if (lastRuntimeVisibleAnnotation != null) {
|
||||
lastRuntimeVisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleAnnotation != null) {
|
||||
lastRuntimeInvisibleAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
|
||||
}
|
||||
Attribute.putAttributes(symbolTable, accessFlags, signatureIndex, output);
|
||||
AnnotationWriter.putAnnotations(
|
||||
symbolTable,
|
||||
lastRuntimeVisibleAnnotation,
|
||||
lastRuntimeInvisibleAnnotation,
|
||||
lastRuntimeVisibleTypeAnnotation,
|
||||
lastRuntimeInvisibleTypeAnnotation,
|
||||
output);
|
||||
if (lastRuntimeVisibleParameterAnnotations != null) {
|
||||
AnnotationWriter.putParameterAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS),
|
||||
@ -2434,14 +2394,6 @@ final class MethodWriter extends MethodVisitor {
|
||||
: invisibleAnnotableParameterCount,
|
||||
output);
|
||||
}
|
||||
if (lastRuntimeVisibleTypeAnnotation != null) {
|
||||
lastRuntimeVisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (lastRuntimeInvisibleTypeAnnotation != null) {
|
||||
lastRuntimeInvisibleTypeAnnotation.putAnnotations(
|
||||
symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
|
||||
}
|
||||
if (defaultValue != null) {
|
||||
output
|
||||
.putShort(symbolTable.addConstantUtf8(Constants.ANNOTATION_DEFAULT))
|
||||
|
@ -73,7 +73,9 @@ public abstract class ModuleVisitor {
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/** The module visitor to which this visitor must delegate method calls. May be null. */
|
||||
/**
|
||||
* The module visitor to which this visitor must delegate method calls. May be {@literal null}.
|
||||
*/
|
||||
protected ModuleVisitor mv;
|
||||
|
||||
/**
|
||||
@ -94,9 +96,18 @@ public abstract class ModuleVisitor {
|
||||
* @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
|
||||
* be null.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
if (api == Opcodes.ASM9_EXPERIMENTAL) {
|
||||
Constants.checkAsmExperimental(this);
|
||||
}
|
||||
this.api = api;
|
||||
this.mv = moduleVisitor;
|
||||
|
@ -125,7 +125,7 @@ final class ModuleWriter extends ModuleVisitor {
|
||||
private int mainClassIndex;
|
||||
|
||||
ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.symbolTable = symbolTable;
|
||||
this.moduleNameIndex = name;
|
||||
this.moduleFlags = access;
|
||||
|
@ -78,9 +78,222 @@ public interface Opcodes {
|
||||
int ASM5 = 5 << 16 | 0 << 8;
|
||||
int ASM6 = 6 << 16 | 0 << 8;
|
||||
int ASM7 = 7 << 16 | 0 << 8;
|
||||
int ASM8 = 8 << 16 | 0 << 8;
|
||||
|
||||
// Java ClassFile versions (the minor version is stored in the 16 most
|
||||
// significant bits, and the
|
||||
/**
|
||||
* <i>Experimental, use at your own risk. This field will be renamed when it becomes stable, this
|
||||
* will break existing code using it. Only code compiled with --enable-preview can use this.</i>
|
||||
*
|
||||
* @deprecated This API is experimental.
|
||||
*/
|
||||
@Deprecated int ASM9_EXPERIMENTAL = 1 << 24 | 9 << 16 | 0 << 8;
|
||||
|
||||
/*
|
||||
* Internal flags used to redirect calls to deprecated methods. For instance, if a visitOldStuff
|
||||
* method in API_OLD is deprecated and replaced with visitNewStuff in API_NEW, then the
|
||||
* redirection should be done as follows:
|
||||
*
|
||||
* <pre>
|
||||
* public class StuffVisitor {
|
||||
* ...
|
||||
*
|
||||
* @Deprecated public void visitOldStuff(int arg, ...) {
|
||||
* // SOURCE_DEPRECATED means "a call from a deprecated method using the old 'api' value".
|
||||
* visitNewStuf(arg | (api < API_NEW ? SOURCE_DEPRECATED : 0), ...);
|
||||
* }
|
||||
*
|
||||
* public void visitNewStuff(int argAndSource, ...) {
|
||||
* if (api < API_NEW && (argAndSource & SOURCE_DEPRECATED) == 0) {
|
||||
* visitOldStuff(argAndSource, ...);
|
||||
* } else {
|
||||
* int arg = argAndSource & ~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 {
|
||||
* @Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
|
||||
* public void visitNewStuff(int arg, ...) { [ do stuff ] }
|
||||
* }
|
||||
* class UserStuffVisitor extends StuffVisitor {
|
||||
* @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 {
|
||||
* @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 & ~SOURCE_MASK;
|
||||
* [ do stuff ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* class UserStuffVisitor extends StuffVisitor {
|
||||
* @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 {
|
||||
* @Override public void visitNewStuff(int argAndSource, ...) {
|
||||
* if (api < API_NEW && (argAndSource & SOURCE_DEPRECATED) == 0) {
|
||||
* super.visitNewStuff(argAndSource, ...);
|
||||
* return;
|
||||
* }
|
||||
* super.visitNewStuff(argAndSource, ...); // optional
|
||||
* int arg = argAndSource & ~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 {
|
||||
* @Deprecated public void visitOldStuff(int arg, ...) { visitNewStuf(arg, ...); }
|
||||
* public void visitNewStuff(int arg, ...) { [ do stuff ] }
|
||||
* }
|
||||
* public class AsmStuffVisitor extends StuffVisitor {
|
||||
* @Override public void visitNewStuff(int arg, ...) {
|
||||
* super.visitNewStuff(arg, ...);
|
||||
* [ do other stuff ]
|
||||
* }
|
||||
* }
|
||||
* class UserStuffVisitor extends StuffVisitor {
|
||||
* @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 {
|
||||
* @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 & ~SOURCE_MASK;
|
||||
* [ do stuff ]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* public class AsmStuffVisitor extends StuffVisitor {
|
||||
* @Override public void visitNewStuff(int argAndSource, ...) {
|
||||
* if ((argAndSource & SOURCE_DEPRECATED) == 0) {
|
||||
* super.visitNewStuff(argAndSource, ...);
|
||||
* return;
|
||||
* }
|
||||
* super.visitNewStuff(argAndSource, ...); // optional
|
||||
* int arg = argAndSource & ~SOURCE_MASK;
|
||||
* [ do other stuff ]
|
||||
* }
|
||||
* }
|
||||
* class UserStuffVisitor extends StuffVisitor {
|
||||
* @Override public void visitOldStuff(int arg, ...) {
|
||||
* super.visitOldStuff(arg, ...);
|
||||
* [ do user stuff ]
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>and, here again, whether visitNewStuff or visitOldStuff is called, 'do stuff', 'do other
|
||||
* stuff' and 'do user stuff' will be executed, in this order (exercise left to the reader).
|
||||
*
|
||||
* <h1>Notes</h1>
|
||||
*
|
||||
* <ul>
|
||||
* <li>the SOURCE_DEPRECATED flag is set only if 'api' is API_OLD, just before calling
|
||||
* visitNewStuff. By hypothesis, this method is not overridden by the user. Therefore, user
|
||||
* classes can never see this flag. Only ASM subclasses must take care of extracting the
|
||||
* actual argument value by clearing the source flags.
|
||||
* <li>because the SOURCE_DEPRECATED flag is immediately cleared in the caller, the caller can
|
||||
* call visitOldStuff or visitNewStuff (in 'do stuff' and 'do user stuff') on a delegate
|
||||
* visitor without any risks (breaking the redirection logic, "leaking" the flag, etc).
|
||||
* <li>all the scenarios discussed above are unit tested in MethodVisitorTest.
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
int SOURCE_DEPRECATED = 0x100;
|
||||
int SOURCE_MASK = SOURCE_DEPRECATED;
|
||||
|
||||
// Java ClassFile versions (the minor version is stored in the 16 most significant bits, and the
|
||||
// major version in the 16 least significant bits).
|
||||
|
||||
int V1_1 = 3 << 16 | 45;
|
||||
@ -134,7 +347,7 @@ public interface Opcodes {
|
||||
int ACC_SYNTHETIC = 0x1000; // class, field, method, parameter, module *
|
||||
int ACC_ANNOTATION = 0x2000; // class
|
||||
int ACC_ENUM = 0x4000; // class(?) field inner
|
||||
int ACC_MANDATED = 0x8000; // parameter, module, module *
|
||||
int ACC_MANDATED = 0x8000; // field, method, parameter, module, module *
|
||||
int ACC_MODULE = 0x8000; // class
|
||||
|
||||
// ASM specific access flags.
|
||||
@ -142,6 +355,7 @@ public interface Opcodes {
|
||||
// access flags, and also to make sure that these flags are automatically filtered out when
|
||||
// written in class files (because access flags are stored using 16 bits only).
|
||||
|
||||
int ACC_RECORD = 0x10000; // class
|
||||
int ACC_DEPRECATED = 0x20000; // class, field, method
|
||||
|
||||
// Possible values for the type operand of the NEWARRAY instruction.
|
||||
|
182
src/java.base/share/classes/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java
Normal file
182
src/java.base/share/classes/jdk/internal/org/objectweb/asm/RecordComponentVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
256
src/java.base/share/classes/jdk/internal/org/objectweb/asm/RecordComponentWriter.java
Normal file
256
src/java.base/share/classes/jdk/internal/org/objectweb/asm/RecordComponentWriter.java
Normal 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);
|
||||
}
|
||||
}
|
@ -62,11 +62,11 @@ package jdk.internal.org.objectweb.asm;
|
||||
* The constant pool entries, the BootstrapMethods attribute entries and the (ASM specific) type
|
||||
* table entries of a class.
|
||||
*
|
||||
* @author Eric Bruneton
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4">JVMS
|
||||
* 4.4</a>
|
||||
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
|
||||
* 4.7.23</a>
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
final class SymbolTable {
|
||||
|
||||
@ -170,7 +170,7 @@ final class SymbolTable {
|
||||
this.sourceClassReader = classReader;
|
||||
|
||||
// Copy the constant pool binary content.
|
||||
byte[] inputBytes = classReader.b;
|
||||
byte[] inputBytes = classReader.classFileBuffer;
|
||||
int constantPoolOffset = classReader.getItem(1) - 1;
|
||||
int constantPoolLength = classReader.header - constantPoolOffset;
|
||||
constantPoolCount = classReader.getItemCount();
|
||||
@ -273,7 +273,7 @@ final class SymbolTable {
|
||||
*/
|
||||
private void copyBootstrapMethods(final ClassReader classReader, final char[] charBuffer) {
|
||||
// Find attributOffset of the 'bootstrap_methods' array.
|
||||
byte[] inputBytes = classReader.b;
|
||||
byte[] inputBytes = classReader.classFileBuffer;
|
||||
int currentAttributeOffset = classReader.getFirstAttributeOffset();
|
||||
for (int i = classReader.readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
|
||||
String attributeName = classReader.readUTF8(currentAttributeOffset, charBuffer);
|
||||
@ -1077,8 +1077,10 @@ final class SymbolTable {
|
||||
// bootstrap methods. We must therefore add the bootstrap method arguments to the constant pool
|
||||
// and BootstrapMethods attribute first, so that the BootstrapMethods attribute is not modified
|
||||
// while adding the given bootstrap method to it, in the rest of this method.
|
||||
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
|
||||
addConstant(bootstrapMethodArgument);
|
||||
int numBootstrapArguments = bootstrapMethodArguments.length;
|
||||
int[] bootstrapMethodArgumentIndexes = new int[numBootstrapArguments];
|
||||
for (int i = 0; i < numBootstrapArguments; i++) {
|
||||
bootstrapMethodArgumentIndexes[i] = addConstant(bootstrapMethodArguments[i]).index;
|
||||
}
|
||||
|
||||
// Write the bootstrap method in the BootstrapMethods table. This is necessary to be able to
|
||||
@ -1093,10 +1095,10 @@ final class SymbolTable {
|
||||
bootstrapMethodHandle.getDesc(),
|
||||
bootstrapMethodHandle.isInterface())
|
||||
.index);
|
||||
int numBootstrapArguments = bootstrapMethodArguments.length;
|
||||
|
||||
bootstrapMethodsAttribute.putShort(numBootstrapArguments);
|
||||
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
|
||||
bootstrapMethodsAttribute.putShort(addConstant(bootstrapMethodArgument).index);
|
||||
for (int i = 0; i < numBootstrapArguments; i++) {
|
||||
bootstrapMethodsAttribute.putShort(bootstrapMethodArgumentIndexes[i]);
|
||||
}
|
||||
|
||||
// Compute the length and the hash code of the bootstrap method.
|
||||
@ -1214,8 +1216,10 @@ final class SymbolTable {
|
||||
* corresponding to the common super class of the given types.
|
||||
*/
|
||||
int addMergedType(final int typeTableIndex1, final int typeTableIndex2) {
|
||||
// TODO sort the arguments? The merge result should be independent of their order.
|
||||
long data = typeTableIndex1 | (((long) typeTableIndex2) << 32);
|
||||
long data =
|
||||
typeTableIndex1 < typeTableIndex2
|
||||
? typeTableIndex1 | (((long) typeTableIndex2) << 32)
|
||||
: typeTableIndex2 | (((long) typeTableIndex1) << 32);
|
||||
int hashCode = hash(Symbol.MERGED_TYPE_TAG, typeTableIndex1 + typeTableIndex2);
|
||||
Entry entry = get(hashCode);
|
||||
while (entry != null) {
|
||||
|
@ -336,7 +336,8 @@ public final class Type {
|
||||
}
|
||||
if (methodDescriptor.charAt(currentOffset++) == 'L') {
|
||||
// Skip the argument descriptor content.
|
||||
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
|
||||
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
|
||||
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
|
||||
}
|
||||
++numArgumentTypes;
|
||||
}
|
||||
@ -354,7 +355,8 @@ public final class Type {
|
||||
}
|
||||
if (methodDescriptor.charAt(currentOffset++) == 'L') {
|
||||
// Skip the argument descriptor content.
|
||||
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
|
||||
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
|
||||
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
|
||||
}
|
||||
argumentTypes[currentArgumentTypeIndex++] =
|
||||
getTypeInternal(methodDescriptor, currentArgumentTypeOffset, currentOffset);
|
||||
@ -394,19 +396,8 @@ public final class Type {
|
||||
* @return the {@link Type} corresponding to the return type of the given method descriptor.
|
||||
*/
|
||||
public static Type getReturnType(final String methodDescriptor) {
|
||||
// Skip the first character, which is always a '('.
|
||||
int currentOffset = 1;
|
||||
// Skip the argument types, one at a each loop iteration.
|
||||
while (methodDescriptor.charAt(currentOffset) != ')') {
|
||||
while (methodDescriptor.charAt(currentOffset) == '[') {
|
||||
currentOffset++;
|
||||
}
|
||||
if (methodDescriptor.charAt(currentOffset++) == 'L') {
|
||||
// Skip the argument descriptor content.
|
||||
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
|
||||
}
|
||||
}
|
||||
return getTypeInternal(methodDescriptor, currentOffset + 1, methodDescriptor.length());
|
||||
return getTypeInternal(
|
||||
methodDescriptor, getReturnTypeOffset(methodDescriptor), methodDescriptor.length());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -419,6 +410,29 @@ public final class Type {
|
||||
return getType(method.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start index of the return type of the given method descriptor.
|
||||
*
|
||||
* @param methodDescriptor a method descriptor.
|
||||
* @return the start index of the return type of the given method descriptor.
|
||||
*/
|
||||
static int getReturnTypeOffset(final String methodDescriptor) {
|
||||
// Skip the first character, which is always a '('.
|
||||
int currentOffset = 1;
|
||||
// Skip the argument types, one at a each loop iteration.
|
||||
while (methodDescriptor.charAt(currentOffset) != ')') {
|
||||
while (methodDescriptor.charAt(currentOffset) == '[') {
|
||||
currentOffset++;
|
||||
}
|
||||
if (methodDescriptor.charAt(currentOffset++) == 'L') {
|
||||
// Skip the argument descriptor content.
|
||||
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
|
||||
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
|
||||
}
|
||||
}
|
||||
return currentOffset + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Type} corresponding to the given field or method descriptor.
|
||||
*
|
||||
@ -536,11 +550,7 @@ public final class Type {
|
||||
if (sort == OBJECT) {
|
||||
return valueBuffer.substring(valueBegin - 1, valueEnd + 1);
|
||||
} else if (sort == INTERNAL) {
|
||||
return new StringBuilder()
|
||||
.append('L')
|
||||
.append(valueBuffer, valueBegin, valueEnd)
|
||||
.append(';')
|
||||
.toString();
|
||||
return 'L' + valueBuffer.substring(valueBegin, valueEnd) + ';';
|
||||
} else {
|
||||
return valueBuffer.substring(valueBegin, valueEnd);
|
||||
}
|
||||
@ -662,14 +672,7 @@ public final class Type {
|
||||
}
|
||||
stringBuilder.append(descriptor);
|
||||
} else {
|
||||
stringBuilder.append('L');
|
||||
String name = currentClass.getName();
|
||||
int nameLength = name.length();
|
||||
for (int i = 0; i < nameLength; ++i) {
|
||||
char car = name.charAt(i);
|
||||
stringBuilder.append(car == '.' ? '/' : car);
|
||||
}
|
||||
stringBuilder.append(';');
|
||||
stringBuilder.append('L').append(getInternalName(currentClass)).append(';');
|
||||
}
|
||||
}
|
||||
|
||||
@ -768,7 +771,8 @@ public final class Type {
|
||||
}
|
||||
if (methodDescriptor.charAt(currentOffset++) == 'L') {
|
||||
// Skip the argument descriptor content.
|
||||
currentOffset = methodDescriptor.indexOf(';', currentOffset) + 1;
|
||||
int semiColumnOffset = methodDescriptor.indexOf(';', currentOffset);
|
||||
currentOffset = Math.max(currentOffset, semiColumnOffset + 1);
|
||||
}
|
||||
argumentsSize += 1;
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ public final class TypePath {
|
||||
* @return the corresponding TypePath object, or {@literal null} if the path is empty.
|
||||
*/
|
||||
public static TypePath fromString(final String typePath) {
|
||||
if (typePath == null || typePath.isEmpty()) {
|
||||
if (typePath == null || typePath.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
int typePathLength = typePath.length();
|
||||
|
@ -152,8 +152,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
|
||||
public void visitCode() {
|
||||
super.visitCode();
|
||||
if (isConstructor) {
|
||||
stackFrame = new ArrayList<Object>();
|
||||
forwardJumpStackFrames = new HashMap<Label, List<Object>>();
|
||||
stackFrame = new ArrayList<>();
|
||||
forwardJumpStackFrames = new HashMap<>();
|
||||
} else {
|
||||
onMethodEnter();
|
||||
}
|
||||
@ -382,6 +382,8 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
|
||||
popValue();
|
||||
popValue();
|
||||
break;
|
||||
case RET:
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(INVALID_OPCODE + opcode);
|
||||
}
|
||||
@ -467,35 +469,21 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
doVisitMethodInsn(opcode, descriptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
doVisitMethodInsn(opcode, descriptor);
|
||||
}
|
||||
|
||||
@ -611,7 +599,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
|
||||
// initialized twice), so this is not issue (in the sense that there is no risk to emit a wrong
|
||||
// 'onMethodEnter').
|
||||
if (isConstructor && !forwardJumpStackFrames.containsKey(handler)) {
|
||||
List<Object> handlerStackFrame = new ArrayList<Object>();
|
||||
List<Object> handlerStackFrame = new ArrayList<>();
|
||||
handlerStackFrame.add(OTHER);
|
||||
forwardJumpStackFrames.put(handler, handlerStackFrame);
|
||||
}
|
||||
@ -628,7 +616,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
|
||||
if (forwardJumpStackFrames.containsKey(label)) {
|
||||
return;
|
||||
}
|
||||
forwardJumpStackFrames.put(label, new ArrayList<Object>(stackFrame));
|
||||
forwardJumpStackFrames.put(label, new ArrayList<>(stackFrame));
|
||||
}
|
||||
|
||||
private Object popValue() {
|
||||
|
@ -147,7 +147,7 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final MethodVisitor methodVisitor) {
|
||||
this(Opcodes.ASM7, owner, access, name, descriptor, methodVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, owner, access, name, descriptor, methodVisitor);
|
||||
if (getClass() != AnalyzerAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -157,7 +157,8 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
* Constructs a new {@link AnalyzerAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param owner the owner's class name.
|
||||
* @param access the method's access flags (see {@link Opcodes}).
|
||||
* @param name the method's name.
|
||||
@ -174,9 +175,9 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
final MethodVisitor methodVisitor) {
|
||||
super(api, methodVisitor);
|
||||
this.owner = owner;
|
||||
locals = new ArrayList<Object>();
|
||||
stack = new ArrayList<Object>();
|
||||
uninitializedTypes = new HashMap<Object, Object>();
|
||||
locals = new ArrayList<>();
|
||||
stack = new ArrayList<>();
|
||||
uninitializedTypes = new HashMap<>();
|
||||
|
||||
if ((access & Opcodes.ACC_STATIC) == 0) {
|
||||
if ("<init>".equals(name)) {
|
||||
@ -236,8 +237,8 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
this.locals.clear();
|
||||
this.stack.clear();
|
||||
} else {
|
||||
this.locals = new ArrayList<Object>();
|
||||
this.stack = new ArrayList<Object>();
|
||||
this.locals = new ArrayList<>();
|
||||
this.stack = new ArrayList<>();
|
||||
}
|
||||
visitFrameTypes(numLocal, local, this.locals);
|
||||
visitFrameTypes(numStack, stack, this.stack);
|
||||
@ -289,7 +290,7 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
if (opcode == Opcodes.NEW) {
|
||||
if (labels == null) {
|
||||
Label label = new Label();
|
||||
labels = new ArrayList<Label>(3);
|
||||
labels = new ArrayList<>(3);
|
||||
labels.add(label);
|
||||
if (mv != null) {
|
||||
mv.visitLabel(label);
|
||||
@ -310,45 +311,21 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
execute(opcode, 0, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
@ -409,7 +386,7 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
public void visitLabel(final Label label) {
|
||||
super.visitLabel(label);
|
||||
if (labels == null) {
|
||||
labels = new ArrayList<Label>(3);
|
||||
labels = new ArrayList<>(3);
|
||||
}
|
||||
labels.add(label);
|
||||
}
|
||||
@ -526,9 +503,12 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
maxStack = Math.max(maxStack, stack.size());
|
||||
}
|
||||
|
||||
private void pushDescriptor(final String descriptor) {
|
||||
int index = descriptor.charAt(0) == '(' ? descriptor.indexOf(')') + 1 : 0;
|
||||
switch (descriptor.charAt(index)) {
|
||||
private void pushDescriptor(final String fieldOrMethodDescriptor) {
|
||||
String descriptor =
|
||||
fieldOrMethodDescriptor.charAt(0) == '('
|
||||
? Type.getReturnType(fieldOrMethodDescriptor).getDescriptor()
|
||||
: fieldOrMethodDescriptor;
|
||||
switch (descriptor.charAt(0)) {
|
||||
case 'V':
|
||||
return;
|
||||
case 'Z':
|
||||
@ -550,18 +530,10 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
push(Opcodes.TOP);
|
||||
return;
|
||||
case '[':
|
||||
if (index == 0) {
|
||||
push(descriptor);
|
||||
} else {
|
||||
push(descriptor.substring(index, descriptor.length()));
|
||||
}
|
||||
push(descriptor);
|
||||
break;
|
||||
case 'L':
|
||||
if (index == 0) {
|
||||
push(descriptor.substring(1, descriptor.length() - 1));
|
||||
} else {
|
||||
push(descriptor.substring(index + 1, descriptor.length() - 1));
|
||||
}
|
||||
push(descriptor.substring(1, descriptor.length() - 1));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
@ -597,6 +569,9 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
}
|
||||
|
||||
private void execute(final int opcode, final int intArg, final String stringArg) {
|
||||
if (opcode == Opcodes.JSR || opcode == Opcodes.RET) {
|
||||
throw new IllegalArgumentException("JSR/RET are not supported");
|
||||
}
|
||||
if (this.locals == null) {
|
||||
labels = null;
|
||||
return;
|
||||
@ -897,9 +872,6 @@ public class AnalyzerAdapter extends MethodVisitor {
|
||||
pop(4);
|
||||
push(Opcodes.INTEGER);
|
||||
break;
|
||||
case Opcodes.JSR:
|
||||
case Opcodes.RET:
|
||||
throw new IllegalArgumentException("JSR/RET are not supported");
|
||||
case Opcodes.GETSTATIC:
|
||||
pushDescriptor(stringArg);
|
||||
break;
|
||||
|
@ -79,15 +79,16 @@ public class AnnotationRemapper extends AnnotationVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited annotation.
|
||||
*/
|
||||
public AnnotationRemapper(final AnnotationVisitor annotationVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, annotationVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, annotationVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link AnnotationRemapper}.
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}
|
||||
* @param annotationVisitor the annotation visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited annotation.
|
||||
*/
|
||||
@ -113,9 +114,7 @@ public class AnnotationRemapper extends AnnotationVisitor {
|
||||
if (annotationVisitor == null) {
|
||||
return null;
|
||||
} else {
|
||||
return annotationVisitor == av
|
||||
? this
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,9 +124,18 @@ public class AnnotationRemapper extends AnnotationVisitor {
|
||||
if (annotationVisitor == null) {
|
||||
return null;
|
||||
} else {
|
||||
return annotationVisitor == av
|
||||
? this
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
return annotationVisitor == av ? this : createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new remapper for annotations. The default implementation of this method returns a
|
||||
* new {@link AnnotationRemapper}.
|
||||
*
|
||||
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
|
||||
* @return the newly created remapper.
|
||||
*/
|
||||
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
|
||||
return new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
}
|
||||
}
|
||||
|
@ -66,11 +66,26 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
* A {@link ClassVisitor} that remaps types with a {@link Remapper}.
|
||||
*
|
||||
* <p><i>This visitor has several limitations</i>. A non-exhaustive list is the following:
|
||||
*
|
||||
* <ul>
|
||||
* <li>it cannot remap type names in dynamically computed strings (remapping of type names in
|
||||
* static values is supported).
|
||||
* <li>it cannot remap values derived from type names at compile time, such as
|
||||
* <ul>
|
||||
* <li>type name hashcodes used by some Java compilers to implement the string switch
|
||||
* statement.
|
||||
* <li>some compound strings used by some Java compilers to implement lambda
|
||||
* deserialization.
|
||||
* </ul>
|
||||
* </ul>
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
public class ClassRemapper extends ClassVisitor {
|
||||
@ -89,7 +104,7 @@ public class ClassRemapper extends ClassVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited class.
|
||||
*/
|
||||
public ClassRemapper(final ClassVisitor classVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, classVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, classVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,7 +112,8 @@ public class ClassRemapper extends ClassVisitor {
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
* @param classVisitor the class visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited class.
|
||||
*/
|
||||
@ -157,6 +173,19 @@ public class ClassRemapper extends ClassVisitor {
|
||||
super.visitAttribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
RecordComponentVisitor recordComponentVisitor =
|
||||
super.visitRecordComponent(
|
||||
remapper.mapRecordComponentName(className, name, descriptor),
|
||||
remapper.mapDesc(descriptor),
|
||||
remapper.mapSignature(signature, true));
|
||||
return recordComponentVisitor == null
|
||||
? null
|
||||
: createRecordComponentRemapper(recordComponentVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
@ -220,6 +249,18 @@ public class ClassRemapper extends ClassVisitor {
|
||||
super.visitNestMember(remapper.mapType(nestMember));
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
super.visitPermittedSubtypeExperimental(remapper.mapType(permittedSubtype));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new remapper for fields. The default implementation of this method returns a new
|
||||
* {@link FieldRemapper}.
|
||||
@ -263,4 +304,16 @@ public class ClassRemapper extends ClassVisitor {
|
||||
protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
|
||||
return new ModuleRemapper(api, moduleVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new remapper for record components. The default implementation of this method
|
||||
* returns a new {@link RecordComponentRemapper}.
|
||||
*
|
||||
* @param recordComponentVisitor the RecordComponentVisitor the remapper must delegate to.
|
||||
* @return the newly created remapper.
|
||||
*/
|
||||
protected RecordComponentVisitor createRecordComponentRemapper(
|
||||
final RecordComponentVisitor recordComponentVisitor) {
|
||||
return new RecordComponentRemapper(api, recordComponentVisitor, remapper);
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
|
||||
private int maxSize;
|
||||
|
||||
public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
|
||||
this(Opcodes.ASM7, methodVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, methodVisitor);
|
||||
}
|
||||
|
||||
protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
|
||||
@ -142,42 +142,20 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
|
||||
super.visitFieldInsn(opcode, owner, name, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (opcode == INVOKEINTERFACE) {
|
||||
minSize += 5;
|
||||
maxSize += 5;
|
||||
@ -185,9 +163,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
|
||||
minSize += 3;
|
||||
maxSize += 3;
|
||||
}
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -81,15 +81,15 @@ public class FieldRemapper extends FieldVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited field.
|
||||
*/
|
||||
public FieldRemapper(final FieldVisitor fieldVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, fieldVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, fieldVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldRemapper}.
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
|
||||
* @param fieldVisitor the field visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited field.
|
||||
*/
|
||||
@ -102,9 +102,7 @@ public class FieldRemapper extends FieldVisitor {
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
AnnotationVisitor annotationVisitor =
|
||||
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? null
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -112,8 +110,17 @@ public class FieldRemapper extends FieldVisitor {
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
AnnotationVisitor annotationVisitor =
|
||||
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? null
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new remapper for annotations. The default implementation of this method returns a
|
||||
* new {@link AnnotationRemapper}.
|
||||
*
|
||||
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
|
||||
* @return the newly created remapper.
|
||||
*/
|
||||
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
|
||||
return new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
private final Type[] argumentTypes;
|
||||
|
||||
/** The types of the local variables of the visited method. */
|
||||
private final List<Type> localTypes = new ArrayList<Type>();
|
||||
private final List<Type> localTypes = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link GeneratorAdapter}. <i>Subclasses must not use this constructor</i>.
|
||||
@ -232,7 +232,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
final int access,
|
||||
final String name,
|
||||
final String descriptor) {
|
||||
this(Opcodes.ASM7, methodVisitor, access, name, descriptor);
|
||||
this(/* latest api = */ Opcodes.ASM8, methodVisitor, access, name, descriptor);
|
||||
if (getClass() != GeneratorAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -242,7 +242,8 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
* Constructs a new {@link GeneratorAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param methodVisitor the method visitor to which this adapter delegates calls.
|
||||
* @param access the method's access flags (see {@link Opcodes}).
|
||||
* @param name the method's name.
|
||||
@ -300,7 +301,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
method.getName(),
|
||||
method.getDescriptor(),
|
||||
signature,
|
||||
getInternalNames(exceptions)));
|
||||
exceptions == null ? null : getInternalNames(exceptions)));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -310,9 +311,6 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
* @return the internal names of the given types.
|
||||
*/
|
||||
private static String[] getInternalNames(final Type[] types) {
|
||||
if (types == null) {
|
||||
return null;
|
||||
}
|
||||
String[] names = new String[types.length];
|
||||
for (int i = 0; i < names.length; ++i) {
|
||||
names[i] = types[i].getInternalName();
|
||||
@ -792,48 +790,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
|| to.getSort() > Type.DOUBLE) {
|
||||
throw new IllegalArgumentException("Cannot cast from " + from + " to " + to);
|
||||
}
|
||||
if (from == Type.DOUBLE_TYPE) {
|
||||
if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.D2F);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.D2L);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.D2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
}
|
||||
} else if (from == Type.FLOAT_TYPE) {
|
||||
if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.F2D);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.F2L);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.F2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
}
|
||||
} else if (from == Type.LONG_TYPE) {
|
||||
if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.L2D);
|
||||
} else if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.L2F);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.L2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
}
|
||||
} else {
|
||||
if (to == Type.BYTE_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2B);
|
||||
} else if (to == Type.CHAR_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2C);
|
||||
} else if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2D);
|
||||
} else if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2F);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2L);
|
||||
} else if (to == Type.SHORT_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2S);
|
||||
}
|
||||
}
|
||||
InstructionAdapter.cast(mv, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1350,37 +1307,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
|
||||
* @param type the type of the array elements.
|
||||
*/
|
||||
public void newArray(final Type type) {
|
||||
int arrayType;
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
arrayType = Opcodes.T_BOOLEAN;
|
||||
break;
|
||||
case Type.CHAR:
|
||||
arrayType = Opcodes.T_CHAR;
|
||||
break;
|
||||
case Type.BYTE:
|
||||
arrayType = Opcodes.T_BYTE;
|
||||
break;
|
||||
case Type.SHORT:
|
||||
arrayType = Opcodes.T_SHORT;
|
||||
break;
|
||||
case Type.INT:
|
||||
arrayType = Opcodes.T_INT;
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
arrayType = Opcodes.T_FLOAT;
|
||||
break;
|
||||
case Type.LONG:
|
||||
arrayType = Opcodes.T_LONG;
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
arrayType = Opcodes.T_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
typeInsn(Opcodes.ANEWARRAY, type);
|
||||
return;
|
||||
}
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
|
||||
InstructionAdapter.newarray(mv, type);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
@ -83,7 +83,7 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public InstructionAdapter(final MethodVisitor methodVisitor) {
|
||||
this(Opcodes.ASM7, methodVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, methodVisitor);
|
||||
if (getClass() != InstructionAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -93,7 +93,8 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
* Constructs a new {@link InstructionAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param methodVisitor the method visitor to which this adapter delegates calls.
|
||||
*/
|
||||
protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) {
|
||||
@ -536,42 +537,20 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
switch (opcode) {
|
||||
case Opcodes.INVOKESPECIAL:
|
||||
invokespecial(owner, name, descriptor, isInterface);
|
||||
@ -673,7 +652,7 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM5");
|
||||
}
|
||||
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
|
||||
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
|
||||
throw new UnsupportedOperationException("This feature requires ASM7");
|
||||
}
|
||||
if (value instanceof Integer) {
|
||||
@ -947,47 +926,58 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
* @param to a Type.
|
||||
*/
|
||||
public void cast(final Type from, final Type to) {
|
||||
cast(mv, from, to);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the instruction to cast from the first given type to the other.
|
||||
*
|
||||
* @param methodVisitor the method visitor to use to generate the instruction.
|
||||
* @param from a Type.
|
||||
* @param to a Type.
|
||||
*/
|
||||
static void cast(final MethodVisitor methodVisitor, final Type from, final Type to) {
|
||||
if (from != to) {
|
||||
if (from == Type.DOUBLE_TYPE) {
|
||||
if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.D2F);
|
||||
methodVisitor.visitInsn(Opcodes.D2F);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.D2L);
|
||||
methodVisitor.visitInsn(Opcodes.D2L);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.D2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
methodVisitor.visitInsn(Opcodes.D2I);
|
||||
cast(methodVisitor, Type.INT_TYPE, to);
|
||||
}
|
||||
} else if (from == Type.FLOAT_TYPE) {
|
||||
if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.F2D);
|
||||
methodVisitor.visitInsn(Opcodes.F2D);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.F2L);
|
||||
methodVisitor.visitInsn(Opcodes.F2L);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.F2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
methodVisitor.visitInsn(Opcodes.F2I);
|
||||
cast(methodVisitor, Type.INT_TYPE, to);
|
||||
}
|
||||
} else if (from == Type.LONG_TYPE) {
|
||||
if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.L2D);
|
||||
methodVisitor.visitInsn(Opcodes.L2D);
|
||||
} else if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.L2F);
|
||||
methodVisitor.visitInsn(Opcodes.L2F);
|
||||
} else {
|
||||
mv.visitInsn(Opcodes.L2I);
|
||||
cast(Type.INT_TYPE, to);
|
||||
methodVisitor.visitInsn(Opcodes.L2I);
|
||||
cast(methodVisitor, Type.INT_TYPE, to);
|
||||
}
|
||||
} else {
|
||||
if (to == Type.BYTE_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2B);
|
||||
methodVisitor.visitInsn(Opcodes.I2B);
|
||||
} else if (to == Type.CHAR_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2C);
|
||||
methodVisitor.visitInsn(Opcodes.I2C);
|
||||
} else if (to == Type.DOUBLE_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2D);
|
||||
methodVisitor.visitInsn(Opcodes.I2D);
|
||||
} else if (to == Type.FLOAT_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2F);
|
||||
methodVisitor.visitInsn(Opcodes.I2F);
|
||||
} else if (to == Type.LONG_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2L);
|
||||
methodVisitor.visitInsn(Opcodes.I2L);
|
||||
} else if (to == Type.SHORT_TYPE) {
|
||||
mv.visitInsn(Opcodes.I2S);
|
||||
methodVisitor.visitInsn(Opcodes.I2S);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1256,6 +1246,16 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
* @param type an array Type.
|
||||
*/
|
||||
public void newarray(final Type type) {
|
||||
newarray(mv, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the instruction to create and push on the stack an array of the given type.
|
||||
*
|
||||
* @param methodVisitor the method visitor to use to generate the instruction.
|
||||
* @param type an array Type.
|
||||
*/
|
||||
static void newarray(final MethodVisitor methodVisitor, final Type type) {
|
||||
int arrayType;
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
@ -1283,10 +1283,10 @@ public class InstructionAdapter extends MethodVisitor {
|
||||
arrayType = Opcodes.T_DOUBLE;
|
||||
break;
|
||||
default:
|
||||
mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
|
||||
methodVisitor.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
|
||||
return;
|
||||
}
|
||||
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
|
||||
methodVisitor.visitIntInsn(Opcodes.NEWARRAY, arrayType);
|
||||
}
|
||||
|
||||
public void arraylength() {
|
||||
|
@ -100,7 +100,7 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
* instruction, bit i of the corresponding BitSet in this map is set iff instruction at index i
|
||||
* belongs to this subroutine.
|
||||
*/
|
||||
private final Map<LabelNode, BitSet> subroutinesInsns = new HashMap<LabelNode, BitSet>();
|
||||
private final Map<LabelNode, BitSet> subroutinesInsns = new HashMap<>();
|
||||
|
||||
/**
|
||||
* The instructions that belong to more that one subroutine. Bit i is set iff instruction at index
|
||||
@ -129,7 +129,14 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
|
||||
this(
|
||||
/* latest api = */ Opcodes.ASM8,
|
||||
methodVisitor,
|
||||
access,
|
||||
name,
|
||||
descriptor,
|
||||
signature,
|
||||
exceptions);
|
||||
if (getClass() != JSRInlinerAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -139,7 +146,8 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
* Constructs a new {@link JSRInlinerAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param methodVisitor the method visitor to send the resulting inlined method code to, or <code>
|
||||
* null</code>.
|
||||
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
@ -322,14 +330,14 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
* fully elaborated.
|
||||
*/
|
||||
private void emitCode() {
|
||||
LinkedList<Instantiation> worklist = new LinkedList<Instantiation>();
|
||||
LinkedList<Instantiation> worklist = new LinkedList<>();
|
||||
// Create an instantiation of the main "subroutine", which is just the main routine.
|
||||
worklist.add(new Instantiation(null, mainSubroutineInsns));
|
||||
|
||||
// Emit instantiations of each subroutine we encounter, including the main subroutine.
|
||||
InsnList newInstructions = new InsnList();
|
||||
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<TryCatchBlockNode>();
|
||||
List<LocalVariableNode> newLocalVariables = new ArrayList<LocalVariableNode>();
|
||||
List<TryCatchBlockNode> newTryCatchBlocks = new ArrayList<>();
|
||||
List<LocalVariableNode> newLocalVariables = new ArrayList<>();
|
||||
while (!worklist.isEmpty()) {
|
||||
Instantiation instantiation = worklist.removeFirst();
|
||||
emitInstantiation(
|
||||
@ -486,7 +494,7 @@ public class JSRInlinerAdapter extends MethodNode implements Opcodes {
|
||||
this.parent = parent;
|
||||
this.subroutineInsns = subroutineInsns;
|
||||
this.returnLabel = parent == null ? null : new LabelNode();
|
||||
this.clonedLabels = new HashMap<LabelNode, LabelNode>();
|
||||
this.clonedLabels = new HashMap<>();
|
||||
|
||||
// Create a clone of each label in the original code of the subroutine. Note that we collapse
|
||||
// labels which point at the same instruction into one.
|
||||
|
@ -112,7 +112,7 @@ public class LocalVariablesSorter extends MethodVisitor {
|
||||
*/
|
||||
public LocalVariablesSorter(
|
||||
final int access, final String descriptor, final MethodVisitor methodVisitor) {
|
||||
this(Opcodes.ASM7, access, descriptor, methodVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, access, descriptor, methodVisitor);
|
||||
if (getClass() != LocalVariablesSorter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -122,7 +122,8 @@ public class LocalVariablesSorter extends MethodVisitor {
|
||||
* Constructs a new {@link LocalVariablesSorter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param access access flags of the adapted method.
|
||||
* @param descriptor the method's descriptor (see {@link Type}).
|
||||
* @param methodVisitor the method visitor to which this adapter delegates calls.
|
||||
|
@ -81,7 +81,7 @@ public class Method {
|
||||
private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
|
||||
|
||||
static {
|
||||
HashMap<String, String> descriptors = new HashMap<String, String>();
|
||||
HashMap<String, String> descriptors = new HashMap<>();
|
||||
descriptors.put("void", "V");
|
||||
descriptors.put("byte", "B");
|
||||
descriptors.put("char", "C");
|
||||
|
@ -83,7 +83,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited method.
|
||||
*/
|
||||
public MethodRemapper(final MethodVisitor methodVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, methodVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, methodVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +91,8 @@ public class MethodRemapper extends MethodVisitor {
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
* @param methodVisitor the method visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited method.
|
||||
*/
|
||||
@ -106,7 +107,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,7 +116,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -125,7 +126,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -135,7 +136,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -180,53 +181,24 @@ public class MethodRemapper extends MethodVisitor {
|
||||
remapper.mapDesc(descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
// Calling super.visitMethodInsn requires to call the correct version depending on this.api
|
||||
// (otherwise infinite loops can occur). To simplify and to make it easier to automatically
|
||||
// remove the backward compatibility code, we inline the code of the overridden method here.
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(
|
||||
opcode,
|
||||
remapper.mapType(owner),
|
||||
remapper.mapMethodName(owner, name, descriptor),
|
||||
remapper.mapMethodDesc(descriptor),
|
||||
isInterface);
|
||||
}
|
||||
super.visitMethodInsn(
|
||||
opcodeAndSource,
|
||||
remapper.mapType(owner),
|
||||
remapper.mapMethodName(owner, name, descriptor),
|
||||
remapper.mapMethodDesc(descriptor),
|
||||
isInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -268,7 +240,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -284,7 +256,7 @@ public class MethodRemapper extends MethodVisitor {
|
||||
super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -318,6 +290,17 @@ public class MethodRemapper extends MethodVisitor {
|
||||
typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
|
||||
return annotationVisitor == null
|
||||
? annotationVisitor
|
||||
: new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
: createAnnotationRemapper(annotationVisitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new remapper for annotations. The default implementation of this method returns a
|
||||
* new {@link AnnotationRemapper}.
|
||||
*
|
||||
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
|
||||
* @return the newly created remapper.
|
||||
*/
|
||||
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
|
||||
return new AnnotationRemapper(api, annotationVisitor, remapper);
|
||||
}
|
||||
}
|
||||
|
@ -121,8 +121,8 @@ public final class ModuleHashesAttribute extends Attribute {
|
||||
int numModules = classReader.readUnsignedShort(currentOffset);
|
||||
currentOffset += 2;
|
||||
|
||||
ArrayList<String> moduleList = new ArrayList<String>(numModules);
|
||||
ArrayList<byte[]> hashList = new ArrayList<byte[]>(numModules);
|
||||
ArrayList<String> moduleList = new ArrayList<>(numModules);
|
||||
ArrayList<byte[]> hashList = new ArrayList<>(numModules);
|
||||
|
||||
for (int i = 0; i < numModules; ++i) {
|
||||
String module = classReader.readModule(currentOffset, charBuffer);
|
||||
|
@ -79,15 +79,16 @@ public class ModuleRemapper extends ModuleVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited module.
|
||||
*/
|
||||
public ModuleRemapper(final ModuleVisitor moduleVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, moduleVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, moduleVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link ModuleRemapper}.
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
* @param moduleVisitor the module visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited module.
|
||||
*/
|
||||
|
128
src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RecordComponentRemapper.java
Normal file
128
src/java.base/share/classes/jdk/internal/org/objectweb/asm/commons/RecordComponentRemapper.java
Normal 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);
|
||||
}
|
||||
}
|
@ -140,8 +140,7 @@ public abstract class Remapper {
|
||||
String remappedInternalName = mapType(internalName);
|
||||
if (remappedInternalName != null) {
|
||||
if (remappedInternalNames == null) {
|
||||
remappedInternalNames = new String[internalNames.length];
|
||||
System.arraycopy(internalNames, 0, remappedInternalNames, 0, internalNames.length);
|
||||
remappedInternalNames = internalNames.clone();
|
||||
}
|
||||
remappedInternalNames[i] = remappedInternalName;
|
||||
}
|
||||
@ -281,7 +280,12 @@ public abstract class Remapper {
|
||||
final String name, final String ownerName, final String innerName) {
|
||||
final String remappedInnerName = this.mapType(name);
|
||||
if (remappedInnerName.contains("$")) {
|
||||
return remappedInnerName.substring(remappedInnerName.lastIndexOf('$') + 1);
|
||||
int index = remappedInnerName.lastIndexOf('$') + 1;
|
||||
while (index < remappedInnerName.length()
|
||||
&& Character.isDigit(remappedInnerName.charAt(index))) {
|
||||
index++;
|
||||
}
|
||||
return remappedInnerName.substring(index);
|
||||
} else {
|
||||
return innerName;
|
||||
}
|
||||
@ -312,6 +316,20 @@ public abstract class Remapper {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a record component name to its new name. The default implementation of this method returns
|
||||
* the given name, unchanged. Subclasses can override.
|
||||
*
|
||||
* @param owner the internal name of the owner class of the field.
|
||||
* @param name the name of the field.
|
||||
* @param descriptor the descriptor of the field.
|
||||
* @return the new name of the field.
|
||||
*/
|
||||
public String mapRecordComponentName(
|
||||
final String owner, final String name, final String descriptor) {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a field name to its new name. The default implementation of this method returns the given
|
||||
* name, unchanged. Subclasses can override.
|
||||
|
@ -67,7 +67,6 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import jdk.internal.org.objectweb.asm.ClassVisitor;
|
||||
import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
@ -182,7 +181,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public SerialVersionUIDAdder(final ClassVisitor classVisitor) {
|
||||
this(Opcodes.ASM7, classVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, classVisitor);
|
||||
if (getClass() != SerialVersionUIDAdder.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -192,7 +191,8 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
* Constructs a new {@link SerialVersionUIDAdder}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
|
||||
*/
|
||||
protected SerialVersionUIDAdder(final int api, final ClassVisitor classVisitor) {
|
||||
@ -218,11 +218,10 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
if (computeSvuid) {
|
||||
this.name = name;
|
||||
this.access = access;
|
||||
this.interfaces = new String[interfaces.length];
|
||||
this.svuidFields = new ArrayList<Item>();
|
||||
this.svuidConstructors = new ArrayList<Item>();
|
||||
this.svuidMethods = new ArrayList<Item>();
|
||||
System.arraycopy(interfaces, 0, this.interfaces, 0, interfaces.length);
|
||||
this.interfaces = interfaces.clone();
|
||||
this.svuidFields = new ArrayList<>();
|
||||
this.svuidConstructors = new ArrayList<>();
|
||||
this.svuidMethods = new ArrayList<>();
|
||||
}
|
||||
|
||||
super.visit(version, access, name, signature, superName, interfaces);
|
||||
@ -372,13 +371,10 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
*/
|
||||
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
|
||||
protected long computeSVUID() throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = null;
|
||||
DataOutputStream dataOutputStream = null;
|
||||
long svuid = 0;
|
||||
|
||||
try {
|
||||
byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
dataOutputStream = new DataOutputStream(byteArrayOutputStream);
|
||||
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) {
|
||||
|
||||
// 1. The class name written using UTF encoding.
|
||||
dataOutputStream.writeUTF(name.replace('/', '.'));
|
||||
@ -445,10 +441,6 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
|
||||
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
|
||||
}
|
||||
} finally {
|
||||
if (dataOutputStream != null) {
|
||||
dataOutputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
return svuid;
|
||||
@ -483,18 +475,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
final boolean dotted)
|
||||
throws IOException {
|
||||
Item[] items = itemCollection.toArray(new Item[0]);
|
||||
Arrays.sort(
|
||||
items,
|
||||
new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(final Item item1, final Item item2) {
|
||||
int result = item1.name.compareTo(item2.name);
|
||||
if (result == 0) {
|
||||
result = item1.descriptor.compareTo(item2.descriptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
Arrays.sort(items);
|
||||
for (Item item : items) {
|
||||
dataOutputStream.writeUTF(item.name);
|
||||
dataOutputStream.writeInt(item.access);
|
||||
@ -506,7 +487,7 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
// Inner classes
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
private static final class Item {
|
||||
private static final class Item implements Comparable<Item> {
|
||||
|
||||
final String name;
|
||||
final int access;
|
||||
@ -517,5 +498,27 @@ public class SerialVersionUIDAdder extends ClassVisitor {
|
||||
this.access = access;
|
||||
this.descriptor = descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Item item) {
|
||||
int result = name.compareTo(item.name);
|
||||
if (result == 0) {
|
||||
result = descriptor.compareTo(item.descriptor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object other) {
|
||||
if (other instanceof Item) {
|
||||
return compareTo((Item) other) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ descriptor.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public class SignatureRemapper extends SignatureVisitor {
|
||||
|
||||
private final Remapper remapper;
|
||||
|
||||
private ArrayList<String> classNames = new ArrayList<String>();
|
||||
private ArrayList<String> classNames = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SignatureRemapper}. <i>Subclasses must not use this constructor</i>.
|
||||
@ -83,15 +83,16 @@ public class SignatureRemapper extends SignatureVisitor {
|
||||
* @param remapper the remapper to use to remap the types in the visited signature.
|
||||
*/
|
||||
public SignatureRemapper(final SignatureVisitor signatureVisitor, final Remapper remapper) {
|
||||
this(Opcodes.ASM7, signatureVisitor, remapper);
|
||||
this(/* latest api = */ Opcodes.ASM8, signatureVisitor, remapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link SignatureRemapper}.
|
||||
*
|
||||
* @param api the ASM API version supported by this remapper. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5},{@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
* @param signatureVisitor the signature visitor this remapper must deleted to.
|
||||
* @param remapper the remapper to use to remap the types in the visited signature.
|
||||
*/
|
||||
|
@ -92,14 +92,15 @@ public class StaticInitMerger extends ClassVisitor {
|
||||
* null.
|
||||
*/
|
||||
public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) {
|
||||
this(Opcodes.ASM7, prefix, classVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, prefix, classVisitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link StaticInitMerger}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param prefix the prefix to use to rename the existing <clinit> methods.
|
||||
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
|
||||
* null.
|
||||
|
@ -100,7 +100,14 @@ public class TryCatchBlockSorter extends MethodNode {
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
|
||||
this(
|
||||
/* latest api = */ Opcodes.ASM8,
|
||||
methodVisitor,
|
||||
access,
|
||||
name,
|
||||
descriptor,
|
||||
signature,
|
||||
exceptions);
|
||||
if (getClass() != TryCatchBlockSorter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
@ -102,9 +102,15 @@ public abstract class SignatureVisitor {
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public SignatureVisitor(final int api) {
|
||||
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
|
||||
throw new IllegalArgumentException();
|
||||
if (api != Opcodes.ASM8
|
||||
&& api != Opcodes.ASM7
|
||||
&& api != Opcodes.ASM6
|
||||
&& api != Opcodes.ASM5
|
||||
&& api != Opcodes.ASM4
|
||||
&& api != Opcodes.ASM9_EXPERIMENTAL) {
|
||||
throw new IllegalArgumentException("Unsupported api " + api);
|
||||
}
|
||||
this.api = api;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public class SignatureWriter extends SignatureVisitor {
|
||||
|
||||
/** Constructs a new {@link SignatureWriter}. */
|
||||
public SignatureWriter() {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api =*/ Opcodes.ASM8);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
@ -270,7 +270,7 @@ public abstract class AbstractInsnNode {
|
||||
*/
|
||||
protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
|
||||
if (insnNode.visibleTypeAnnotations != null) {
|
||||
this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
|
||||
this.visibleTypeAnnotations = new ArrayList<>();
|
||||
for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
|
||||
TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
|
||||
TypeAnnotationNode cloneAnnotation =
|
||||
@ -281,7 +281,7 @@ public abstract class AbstractInsnNode {
|
||||
}
|
||||
}
|
||||
if (insnNode.invisibleTypeAnnotations != null) {
|
||||
this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
|
||||
this.invisibleTypeAnnotations = new ArrayList<>();
|
||||
for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
|
||||
TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
|
||||
TypeAnnotationNode cloneAnnotation =
|
||||
|
@ -91,7 +91,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public AnnotationNode(final String descriptor) {
|
||||
this(Opcodes.ASM7, descriptor);
|
||||
this(/* latest api = */ Opcodes.ASM8, descriptor);
|
||||
if (getClass() != AnnotationNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -101,7 +101,8 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
* Constructs a new {@link AnnotationNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
*/
|
||||
public AnnotationNode(final int api, final String descriptor) {
|
||||
@ -115,7 +116,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
* @param values where the visited values must be stored.
|
||||
*/
|
||||
AnnotationNode(final List<Object> values) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@ -126,7 +127,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
@Override
|
||||
public void visit(final String name, final Object value) {
|
||||
if (values == null) {
|
||||
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
|
||||
values = new ArrayList<>(this.desc != null ? 2 : 1);
|
||||
}
|
||||
if (this.desc != null) {
|
||||
values.add(name);
|
||||
@ -155,7 +156,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
@Override
|
||||
public void visitEnum(final String name, final String descriptor, final String value) {
|
||||
if (values == null) {
|
||||
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
|
||||
values = new ArrayList<>(this.desc != null ? 2 : 1);
|
||||
}
|
||||
if (this.desc != null) {
|
||||
values.add(name);
|
||||
@ -166,7 +167,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
@Override
|
||||
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
|
||||
if (values == null) {
|
||||
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
|
||||
values = new ArrayList<>(this.desc != null ? 2 : 1);
|
||||
}
|
||||
if (this.desc != null) {
|
||||
values.add(name);
|
||||
@ -179,12 +180,12 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
@Override
|
||||
public AnnotationVisitor visitArray(final String name) {
|
||||
if (values == null) {
|
||||
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
|
||||
values = new ArrayList<>(this.desc != null ? 2 : 1);
|
||||
}
|
||||
if (this.desc != null) {
|
||||
values.add(name);
|
||||
}
|
||||
List<Object> array = new ArrayList<Object>();
|
||||
List<Object> array = new ArrayList<>();
|
||||
values.add(array);
|
||||
return new AnnotationNode(array);
|
||||
}
|
||||
@ -204,7 +205,7 @@ public class AnnotationNode extends AnnotationVisitor {
|
||||
* introduced in more recent versions of the ASM API than the given version.
|
||||
*
|
||||
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
|
||||
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
|
||||
*/
|
||||
public void check(final int api) {
|
||||
// nothing to do
|
||||
|
@ -67,6 +67,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
@ -84,7 +85,7 @@ public class ClassNode extends ClassVisitor {
|
||||
|
||||
/**
|
||||
* The class's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This field also indicates if
|
||||
* the class is deprecated.
|
||||
* the class is deprecated {@link Opcodes#ACC_DEPRECATED} or a record {@link Opcodes#ACC_RECORD}.
|
||||
*/
|
||||
public int access;
|
||||
|
||||
@ -157,6 +158,18 @@ public class ClassNode extends ClassVisitor {
|
||||
/** The internal names of the nest members of this class. May be {@literal null}. */
|
||||
public List<String> nestMembers;
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>. The internal names of the permitted subtypes of this
|
||||
* class. May be {@literal null}.
|
||||
*
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated public List<String> permittedSubtypesExperimental;
|
||||
|
||||
/** The record components of this class. May be {@literal null}. */
|
||||
public List<RecordComponentNode> recordComponents;
|
||||
|
||||
/** The fields of this class. */
|
||||
public List<FieldNode> fields;
|
||||
|
||||
@ -170,7 +183,7 @@ public class ClassNode extends ClassVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public ClassNode() {
|
||||
this(Opcodes.ASM7);
|
||||
this(Opcodes.ASM8);
|
||||
if (getClass() != ClassNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -180,14 +193,15 @@ public class ClassNode extends ClassVisitor {
|
||||
* Constructs a new {@link ClassNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
*/
|
||||
public ClassNode(final int api) {
|
||||
super(api);
|
||||
this.interfaces = new ArrayList<String>();
|
||||
this.innerClasses = new ArrayList<InnerClassNode>();
|
||||
this.fields = new ArrayList<FieldNode>();
|
||||
this.methods = new ArrayList<MethodNode>();
|
||||
this.interfaces = new ArrayList<>();
|
||||
this.innerClasses = new ArrayList<>();
|
||||
this.fields = new ArrayList<>();
|
||||
this.methods = new ArrayList<>();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -238,15 +252,9 @@ public class ClassNode extends ClassVisitor {
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
AnnotationNode annotation = new AnnotationNode(descriptor);
|
||||
if (visible) {
|
||||
if (visibleAnnotations == null) {
|
||||
visibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
visibleAnnotations.add(annotation);
|
||||
visibleAnnotations = Util.add(visibleAnnotations, annotation);
|
||||
} else {
|
||||
if (invisibleAnnotations == null) {
|
||||
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
invisibleAnnotations.add(annotation);
|
||||
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
@ -256,33 +264,33 @@ public class ClassNode extends ClassVisitor {
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
|
||||
if (visible) {
|
||||
if (visibleTypeAnnotations == null) {
|
||||
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
visibleTypeAnnotations.add(typeAnnotation);
|
||||
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
|
||||
} else {
|
||||
if (invisibleTypeAnnotations == null) {
|
||||
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
invisibleTypeAnnotations.add(typeAnnotation);
|
||||
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
|
||||
}
|
||||
return typeAnnotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
if (attrs == null) {
|
||||
attrs = new ArrayList<Attribute>(1);
|
||||
}
|
||||
attrs.add(attribute);
|
||||
attrs = Util.add(attrs, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNestMember(final String nestMember) {
|
||||
if (nestMembers == null) {
|
||||
nestMembers = new ArrayList<String>();
|
||||
}
|
||||
nestMembers.add(nestMember);
|
||||
nestMembers = Util.add(nestMembers, nestMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
permittedSubtypesExperimental = Util.add(permittedSubtypesExperimental, permittedSubtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -292,6 +300,14 @@ public class ClassNode extends ClassVisitor {
|
||||
innerClasses.add(innerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
RecordComponentNode recordComponent = new RecordComponentNode(name, descriptor, signature);
|
||||
recordComponents = Util.add(recordComponents, recordComponent);
|
||||
return recordComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
@ -331,9 +347,16 @@ public class ClassNode extends ClassVisitor {
|
||||
* in more recent versions of the ASM API than the given version.
|
||||
*
|
||||
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
|
||||
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7}. or {@link Opcodes#ASM8}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void check(final int api) {
|
||||
if (api != Opcodes.ASM9_EXPERIMENTAL && permittedSubtypesExperimental != null) {
|
||||
throw new UnsupportedClassVersionException();
|
||||
}
|
||||
if (api < Opcodes.ASM8 && ((access & Opcodes.ACC_RECORD) != 0 || recordComponents != null)) {
|
||||
throw new UnsupportedClassVersionException();
|
||||
}
|
||||
if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
|
||||
throw new UnsupportedClassVersionException();
|
||||
}
|
||||
@ -369,6 +392,11 @@ public class ClassNode extends ClassVisitor {
|
||||
invisibleTypeAnnotations.get(i).check(api);
|
||||
}
|
||||
}
|
||||
if (recordComponents != null) {
|
||||
for (int i = recordComponents.size() - 1; i >= 0; --i) {
|
||||
recordComponents.get(i).check(api);
|
||||
}
|
||||
}
|
||||
for (int i = fields.size() - 1; i >= 0; --i) {
|
||||
fields.get(i).check(api);
|
||||
}
|
||||
@ -382,6 +410,7 @@ public class ClassNode extends ClassVisitor {
|
||||
*
|
||||
* @param classVisitor a class visitor.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void accept(final ClassVisitor classVisitor) {
|
||||
// Visit the header.
|
||||
String[] interfacesArray = new String[this.interfaces.size()];
|
||||
@ -444,10 +473,22 @@ public class ClassNode extends ClassVisitor {
|
||||
classVisitor.visitNestMember(nestMembers.get(i));
|
||||
}
|
||||
}
|
||||
// Visit the permitted subtypes.
|
||||
if (permittedSubtypesExperimental != null) {
|
||||
for (int i = 0, n = permittedSubtypesExperimental.size(); i < n; ++i) {
|
||||
classVisitor.visitPermittedSubtypeExperimental(permittedSubtypesExperimental.get(i));
|
||||
}
|
||||
}
|
||||
// Visit the inner classes.
|
||||
for (int i = 0, n = innerClasses.size(); i < n; ++i) {
|
||||
innerClasses.get(i).accept(classVisitor);
|
||||
}
|
||||
// Visit the record components.
|
||||
if (recordComponents != null) {
|
||||
for (int i = 0, n = recordComponents.size(); i < n; ++i) {
|
||||
recordComponents.get(i).accept(classVisitor);
|
||||
}
|
||||
}
|
||||
// Visit the fields.
|
||||
for (int i = 0, n = fields.size(); i < n; ++i) {
|
||||
fields.get(i).accept(classVisitor);
|
||||
|
@ -58,7 +58,6 @@
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.tree;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Attribute;
|
||||
@ -131,17 +130,18 @@ public class FieldNode extends FieldVisitor {
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final Object value) {
|
||||
this(Opcodes.ASM7, access, name, descriptor, signature, value);
|
||||
this(/* latest api = */ Opcodes.ASM8, access, name, descriptor, signature, value);
|
||||
if (getClass() != FieldNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>.
|
||||
* Constructs a new {@link FieldNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}
|
||||
* or {@link Opcodes#ASM5}.
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param access the field's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This parameter
|
||||
* also indicates if the field is synthetic and/or deprecated.
|
||||
* @param name the field's name.
|
||||
@ -174,15 +174,9 @@ public class FieldNode extends FieldVisitor {
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
AnnotationNode annotation = new AnnotationNode(descriptor);
|
||||
if (visible) {
|
||||
if (visibleAnnotations == null) {
|
||||
visibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
visibleAnnotations.add(annotation);
|
||||
visibleAnnotations = Util.add(visibleAnnotations, annotation);
|
||||
} else {
|
||||
if (invisibleAnnotations == null) {
|
||||
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
invisibleAnnotations.add(annotation);
|
||||
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
@ -192,25 +186,16 @@ public class FieldNode extends FieldVisitor {
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
|
||||
if (visible) {
|
||||
if (visibleTypeAnnotations == null) {
|
||||
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
visibleTypeAnnotations.add(typeAnnotation);
|
||||
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
|
||||
} else {
|
||||
if (invisibleTypeAnnotations == null) {
|
||||
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
invisibleTypeAnnotations.add(typeAnnotation);
|
||||
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
|
||||
}
|
||||
return typeAnnotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
if (attrs == null) {
|
||||
attrs = new ArrayList<Attribute>(1);
|
||||
}
|
||||
attrs.add(attribute);
|
||||
attrs = Util.add(attrs, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -183,7 +183,7 @@ public class FrameNode extends AbstractInsnNode {
|
||||
FrameNode clone = new FrameNode();
|
||||
clone.type = type;
|
||||
if (local != null) {
|
||||
clone.local = new ArrayList<Object>();
|
||||
clone.local = new ArrayList<>();
|
||||
for (int i = 0, n = local.size(); i < n; ++i) {
|
||||
Object localElement = local.get(i);
|
||||
if (localElement instanceof LabelNode) {
|
||||
@ -193,7 +193,7 @@ public class FrameNode extends AbstractInsnNode {
|
||||
}
|
||||
}
|
||||
if (stack != null) {
|
||||
clone.stack = new ArrayList<Object>();
|
||||
clone.stack = new ArrayList<>();
|
||||
for (int i = 0, n = stack.size(); i < n; ++i) {
|
||||
Object stackElement = stack.get(i);
|
||||
if (stackElement instanceof LabelNode) {
|
||||
|
@ -66,7 +66,7 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This implementation is not thread
|
||||
* safe</i>.
|
||||
*/
|
||||
public class InsnList {
|
||||
public class InsnList implements Iterable<AbstractInsnNode> {
|
||||
|
||||
/** The number of instructions in this list. */
|
||||
private int size;
|
||||
@ -182,6 +182,7 @@ public class InsnList {
|
||||
*
|
||||
* @return an iterator over the instructions in this list.
|
||||
*/
|
||||
@Override
|
||||
public ListIterator<AbstractInsnNode> iterator() {
|
||||
return iterator(0);
|
||||
}
|
||||
@ -240,7 +241,7 @@ public class InsnList {
|
||||
cache[index] = newInsnNode;
|
||||
newInsnNode.index = index;
|
||||
} else {
|
||||
newInsnNode.index = 0; // newInnsnNode now belongs to an InsnList.
|
||||
newInsnNode.index = 0; // newInsnNode now belongs to an InsnList.
|
||||
}
|
||||
oldInsnNode.index = -1; // oldInsnNode no longer belongs to an InsnList.
|
||||
oldInsnNode.previousInsn = null;
|
||||
@ -565,6 +566,9 @@ public class InsnList {
|
||||
|
||||
@Override
|
||||
public Object previous() {
|
||||
if (previousInsn == null) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
AbstractInsnNode result = previousInsn;
|
||||
nextInsn = result;
|
||||
previousInsn = result.previousInsn;
|
||||
|
@ -114,14 +114,15 @@ public class LocalVariableAnnotationNode extends TypeAnnotationNode {
|
||||
final LabelNode[] end,
|
||||
final int[] index,
|
||||
final String descriptor) {
|
||||
this(Opcodes.ASM7, typeRef, typePath, start, end, index, descriptor);
|
||||
this(/* latest api = */ Opcodes.ASM8, typeRef, typePath, start, end, index, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link LocalVariableAnnotationNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
|
||||
* @param start the fist instructions corresponding to the continuous ranges that make the scope
|
||||
* of this local variable (inclusive).
|
||||
|
@ -96,9 +96,7 @@ public class MethodInsnNode extends AbstractInsnNode {
|
||||
* jdk.internal.org.objectweb.asm.Type#getInternalName()}).
|
||||
* @param name the method's name.
|
||||
* @param descriptor the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
|
||||
* @deprecated use {@link #MethodInsnNode(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public MethodInsnNode(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
|
@ -186,7 +186,7 @@ public class MethodNode extends MethodVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public MethodNode() {
|
||||
this(Opcodes.ASM7);
|
||||
this(/* latest api = */ Opcodes.ASM8);
|
||||
if (getClass() != MethodNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -196,7 +196,8 @@ public class MethodNode extends MethodVisitor {
|
||||
* Constructs an uninitialized {@link MethodNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
*/
|
||||
public MethodNode(final int api) {
|
||||
super(api);
|
||||
@ -222,7 +223,7 @@ public class MethodNode extends MethodVisitor {
|
||||
final String descriptor,
|
||||
final String signature,
|
||||
final String[] exceptions) {
|
||||
this(Opcodes.ASM7, access, name, descriptor, signature, exceptions);
|
||||
this(/* latest api = */ Opcodes.ASM8, access, name, descriptor, signature, exceptions);
|
||||
if (getClass() != MethodNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -232,7 +233,8 @@ public class MethodNode extends MethodVisitor {
|
||||
* Constructs a new {@link MethodNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
|
||||
* the method is synthetic and/or deprecated.
|
||||
* @param name the method's name.
|
||||
@ -255,9 +257,9 @@ public class MethodNode extends MethodVisitor {
|
||||
this.signature = signature;
|
||||
this.exceptions = Util.asArrayList(exceptions);
|
||||
if ((access & Opcodes.ACC_ABSTRACT) == 0) {
|
||||
this.localVariables = new ArrayList<LocalVariableNode>(5);
|
||||
this.localVariables = new ArrayList<>(5);
|
||||
}
|
||||
this.tryCatchBlocks = new ArrayList<TryCatchBlockNode>();
|
||||
this.tryCatchBlocks = new ArrayList<>();
|
||||
this.instructions = new InsnList();
|
||||
}
|
||||
|
||||
@ -268,7 +270,7 @@ public class MethodNode extends MethodVisitor {
|
||||
@Override
|
||||
public void visitParameter(final String name, final int access) {
|
||||
if (parameters == null) {
|
||||
parameters = new ArrayList<ParameterNode>(5);
|
||||
parameters = new ArrayList<>(5);
|
||||
}
|
||||
parameters.add(new ParameterNode(name, access));
|
||||
}
|
||||
@ -290,15 +292,9 @@ public class MethodNode extends MethodVisitor {
|
||||
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
|
||||
AnnotationNode annotation = new AnnotationNode(descriptor);
|
||||
if (visible) {
|
||||
if (visibleAnnotations == null) {
|
||||
visibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
visibleAnnotations.add(annotation);
|
||||
visibleAnnotations = Util.add(visibleAnnotations, annotation);
|
||||
} else {
|
||||
if (invisibleAnnotations == null) {
|
||||
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
invisibleAnnotations.add(annotation);
|
||||
invisibleAnnotations = Util.add(invisibleAnnotations, annotation);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
@ -308,15 +304,9 @@ public class MethodNode extends MethodVisitor {
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
|
||||
if (visible) {
|
||||
if (visibleTypeAnnotations == null) {
|
||||
visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
visibleTypeAnnotations.add(typeAnnotation);
|
||||
visibleTypeAnnotations = Util.add(visibleTypeAnnotations, typeAnnotation);
|
||||
} else {
|
||||
if (invisibleTypeAnnotations == null) {
|
||||
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
invisibleTypeAnnotations.add(typeAnnotation);
|
||||
invisibleTypeAnnotations = Util.add(invisibleTypeAnnotations, typeAnnotation);
|
||||
}
|
||||
return typeAnnotation;
|
||||
}
|
||||
@ -340,29 +330,22 @@ public class MethodNode extends MethodVisitor {
|
||||
int params = Type.getArgumentTypes(desc).length;
|
||||
visibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
|
||||
}
|
||||
if (visibleParameterAnnotations[parameter] == null) {
|
||||
visibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
visibleParameterAnnotations[parameter].add(annotation);
|
||||
visibleParameterAnnotations[parameter] =
|
||||
Util.add(visibleParameterAnnotations[parameter], annotation);
|
||||
} else {
|
||||
if (invisibleParameterAnnotations == null) {
|
||||
int params = Type.getArgumentTypes(desc).length;
|
||||
invisibleParameterAnnotations = (List<AnnotationNode>[]) new List<?>[params];
|
||||
}
|
||||
if (invisibleParameterAnnotations[parameter] == null) {
|
||||
invisibleParameterAnnotations[parameter] = new ArrayList<AnnotationNode>(1);
|
||||
}
|
||||
invisibleParameterAnnotations[parameter].add(annotation);
|
||||
invisibleParameterAnnotations[parameter] =
|
||||
Util.add(invisibleParameterAnnotations[parameter], annotation);
|
||||
}
|
||||
return annotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
if (attrs == null) {
|
||||
attrs = new ArrayList<Attribute>(1);
|
||||
}
|
||||
attrs.add(attribute);
|
||||
attrs = Util.add(attrs, attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -412,33 +395,20 @@ public class MethodNode extends MethodVisitor {
|
||||
instructions.add(new FieldInsnNode(opcode, owner, name, descriptor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
instructions.add(new MethodInsnNode(opcode, owner, name, descriptor, isInterface));
|
||||
}
|
||||
|
||||
@ -500,15 +470,11 @@ public class MethodNode extends MethodVisitor {
|
||||
// Add the annotation to this instruction.
|
||||
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
|
||||
if (visible) {
|
||||
if (currentInsn.visibleTypeAnnotations == null) {
|
||||
currentInsn.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
currentInsn.visibleTypeAnnotations.add(typeAnnotation);
|
||||
currentInsn.visibleTypeAnnotations =
|
||||
Util.add(currentInsn.visibleTypeAnnotations, typeAnnotation);
|
||||
} else {
|
||||
if (currentInsn.invisibleTypeAnnotations == null) {
|
||||
currentInsn.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
currentInsn.invisibleTypeAnnotations.add(typeAnnotation);
|
||||
currentInsn.invisibleTypeAnnotations =
|
||||
Util.add(currentInsn.invisibleTypeAnnotations, typeAnnotation);
|
||||
}
|
||||
return typeAnnotation;
|
||||
}
|
||||
@ -516,8 +482,9 @@ public class MethodNode extends MethodVisitor {
|
||||
@Override
|
||||
public void visitTryCatchBlock(
|
||||
final Label start, final Label end, final Label handler, final String type) {
|
||||
tryCatchBlocks.add(
|
||||
new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type));
|
||||
TryCatchBlockNode tryCatchBlock =
|
||||
new TryCatchBlockNode(getLabelNode(start), getLabelNode(end), getLabelNode(handler), type);
|
||||
tryCatchBlocks = Util.add(tryCatchBlocks, tryCatchBlock);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -526,15 +493,11 @@ public class MethodNode extends MethodVisitor {
|
||||
TryCatchBlockNode tryCatchBlock = tryCatchBlocks.get((typeRef & 0x00FFFF00) >> 8);
|
||||
TypeAnnotationNode typeAnnotation = new TypeAnnotationNode(typeRef, typePath, descriptor);
|
||||
if (visible) {
|
||||
if (tryCatchBlock.visibleTypeAnnotations == null) {
|
||||
tryCatchBlock.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
tryCatchBlock.visibleTypeAnnotations.add(typeAnnotation);
|
||||
tryCatchBlock.visibleTypeAnnotations =
|
||||
Util.add(tryCatchBlock.visibleTypeAnnotations, typeAnnotation);
|
||||
} else {
|
||||
if (tryCatchBlock.invisibleTypeAnnotations == null) {
|
||||
tryCatchBlock.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
|
||||
}
|
||||
tryCatchBlock.invisibleTypeAnnotations.add(typeAnnotation);
|
||||
tryCatchBlock.invisibleTypeAnnotations =
|
||||
Util.add(tryCatchBlock.invisibleTypeAnnotations, typeAnnotation);
|
||||
}
|
||||
return typeAnnotation;
|
||||
}
|
||||
@ -547,9 +510,10 @@ public class MethodNode extends MethodVisitor {
|
||||
final Label start,
|
||||
final Label end,
|
||||
final int index) {
|
||||
localVariables.add(
|
||||
LocalVariableNode localVariable =
|
||||
new LocalVariableNode(
|
||||
name, descriptor, signature, getLabelNode(start), getLabelNode(end), index));
|
||||
name, descriptor, signature, getLabelNode(start), getLabelNode(end), index);
|
||||
localVariables = Util.add(localVariables, localVariable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -565,15 +529,11 @@ public class MethodNode extends MethodVisitor {
|
||||
new LocalVariableAnnotationNode(
|
||||
typeRef, typePath, getLabelNodes(start), getLabelNodes(end), index, descriptor);
|
||||
if (visible) {
|
||||
if (visibleLocalVariableAnnotations == null) {
|
||||
visibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
|
||||
}
|
||||
visibleLocalVariableAnnotations.add(localVariableAnnotation);
|
||||
visibleLocalVariableAnnotations =
|
||||
Util.add(visibleLocalVariableAnnotations, localVariableAnnotation);
|
||||
} else {
|
||||
if (invisibleLocalVariableAnnotations == null) {
|
||||
invisibleLocalVariableAnnotations = new ArrayList<LocalVariableAnnotationNode>(1);
|
||||
}
|
||||
invisibleLocalVariableAnnotations.add(localVariableAnnotation);
|
||||
invisibleLocalVariableAnnotations =
|
||||
Util.add(invisibleLocalVariableAnnotations, localVariableAnnotation);
|
||||
}
|
||||
return localVariableAnnotation;
|
||||
}
|
||||
@ -639,7 +599,7 @@ public class MethodNode extends MethodVisitor {
|
||||
* in more recent versions of the ASM API than the given version.
|
||||
*
|
||||
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
|
||||
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
|
||||
*/
|
||||
public void check(final int api) {
|
||||
if (api == Opcodes.ASM4) {
|
||||
@ -694,7 +654,7 @@ public class MethodNode extends MethodVisitor {
|
||||
throw new UnsupportedClassVersionException();
|
||||
}
|
||||
}
|
||||
if (api != Opcodes.ASM7) {
|
||||
if (api < Opcodes.ASM7) {
|
||||
for (int i = instructions.size() - 1; i >= 0; --i) {
|
||||
AbstractInsnNode insn = instructions.get(i);
|
||||
if (insn instanceof LdcInsnNode) {
|
||||
@ -713,8 +673,7 @@ public class MethodNode extends MethodVisitor {
|
||||
* @param classVisitor a class visitor.
|
||||
*/
|
||||
public void accept(final ClassVisitor classVisitor) {
|
||||
String[] exceptionsArray = new String[this.exceptions.size()];
|
||||
this.exceptions.toArray(exceptionsArray);
|
||||
String[] exceptionsArray = exceptions == null ? null : exceptions.toArray(new String[0]);
|
||||
MethodVisitor methodVisitor =
|
||||
classVisitor.visitMethod(access, name, desc, signature, exceptionsArray);
|
||||
if (methodVisitor != null) {
|
||||
|
@ -115,7 +115,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public ModuleNode(final String name, final int access, final String version) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
if (getClass() != ModuleNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -128,8 +128,8 @@ public class ModuleNode extends ModuleVisitor {
|
||||
/**
|
||||
* Constructs a {@link ModuleNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
|
||||
* or {@link Opcodes#ASM7}.
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
|
||||
* @param name the fully qualified name (using dots) of the module.
|
||||
* @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
|
||||
* ACC_MANDATED}.
|
||||
@ -169,7 +169,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitPackage(final String packaze) {
|
||||
if (packages == null) {
|
||||
packages = new ArrayList<String>(5);
|
||||
packages = new ArrayList<>(5);
|
||||
}
|
||||
packages.add(packaze);
|
||||
}
|
||||
@ -177,7 +177,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitRequire(final String module, final int access, final String version) {
|
||||
if (requires == null) {
|
||||
requires = new ArrayList<ModuleRequireNode>(5);
|
||||
requires = new ArrayList<>(5);
|
||||
}
|
||||
requires.add(new ModuleRequireNode(module, access, version));
|
||||
}
|
||||
@ -185,7 +185,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitExport(final String packaze, final int access, final String... modules) {
|
||||
if (exports == null) {
|
||||
exports = new ArrayList<ModuleExportNode>(5);
|
||||
exports = new ArrayList<>(5);
|
||||
}
|
||||
exports.add(new ModuleExportNode(packaze, access, Util.asArrayList(modules)));
|
||||
}
|
||||
@ -193,7 +193,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitOpen(final String packaze, final int access, final String... modules) {
|
||||
if (opens == null) {
|
||||
opens = new ArrayList<ModuleOpenNode>(5);
|
||||
opens = new ArrayList<>(5);
|
||||
}
|
||||
opens.add(new ModuleOpenNode(packaze, access, Util.asArrayList(modules)));
|
||||
}
|
||||
@ -201,7 +201,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitUse(final String service) {
|
||||
if (uses == null) {
|
||||
uses = new ArrayList<String>(5);
|
||||
uses = new ArrayList<>(5);
|
||||
}
|
||||
uses.add(service);
|
||||
}
|
||||
@ -209,7 +209,7 @@ public class ModuleNode extends ModuleVisitor {
|
||||
@Override
|
||||
public void visitProvide(final String service, final String... providers) {
|
||||
if (provides == null) {
|
||||
provides = new ArrayList<ModuleProvideNode>(5);
|
||||
provides = new ArrayList<>(5);
|
||||
}
|
||||
provides.add(new ModuleProvideNode(service, Util.asArrayList(providers)));
|
||||
}
|
||||
|
234
src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/RecordComponentNode.java
Normal file
234
src/java.base/share/classes/jdk/internal/org/objectweb/asm/tree/RecordComponentNode.java
Normal 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();
|
||||
}
|
||||
}
|
@ -90,7 +90,7 @@ public class TypeAnnotationNode extends AnnotationNode {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) {
|
||||
this(Opcodes.ASM7, typeRef, typePath, descriptor);
|
||||
this(/* latest api = */ Opcodes.ASM8, typeRef, typePath, descriptor);
|
||||
if (getClass() != TypeAnnotationNode.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -100,7 +100,8 @@ public class TypeAnnotationNode extends AnnotationNode {
|
||||
* Constructs a new {@link AnnotationNode}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
|
||||
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
|
||||
|
@ -71,8 +71,14 @@ final class Util {
|
||||
|
||||
private Util() {}
|
||||
|
||||
static <T> List<T> add(final List<T> list, final T element) {
|
||||
List<T> newList = list == null ? new ArrayList<>(1) : list;
|
||||
newList.add(element);
|
||||
return newList;
|
||||
}
|
||||
|
||||
static <T> List<T> asArrayList(final int length) {
|
||||
List<T> list = new ArrayList<T>(length);
|
||||
List<T> list = new ArrayList<>(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
list.add(null);
|
||||
}
|
||||
@ -81,9 +87,9 @@ final class Util {
|
||||
|
||||
static <T> List<T> asArrayList(final T[] array) {
|
||||
if (array == null) {
|
||||
return new ArrayList<T>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<T> list = new ArrayList<T>(array.length);
|
||||
ArrayList<T> list = new ArrayList<>(array.length);
|
||||
for (T t : array) {
|
||||
list.add(t);
|
||||
}
|
||||
@ -92,9 +98,9 @@ final class Util {
|
||||
|
||||
static List<Byte> asArrayList(final byte[] byteArray) {
|
||||
if (byteArray == null) {
|
||||
return new ArrayList<Byte>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Byte> byteList = new ArrayList<Byte>(byteArray.length);
|
||||
ArrayList<Byte> byteList = new ArrayList<>(byteArray.length);
|
||||
for (byte b : byteArray) {
|
||||
byteList.add(b);
|
||||
}
|
||||
@ -103,9 +109,9 @@ final class Util {
|
||||
|
||||
static List<Boolean> asArrayList(final boolean[] booleanArray) {
|
||||
if (booleanArray == null) {
|
||||
return new ArrayList<Boolean>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Boolean> booleanList = new ArrayList<Boolean>(booleanArray.length);
|
||||
ArrayList<Boolean> booleanList = new ArrayList<>(booleanArray.length);
|
||||
for (boolean b : booleanArray) {
|
||||
booleanList.add(b);
|
||||
}
|
||||
@ -114,9 +120,9 @@ final class Util {
|
||||
|
||||
static List<Short> asArrayList(final short[] shortArray) {
|
||||
if (shortArray == null) {
|
||||
return new ArrayList<Short>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Short> shortList = new ArrayList<Short>(shortArray.length);
|
||||
ArrayList<Short> shortList = new ArrayList<>(shortArray.length);
|
||||
for (short s : shortArray) {
|
||||
shortList.add(s);
|
||||
}
|
||||
@ -125,9 +131,9 @@ final class Util {
|
||||
|
||||
static List<Character> asArrayList(final char[] charArray) {
|
||||
if (charArray == null) {
|
||||
return new ArrayList<Character>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Character> charList = new ArrayList<Character>(charArray.length);
|
||||
ArrayList<Character> charList = new ArrayList<>(charArray.length);
|
||||
for (char c : charArray) {
|
||||
charList.add(c);
|
||||
}
|
||||
@ -136,9 +142,9 @@ final class Util {
|
||||
|
||||
static List<Integer> asArrayList(final int[] intArray) {
|
||||
if (intArray == null) {
|
||||
return new ArrayList<Integer>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Integer> intList = new ArrayList<Integer>(intArray.length);
|
||||
ArrayList<Integer> intList = new ArrayList<>(intArray.length);
|
||||
for (int i : intArray) {
|
||||
intList.add(i);
|
||||
}
|
||||
@ -147,9 +153,9 @@ final class Util {
|
||||
|
||||
static List<Float> asArrayList(final float[] floatArray) {
|
||||
if (floatArray == null) {
|
||||
return new ArrayList<Float>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Float> floatList = new ArrayList<Float>(floatArray.length);
|
||||
ArrayList<Float> floatList = new ArrayList<>(floatArray.length);
|
||||
for (float f : floatArray) {
|
||||
floatList.add(f);
|
||||
}
|
||||
@ -158,9 +164,9 @@ final class Util {
|
||||
|
||||
static List<Long> asArrayList(final long[] longArray) {
|
||||
if (longArray == null) {
|
||||
return new ArrayList<Long>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Long> longList = new ArrayList<Long>(longArray.length);
|
||||
ArrayList<Long> longList = new ArrayList<>(longArray.length);
|
||||
for (long l : longArray) {
|
||||
longList.add(l);
|
||||
}
|
||||
@ -169,9 +175,9 @@ final class Util {
|
||||
|
||||
static List<Double> asArrayList(final double[] doubleArray) {
|
||||
if (doubleArray == null) {
|
||||
return new ArrayList<Double>();
|
||||
return new ArrayList<>();
|
||||
}
|
||||
ArrayList<Double> doubleList = new ArrayList<Double>(doubleArray.length);
|
||||
ArrayList<Double> doubleList = new ArrayList<>(doubleArray.length);
|
||||
for (double d : doubleArray) {
|
||||
doubleList.add(d);
|
||||
}
|
||||
@ -179,7 +185,7 @@ final class Util {
|
||||
}
|
||||
|
||||
static <T> List<T> asArrayList(final int length, final T[] array) {
|
||||
List<T> list = new ArrayList<T>(length);
|
||||
List<T> list = new ArrayList<>(length);
|
||||
for (int i = 0; i < length; ++i) {
|
||||
list.add(array[i]); // NOPMD(UseArraysAsList): we convert a part of the array.
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
for (int j = startIndex; j < endIndex; ++j) {
|
||||
List<TryCatchBlockNode> insnHandlers = handlers[j];
|
||||
if (insnHandlers == null) {
|
||||
insnHandlers = new ArrayList<TryCatchBlockNode>();
|
||||
insnHandlers = new ArrayList<>();
|
||||
handlers[j] = insnHandlers;
|
||||
}
|
||||
insnHandlers.add(tryCatchBlock);
|
||||
@ -165,11 +165,11 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
// For each instruction, compute the subroutine to which it belongs.
|
||||
// Follow the main 'subroutine', and collect the jsr instructions to nested subroutines.
|
||||
Subroutine main = new Subroutine(null, method.maxLocals, null);
|
||||
List<AbstractInsnNode> jsrInsns = new ArrayList<AbstractInsnNode>();
|
||||
List<AbstractInsnNode> jsrInsns = new ArrayList<>();
|
||||
findSubroutine(0, main, jsrInsns);
|
||||
// Follow the nested subroutines, and collect their own nested subroutines, until all
|
||||
// subroutines are found.
|
||||
Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<LabelNode, Subroutine>();
|
||||
Map<LabelNode, Subroutine> jsrSubroutines = new HashMap<>();
|
||||
while (!jsrInsns.isEmpty()) {
|
||||
JumpInsnNode jsrInsn = (JumpInsnNode) jsrInsns.remove(0);
|
||||
Subroutine subroutine = jsrSubroutines.get(jsrInsn.label);
|
||||
@ -264,7 +264,7 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
}
|
||||
} else if (insnOpcode == RET) {
|
||||
if (subroutine == null) {
|
||||
throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
|
||||
throw new AnalyzerException(insnNode, "RET instruction outside of a subroutine");
|
||||
}
|
||||
for (int i = 0; i < subroutine.callers.size(); ++i) {
|
||||
JumpInsnNode caller = subroutine.callers.get(i);
|
||||
@ -344,7 +344,7 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
private void findSubroutine(
|
||||
final int insnIndex, final Subroutine subroutine, final List<AbstractInsnNode> jsrInsns)
|
||||
throws AnalyzerException {
|
||||
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<Integer>();
|
||||
ArrayList<Integer> instructionIndicesToProcess = new ArrayList<>();
|
||||
instructionIndicesToProcess.add(insnIndex);
|
||||
while (!instructionIndicesToProcess.isEmpty()) {
|
||||
int currentInsnIndex =
|
||||
@ -490,7 +490,7 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
* @return the created frame.
|
||||
*/
|
||||
protected Frame<V> newFrame(final int numLocals, final int numStack) {
|
||||
return new Frame<V>(numLocals, numStack);
|
||||
return new Frame<>(numLocals, numStack);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -500,7 +500,7 @@ public class Analyzer<V extends Value> implements Opcodes {
|
||||
* @return the created frame.
|
||||
*/
|
||||
protected Frame<V> newFrame(final Frame<? extends V> frame) {
|
||||
return new Frame<V>(frame);
|
||||
return new Frame<>(frame);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +92,7 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
|
||||
* version.
|
||||
*/
|
||||
public BasicInterpreter() {
|
||||
super(ASM7);
|
||||
super(/* latest api = */ ASM8);
|
||||
if (getClass() != BasicInterpreter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -103,7 +103,8 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
|
||||
*
|
||||
* @param api the ASM API version supported by this interpreter. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
*/
|
||||
protected BasicInterpreter(final int api) {
|
||||
super(api);
|
||||
|
@ -78,7 +78,7 @@ public class BasicVerifier extends BasicInterpreter {
|
||||
* use this constructor</i>. Instead, they must use the {@link #BasicVerifier(int)} version.
|
||||
*/
|
||||
public BasicVerifier() {
|
||||
super(ASM7);
|
||||
super(/* latest api = */ ASM8);
|
||||
if (getClass() != BasicVerifier.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -89,7 +89,8 @@ public class BasicVerifier extends BasicInterpreter {
|
||||
*
|
||||
* @param api the ASM API version supported by this interpreter. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
*/
|
||||
protected BasicVerifier(final int api) {
|
||||
super(api);
|
||||
|
@ -151,7 +151,9 @@ public class Frame<V extends Value> {
|
||||
* this frame corresponds to the successor of the jump instruction (i.e. the next instruction
|
||||
* in the instructions sequence).
|
||||
*/
|
||||
public void initJumpTarget(final int opcode, final LabelNode target) {}
|
||||
public void initJumpTarget(final int opcode, final LabelNode target) {
|
||||
// Does nothing by default.
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expected return type of the analyzed method.
|
||||
@ -190,7 +192,7 @@ public class Frame<V extends Value> {
|
||||
*/
|
||||
public V getLocal(final int index) {
|
||||
if (index >= numLocals) {
|
||||
throw new IndexOutOfBoundsException("Trying to access an inexistant local variable");
|
||||
throw new IndexOutOfBoundsException("Trying to get an inexistant local variable " + index);
|
||||
}
|
||||
return values[index];
|
||||
}
|
||||
@ -204,7 +206,7 @@ public class Frame<V extends Value> {
|
||||
*/
|
||||
public void setLocal(final int index, final V value) {
|
||||
if (index >= numLocals) {
|
||||
throw new IndexOutOfBoundsException("Trying to access an inexistant local variable " + index);
|
||||
throw new IndexOutOfBoundsException("Trying to set an inexistant local variable " + index);
|
||||
}
|
||||
values[index] = value;
|
||||
}
|
||||
@ -237,7 +239,7 @@ public class Frame<V extends Value> {
|
||||
* @param value the new value of the stack slot.
|
||||
* @throws IndexOutOfBoundsException if the stack slot does not exist.
|
||||
*/
|
||||
public void setStack(final int index, final V value) throws IndexOutOfBoundsException {
|
||||
public void setStack(final int index, final V value) {
|
||||
values[numLocals + index] = value;
|
||||
}
|
||||
|
||||
@ -379,23 +381,8 @@ public class Frame<V extends Value> {
|
||||
break;
|
||||
case Opcodes.DUP_X2:
|
||||
value1 = pop();
|
||||
if (value1.getSize() == 1) {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
if (value1.getSize() == 1 && executeDupX2(insn, value1, interpreter)) {
|
||||
break;
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP_X2");
|
||||
case Opcodes.DUP2:
|
||||
@ -466,23 +453,8 @@ public class Frame<V extends Value> {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
break;
|
||||
}
|
||||
} else if (executeDupX2(insn, value1, interpreter)) {
|
||||
break;
|
||||
}
|
||||
throw new AnalyzerException(insn, "Illegal use of DUP2_X2");
|
||||
case Opcodes.SWAP:
|
||||
@ -629,36 +601,11 @@ public class Frame<V extends Value> {
|
||||
case Opcodes.INVOKESPECIAL:
|
||||
case Opcodes.INVOKESTATIC:
|
||||
case Opcodes.INVOKEINTERFACE:
|
||||
{
|
||||
List<V> valueList = new ArrayList<V>();
|
||||
String methodDescriptor = ((MethodInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, valueList);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, valueList));
|
||||
}
|
||||
break;
|
||||
}
|
||||
executeInvokeInsn(insn, ((MethodInsnNode) insn).desc, interpreter);
|
||||
break;
|
||||
case Opcodes.INVOKEDYNAMIC:
|
||||
{
|
||||
List<V> valueList = new ArrayList<V>();
|
||||
String methodDesccriptor = ((InvokeDynamicInsnNode) insn).desc;
|
||||
for (int i = Type.getArgumentTypes(methodDesccriptor).length; i > 0; --i) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(methodDesccriptor) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, valueList);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, valueList));
|
||||
}
|
||||
break;
|
||||
}
|
||||
executeInvokeInsn(insn, ((InvokeDynamicInsnNode) insn).desc, interpreter);
|
||||
break;
|
||||
case Opcodes.NEW:
|
||||
push(interpreter.newOperation(insn));
|
||||
break;
|
||||
@ -679,7 +626,7 @@ public class Frame<V extends Value> {
|
||||
interpreter.unaryOperation(insn, pop());
|
||||
break;
|
||||
case Opcodes.MULTIANEWARRAY:
|
||||
List<V> valueList = new ArrayList<V>();
|
||||
List<V> valueList = new ArrayList<>();
|
||||
for (int i = ((MultiANewArrayInsnNode) insn).dims; i > 0; --i) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
@ -694,6 +641,45 @@ public class Frame<V extends Value> {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean executeDupX2(
|
||||
final AbstractInsnNode insn, final V value1, final Interpreter<V> interpreter)
|
||||
throws AnalyzerException {
|
||||
V value2 = pop();
|
||||
if (value2.getSize() == 1) {
|
||||
V value3 = pop();
|
||||
if (value3.getSize() == 1) {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value3);
|
||||
push(value2);
|
||||
push(value1);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
push(interpreter.copyOperation(insn, value1));
|
||||
push(value2);
|
||||
push(value1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void executeInvokeInsn(
|
||||
final AbstractInsnNode insn, final String methodDescriptor, final Interpreter<V> interpreter)
|
||||
throws AnalyzerException {
|
||||
ArrayList<V> valueList = new ArrayList<>();
|
||||
for (int i = Type.getArgumentTypes(methodDescriptor).length; i > 0; --i) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
if (insn.getOpcode() != Opcodes.INVOKESTATIC && insn.getOpcode() != Opcodes.INVOKEDYNAMIC) {
|
||||
valueList.add(0, pop());
|
||||
}
|
||||
if (Type.getReturnType(methodDescriptor) == Type.VOID_TYPE) {
|
||||
interpreter.naryOperation(insn, valueList);
|
||||
} else {
|
||||
push(interpreter.naryOperation(insn, valueList));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the given frame into this frame.
|
||||
*
|
||||
|
@ -124,7 +124,12 @@ public class SimpleVerifier extends BasicVerifier {
|
||||
final Type currentSuperClass,
|
||||
final List<Type> currentClassInterfaces,
|
||||
final boolean isInterface) {
|
||||
this(ASM7, currentClass, currentSuperClass, currentClassInterfaces, isInterface);
|
||||
this(
|
||||
/* latest api = */ ASM8,
|
||||
currentClass,
|
||||
currentSuperClass,
|
||||
currentClassInterfaces,
|
||||
isInterface);
|
||||
if (getClass() != SimpleVerifier.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -136,7 +141,8 @@ public class SimpleVerifier extends BasicVerifier {
|
||||
*
|
||||
* @param api the ASM API version supported by this verifier. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
* @param currentClass the type of the class to be verified.
|
||||
* @param currentSuperClass the type of the super class of the class to be verified.
|
||||
* @param currentClassInterfaces the types of the interfaces directly implemented by the class to
|
||||
@ -285,7 +291,7 @@ public class SimpleVerifier extends BasicVerifier {
|
||||
type1 = type1.getElementType();
|
||||
type2 = type2.getElementType();
|
||||
}
|
||||
do {
|
||||
while (true) {
|
||||
if (type1 == null || isInterface(type1)) {
|
||||
return newArrayValue(Type.getObjectType("java/lang/Object"), numDimensions);
|
||||
}
|
||||
@ -293,7 +299,7 @@ public class SimpleVerifier extends BasicVerifier {
|
||||
if (isAssignableFrom(type1, type2)) {
|
||||
return newArrayValue(type1, numDimensions);
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
}
|
||||
return BasicValue.UNINITIALIZED_VALUE;
|
||||
}
|
||||
|
@ -118,12 +118,18 @@ final class SmallSet<T> extends AbstractSet<T> {
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
return new IteratorImpl<T>(element1, element2);
|
||||
return new IteratorImpl<>(element1, element2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return element1 == null ? 0 : (element2 == null ? 1 : 2);
|
||||
if (element1 == null) {
|
||||
return 0;
|
||||
} else if (element2 == null) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -155,7 +161,7 @@ final class SmallSet<T> extends AbstractSet<T> {
|
||||
if (otherSet.element2 == null) {
|
||||
// If this set also contains exactly one element, we have two distinct elements.
|
||||
if (element2 == null) {
|
||||
return new SmallSet<T>(element1, otherSet.element1);
|
||||
return new SmallSet<>(element1, otherSet.element1);
|
||||
}
|
||||
// If otherSet is included in this set, return this set.
|
||||
if (otherSet.element1 == element1 || otherSet.element1 == element2) {
|
||||
@ -170,7 +176,7 @@ final class SmallSet<T> extends AbstractSet<T> {
|
||||
|
||||
// At this point we know that there are at least 3 distinct elements, so we need a generic set
|
||||
// to store the result.
|
||||
HashSet<T> result = new HashSet<T>(4);
|
||||
HashSet<T> result = new HashSet<>(4);
|
||||
result.add(element1);
|
||||
if (element2 != null) {
|
||||
result.add(element2);
|
||||
|
@ -82,7 +82,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
|
||||
* version.
|
||||
*/
|
||||
public SourceInterpreter() {
|
||||
super(ASM7);
|
||||
super(/* latest api = */ ASM8);
|
||||
if (getClass() != SourceInterpreter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -93,7 +93,8 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
|
||||
*
|
||||
* @param api the ASM API version supported by this interpreter. Must be one of {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM4}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM5}, {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6} or {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7}.
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM6}, {@link jdk.internal.org.objectweb.asm.Opcodes#ASM7} or {@link
|
||||
* jdk.internal.org.objectweb.asm.Opcodes#ASM8}.
|
||||
*/
|
||||
protected SourceInterpreter(final int api) {
|
||||
super(api);
|
||||
@ -235,7 +236,7 @@ public class SourceInterpreter extends Interpreter<SourceValue> implements Opcod
|
||||
}
|
||||
}
|
||||
if (value1.size != value2.size || !containsAll(value1.insns, value2.insns)) {
|
||||
HashSet<AbstractInsnNode> setUnion = new HashSet<AbstractInsnNode>();
|
||||
HashSet<AbstractInsnNode> setUnion = new HashSet<>();
|
||||
setUnion.addAll(value1.insns);
|
||||
setUnion.addAll(value2.insns);
|
||||
return new SourceValue(Math.min(value1.size, value2.size), setUnion);
|
||||
|
@ -108,7 +108,7 @@ public class SourceValue implements Value {
|
||||
*/
|
||||
public SourceValue(final int size, final AbstractInsnNode insnNode) {
|
||||
this.size = size;
|
||||
this.insns = new SmallSet<AbstractInsnNode>(insnNode);
|
||||
this.insns = new SmallSet<>(insnNode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -92,7 +92,7 @@ final class Subroutine {
|
||||
Subroutine(final LabelNode start, final int maxLocals, final JumpInsnNode caller) {
|
||||
this.start = start;
|
||||
this.localsUsed = new boolean[maxLocals];
|
||||
this.callers = new ArrayList<JumpInsnNode>();
|
||||
this.callers = new ArrayList<>();
|
||||
callers.add(caller);
|
||||
}
|
||||
|
||||
@ -103,9 +103,8 @@ final class Subroutine {
|
||||
*/
|
||||
Subroutine(final Subroutine subroutine) {
|
||||
this.start = subroutine.start;
|
||||
this.localsUsed = new boolean[subroutine.localsUsed.length];
|
||||
this.callers = new ArrayList<JumpInsnNode>(subroutine.callers);
|
||||
System.arraycopy(subroutine.localsUsed, 0, this.localsUsed, 0, subroutine.localsUsed.length);
|
||||
this.localsUsed = subroutine.localsUsed.clone();
|
||||
this.callers = new ArrayList<>(subroutine.callers);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,8 +59,11 @@
|
||||
package jdk.internal.org.objectweb.asm.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.Attribute;
|
||||
import jdk.internal.org.objectweb.asm.ConstantDynamic;
|
||||
@ -78,6 +81,11 @@ import jdk.internal.org.objectweb.asm.TypePath;
|
||||
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
|
||||
public class ASMifier extends Printer {
|
||||
|
||||
/** The help message shown when command line arguments are incorrect. */
|
||||
private static final String USAGE =
|
||||
"Prints the ASM code to generate the given class.\n"
|
||||
+ "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
|
||||
|
||||
/** A pseudo access flag used to distinguish class access flags. */
|
||||
private static final int ACCESS_CLASS = 0x40000;
|
||||
|
||||
@ -92,15 +100,27 @@ public class ASMifier extends Printer {
|
||||
|
||||
private static final String ANNOTATION_VISITOR = "annotationVisitor";
|
||||
private static final String ANNOTATION_VISITOR0 = "annotationVisitor0 = ";
|
||||
private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
|
||||
private static final String COMMA = "\", \"";
|
||||
private static final String END_ARRAY = " });\n";
|
||||
private static final String END_PARAMETERS = ");\n\n";
|
||||
private static final String NEW_OBJECT_ARRAY = ", new Object[] {";
|
||||
private static final String VISIT_END = ".visitEnd();\n";
|
||||
|
||||
private static final List<String> FRAME_TYPES =
|
||||
Collections.unmodifiableList(
|
||||
Arrays.asList(
|
||||
"Opcodes.TOP",
|
||||
"Opcodes.INTEGER",
|
||||
"Opcodes.FLOAT",
|
||||
"Opcodes.DOUBLE",
|
||||
"Opcodes.LONG",
|
||||
"Opcodes.NULL",
|
||||
"Opcodes.UNINITIALIZED_THIS"));
|
||||
|
||||
private static final Map<Integer, String> CLASS_VERSIONS;
|
||||
|
||||
static {
|
||||
HashMap<Integer, String> classVersions = new HashMap<Integer, String>();
|
||||
HashMap<Integer, String> classVersions = new HashMap<>();
|
||||
classVersions.put(Opcodes.V1_1, "V1_1");
|
||||
classVersions.put(Opcodes.V1_2, "V1_2");
|
||||
classVersions.put(Opcodes.V1_3, "V1_3");
|
||||
@ -113,6 +133,9 @@ public class ASMifier extends Printer {
|
||||
classVersions.put(Opcodes.V10, "V10");
|
||||
classVersions.put(Opcodes.V11, "V11");
|
||||
classVersions.put(Opcodes.V12, "V12");
|
||||
classVersions.put(Opcodes.V13, "V13");
|
||||
classVersions.put(Opcodes.V14, "V14");
|
||||
classVersions.put(Opcodes.V15, "V15");
|
||||
CLASS_VERSIONS = Collections.unmodifiableMap(classVersions);
|
||||
}
|
||||
|
||||
@ -132,7 +155,7 @@ public class ASMifier extends Printer {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public ASMifier() {
|
||||
this(Opcodes.ASM7, "classWriter", 0);
|
||||
this(/* latest api = */ Opcodes.ASM8, "classWriter", 0);
|
||||
if (getClass() != ASMifier.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -142,7 +165,7 @@ public class ASMifier extends Printer {
|
||||
* Constructs a new {@link ASMifier}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this class. Must be one of {@link Opcodes#ASM4},
|
||||
* {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link Opcodes#ASM8}.
|
||||
* @param visitorVariableName the name of the visitor variable in the produced code.
|
||||
* @param annotationVisitorId identifier of the annotation visitor variable in the produced code.
|
||||
*/
|
||||
@ -162,10 +185,22 @@ public class ASMifier extends Printer {
|
||||
* @throws IOException if the class cannot be found, or if an IOException occurs.
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
String usage =
|
||||
"Prints the ASM code to generate the given class.\n"
|
||||
+ "Usage: ASMifier [-debug] <fully qualified class name or class file name>";
|
||||
main(usage, new ASMifier(), args);
|
||||
main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the ASM source code to generate the given class to the given output.
|
||||
*
|
||||
* <p>Usage: ASMifier [-debug] <binary class name or class file name>
|
||||
*
|
||||
* @param args the command line arguments.
|
||||
* @param output where to print the result.
|
||||
* @param logger where to log errors.
|
||||
* @throws IOException if the class cannot be found, or if an IOException occurs.
|
||||
*/
|
||||
static void main(final String[] args, final PrintWriter output, final PrintWriter logger)
|
||||
throws IOException {
|
||||
main(args, USAGE, new ASMifier(), output, logger);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -189,7 +224,7 @@ public class ASMifier extends Printer {
|
||||
simpleName = name;
|
||||
} else {
|
||||
text.add("package asm." + name.substring(0, lastSlashIndex).replace('/', '.') + ";\n");
|
||||
simpleName = name.substring(lastSlashIndex + 1).replace('-', '_');
|
||||
simpleName = name.substring(lastSlashIndex + 1).replaceAll("[-\\(\\)]", "_");
|
||||
}
|
||||
}
|
||||
text.add("import jdk.internal.org.objectweb.asm.AnnotationVisitor;\n");
|
||||
@ -202,12 +237,14 @@ public class ASMifier extends Printer {
|
||||
text.add("import jdk.internal.org.objectweb.asm.Label;\n");
|
||||
text.add("import jdk.internal.org.objectweb.asm.MethodVisitor;\n");
|
||||
text.add("import jdk.internal.org.objectweb.asm.Opcodes;\n");
|
||||
text.add("import jdk.internal.org.objectweb.asm.RecordComponentVisitor;\n");
|
||||
text.add("import jdk.internal.org.objectweb.asm.Type;\n");
|
||||
text.add("import jdk.internal.org.objectweb.asm.TypePath;\n");
|
||||
text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
|
||||
text.add("public static byte[] dump () throws Exception {\n\n");
|
||||
text.add("ClassWriter classWriter = new ClassWriter(0);\n");
|
||||
text.add("FieldVisitor fieldVisitor;\n");
|
||||
text.add("RecordComponentVisitor recordComponentVisitor;\n");
|
||||
text.add("MethodVisitor methodVisitor;\n");
|
||||
text.add("AnnotationVisitor annotationVisitor0;\n\n");
|
||||
|
||||
@ -275,7 +312,7 @@ public class ASMifier extends Printer {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("classWriter.visitNestHost(");
|
||||
appendConstant(nestHost);
|
||||
stringBuilder.append(");\n\n");
|
||||
stringBuilder.append(END_PARAMETERS);
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@ -313,7 +350,23 @@ public class ASMifier extends Printer {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("classWriter.visitNestMember(");
|
||||
appendConstant(nestMember);
|
||||
stringBuilder.append(");\n\n");
|
||||
stringBuilder.append(END_PARAMETERS);
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("classWriter.visitPermittedSubtypeExperimental(");
|
||||
appendConstant(permittedSubtype);
|
||||
stringBuilder.append(END_PARAMETERS);
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@ -333,6 +386,25 @@ public class ASMifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASMifier visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("{\n");
|
||||
stringBuilder.append("recordComponentVisitor = classWriter.visitRecordComponent(");
|
||||
appendConstant(name);
|
||||
stringBuilder.append(", ");
|
||||
appendConstant(descriptor);
|
||||
stringBuilder.append(", ");
|
||||
appendConstant(signature);
|
||||
stringBuilder.append(");\n");
|
||||
text.add(stringBuilder.toString());
|
||||
ASMifier asmifier = createASMifier("recordComponentVisitor", 0);
|
||||
text.add(asmifier.getText());
|
||||
text.add("}\n");
|
||||
return asmifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASMifier visitField(
|
||||
final int access,
|
||||
@ -441,27 +513,18 @@ public class ASMifier extends Printer {
|
||||
|
||||
@Override
|
||||
public void visitExport(final String packaze, final int access, final String... modules) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("moduleVisitor.visitExport(");
|
||||
appendConstant(packaze);
|
||||
stringBuilder.append(", ");
|
||||
appendAccessFlags(access | ACCESS_MODULE);
|
||||
if (modules != null && modules.length > 0) {
|
||||
stringBuilder.append(", new String[] {");
|
||||
for (int i = 0; i < modules.length; ++i) {
|
||||
stringBuilder.append(i == 0 ? " " : ", ");
|
||||
appendConstant(modules[i]);
|
||||
}
|
||||
stringBuilder.append(" }");
|
||||
}
|
||||
stringBuilder.append(");\n");
|
||||
text.add(stringBuilder.toString());
|
||||
visitExportOrOpen("moduleVisitor.visitExport(", packaze, access, modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOpen(final String packaze, final int access, final String... modules) {
|
||||
visitExportOrOpen("moduleVisitor.visitOpen(", packaze, access, modules);
|
||||
}
|
||||
|
||||
private void visitExportOrOpen(
|
||||
final String visitMethod, final String packaze, final int access, final String... modules) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("moduleVisitor.visitOpen(");
|
||||
stringBuilder.append(visitMethod);
|
||||
appendConstant(packaze);
|
||||
stringBuilder.append(", ");
|
||||
appendAccessFlags(access | ACCESS_MODULE);
|
||||
@ -579,6 +642,33 @@ public class ASMifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Record components
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public ASMifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
|
||||
return visitAnnotation(descriptor, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASMifier visitRecordComponentTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordComponentAttribute(final Attribute attribute) {
|
||||
visitAttribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordComponentEnd() {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(name).append(VISIT_END);
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Fields
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -805,37 +895,8 @@ public class ASMifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
@ -1205,14 +1266,12 @@ public class ASMifier extends Printer {
|
||||
public void visitAttribute(final Attribute attribute) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append("// ATTRIBUTE ").append(attribute.type).append('\n');
|
||||
if (attribute instanceof ASMifiable) {
|
||||
if (attribute instanceof ASMifierSupport) {
|
||||
if (labelNames == null) {
|
||||
labelNames = new HashMap<Label, String>();
|
||||
labelNames = new HashMap<>();
|
||||
}
|
||||
stringBuilder.append("{\n");
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
((ASMifiable) attribute).asmify(stringBuffer, "attribute", labelNames);
|
||||
stringBuilder.append(stringBuffer.toString());
|
||||
((ASMifierSupport) attribute).asmify(stringBuilder, "attribute", labelNames);
|
||||
stringBuilder.append(name).append(".visitAttribute(attribute);\n");
|
||||
stringBuilder.append("}\n");
|
||||
}
|
||||
@ -1233,7 +1292,7 @@ public class ASMifier extends Printer {
|
||||
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
|
||||
protected ASMifier createASMifier(
|
||||
final String visitorVariableName, final int annotationVisitorId) {
|
||||
return new ASMifier(Opcodes.ASM7, visitorVariableName, annotationVisitorId);
|
||||
return new ASMifier(api, visitorVariableName, annotationVisitorId);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1379,6 +1438,13 @@ public class ASMifier extends Printer {
|
||||
stringBuilder.append("ACC_DEPRECATED");
|
||||
isEmpty = false;
|
||||
}
|
||||
if ((accessFlags & Opcodes.ACC_RECORD) != 0) {
|
||||
if (!isEmpty) {
|
||||
stringBuilder.append(" | ");
|
||||
}
|
||||
stringBuilder.append("ACC_RECORD");
|
||||
isEmpty = false;
|
||||
}
|
||||
if ((accessFlags & (Opcodes.ACC_MANDATED | Opcodes.ACC_MODULE)) != 0) {
|
||||
if (!isEmpty) {
|
||||
stringBuilder.append(" | ");
|
||||
@ -1415,17 +1481,17 @@ public class ASMifier extends Printer {
|
||||
stringBuilder.append("new Handle(");
|
||||
Handle handle = (Handle) value;
|
||||
stringBuilder.append("Opcodes.").append(HANDLE_TAG[handle.getTag()]).append(", \"");
|
||||
stringBuilder.append(handle.getOwner()).append("\", \"");
|
||||
stringBuilder.append(handle.getName()).append("\", \"");
|
||||
stringBuilder.append(handle.getOwner()).append(COMMA);
|
||||
stringBuilder.append(handle.getName()).append(COMMA);
|
||||
stringBuilder.append(handle.getDesc()).append("\", ");
|
||||
stringBuilder.append(handle.isInterface()).append(")");
|
||||
} else if (value instanceof ConstantDynamic) {
|
||||
stringBuilder.append("new ConstantDynamic(\"");
|
||||
ConstantDynamic constantDynamic = (ConstantDynamic) value;
|
||||
stringBuilder.append(constantDynamic.getName()).append("\", \"");
|
||||
stringBuilder.append(constantDynamic.getName()).append(COMMA);
|
||||
stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
|
||||
appendConstant(constantDynamic.getBootstrapMethod());
|
||||
stringBuilder.append(", new Object[] {");
|
||||
stringBuilder.append(NEW_OBJECT_ARRAY);
|
||||
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
|
||||
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
|
||||
appendConstant(constantDynamic.getBootstrapMethodArgument(i));
|
||||
@ -1542,31 +1608,7 @@ public class ASMifier extends Printer {
|
||||
if (frameTypes[i] instanceof String) {
|
||||
appendConstant(frameTypes[i]);
|
||||
} else if (frameTypes[i] instanceof Integer) {
|
||||
switch (((Integer) frameTypes[i]).intValue()) {
|
||||
case 0:
|
||||
stringBuilder.append("Opcodes.TOP");
|
||||
break;
|
||||
case 1:
|
||||
stringBuilder.append("Opcodes.INTEGER");
|
||||
break;
|
||||
case 2:
|
||||
stringBuilder.append("Opcodes.FLOAT");
|
||||
break;
|
||||
case 3:
|
||||
stringBuilder.append("Opcodes.DOUBLE");
|
||||
break;
|
||||
case 4:
|
||||
stringBuilder.append("Opcodes.LONG");
|
||||
break;
|
||||
case 5:
|
||||
stringBuilder.append("Opcodes.NULL");
|
||||
break;
|
||||
case 6:
|
||||
stringBuilder.append("Opcodes.UNINITIALIZED_THIS");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue()));
|
||||
} else {
|
||||
appendLabel((Label) frameTypes[i]);
|
||||
}
|
||||
@ -1582,7 +1624,7 @@ public class ASMifier extends Printer {
|
||||
*/
|
||||
protected void declareLabel(final Label label) {
|
||||
if (labelNames == null) {
|
||||
labelNames = new HashMap<Label, String>();
|
||||
labelNames = new HashMap<>();
|
||||
}
|
||||
String labelName = labelNames.get(label);
|
||||
if (labelName == null) {
|
||||
|
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is available under and governed by the GNU General Public
|
||||
* License version 2 only, as published by the Free Software Foundation.
|
||||
* However, the following notice accompanied the original version of this
|
||||
* file:
|
||||
*
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2011 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.util;
|
||||
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.Label;
|
||||
|
||||
/**
|
||||
* An {@link jdk.internal.org.objectweb.asm.Attribute} that can generate the ASM code to create an equivalent
|
||||
* attribute.
|
||||
*
|
||||
* @author Eugene Kuleshov
|
||||
*/
|
||||
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
|
||||
public interface ASMifierSupport {
|
||||
|
||||
/**
|
||||
* Generates the ASM code to create an attribute equal to this attribute.
|
||||
*
|
||||
* @param outputBuilder where the generated code must be appended.
|
||||
* @param visitorVariableName the name of the visitor variable in the produced code.
|
||||
* @param labelNames the names of the labels in the generated code.
|
||||
*/
|
||||
void asmify(
|
||||
StringBuilder outputBuilder, String visitorVariableName, Map<Label, String> labelNames);
|
||||
}
|
@ -83,7 +83,7 @@ public class CheckAnnotationAdapter extends AnnotationVisitor {
|
||||
}
|
||||
|
||||
CheckAnnotationAdapter(final AnnotationVisitor annotationVisitor, final boolean useNamedValues) {
|
||||
super(Opcodes.ASM7, annotationVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM8, annotationVisitor);
|
||||
this.useNamedValue = useNamedValues;
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
import jdk.internal.org.objectweb.asm.TypeReference;
|
||||
@ -140,6 +141,11 @@ import jdk.internal.org.objectweb.asm.tree.analysis.SimpleVerifier;
|
||||
*/
|
||||
public class CheckClassAdapter extends ClassVisitor {
|
||||
|
||||
/** The help message shown when command line arguments are incorrect. */
|
||||
private static final String USAGE =
|
||||
"Verifies the given class.\n"
|
||||
+ "Usage: CheckClassAdapter <fully qualified class name or class file name>";
|
||||
|
||||
private static final String ERROR_AT = ": error at index ";
|
||||
|
||||
/** Whether the bytecode must be checked with a BasicVerifier. */
|
||||
@ -199,7 +205,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public CheckClassAdapter(final ClassVisitor classVisitor, final boolean checkDataFlow) {
|
||||
this(Opcodes.ASM7, classVisitor, checkDataFlow);
|
||||
this(/* latest api = */ Opcodes.ASM8, classVisitor, checkDataFlow);
|
||||
if (getClass() != CheckClassAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -209,7 +215,8 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
* Constructs a new {@link CheckClassAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param classVisitor the class visitor to which this adapter must delegate calls.
|
||||
* @param checkDataFlow {@literal true} to perform basic data flow checks, or {@literal false} to
|
||||
* not perform any data flow check (see {@link CheckMethodAdapter}). This option requires
|
||||
@ -218,7 +225,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
protected CheckClassAdapter(
|
||||
final int api, final ClassVisitor classVisitor, final boolean checkDataFlow) {
|
||||
super(api, classVisitor);
|
||||
this.labelInsnIndices = new HashMap<Label, Integer>();
|
||||
this.labelInsnIndices = new HashMap<>();
|
||||
this.checkDataFlow = checkDataFlow;
|
||||
}
|
||||
|
||||
@ -250,6 +257,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
| Opcodes.ACC_ANNOTATION
|
||||
| Opcodes.ACC_ENUM
|
||||
| Opcodes.ACC_DEPRECATED
|
||||
| Opcodes.ACC_RECORD
|
||||
| Opcodes.ACC_MODULE);
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("Illegal class name (null)");
|
||||
@ -345,6 +353,20 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
super.visitNestMember(nestMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
checkState();
|
||||
CheckMethodAdapter.checkInternalName(version, permittedSubtype, "permittedSubtype");
|
||||
super.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOuterClass(final String owner, final String name, final String descriptor) {
|
||||
checkState();
|
||||
@ -393,6 +415,19 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
checkState();
|
||||
CheckMethodAdapter.checkUnqualifiedName(version, name, "record component name");
|
||||
CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
|
||||
if (signature != null) {
|
||||
checkFieldSignature(signature);
|
||||
}
|
||||
return new CheckRecordComponentAdapter(
|
||||
api, super.visitRecordComponent(name, descriptor, signature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
@ -412,6 +447,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
| Opcodes.ACC_TRANSIENT
|
||||
| Opcodes.ACC_SYNTHETIC
|
||||
| Opcodes.ACC_ENUM
|
||||
| Opcodes.ACC_MANDATED
|
||||
| Opcodes.ACC_DEPRECATED);
|
||||
CheckMethodAdapter.checkUnqualifiedName(version, name, "field name");
|
||||
CheckMethodAdapter.checkDescriptor(version, descriptor, /* canBeVoid = */ false);
|
||||
@ -446,6 +482,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
| Opcodes.ACC_ABSTRACT
|
||||
| Opcodes.ACC_STRICT
|
||||
| Opcodes.ACC_SYNTHETIC
|
||||
| Opcodes.ACC_MANDATED
|
||||
| Opcodes.ACC_DEPRECATED);
|
||||
if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
|
||||
CheckMethodAdapter.checkMethodIdentifier(version, name, "method name");
|
||||
@ -979,10 +1016,19 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
* @throws IOException if the class cannot be found, or if an IO exception occurs.
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
main(args, new PrintWriter(System.err, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given class.
|
||||
*
|
||||
* @param args the command line arguments.
|
||||
* @param logger where to log errors.
|
||||
* @throws IOException if the class cannot be found, or if an IO exception occurs.
|
||||
*/
|
||||
static void main(final String[] args, final PrintWriter logger) throws IOException {
|
||||
if (args.length != 1) {
|
||||
System.err.println(
|
||||
"Verifies the given class.\n"
|
||||
+ "Usage: CheckClassAdapter <fully qualified class name or class file name>");
|
||||
logger.println(USAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -995,7 +1041,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
classReader = new ClassReader(args[0]);
|
||||
}
|
||||
|
||||
verify(classReader, false, new PrintWriter(System.err));
|
||||
verify(classReader, false, logger);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1019,6 +1065,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
* @param printResults whether to print the results of the bytecode verification.
|
||||
* @param printWriter where the results (or the stack trace in case of error) must be printed.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void verify(
|
||||
final ClassReader classReader,
|
||||
final ClassLoader loader,
|
||||
@ -1026,12 +1073,13 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
final PrintWriter printWriter) {
|
||||
ClassNode classNode = new ClassNode();
|
||||
classReader.accept(
|
||||
new CheckClassAdapter(Opcodes.ASM7, classNode, false) {}, ClassReader.SKIP_DEBUG);
|
||||
new CheckClassAdapter(Opcodes.ASM9_EXPERIMENTAL, classNode, false) {},
|
||||
ClassReader.SKIP_DEBUG);
|
||||
|
||||
Type syperType = classNode.superName == null ? null : Type.getObjectType(classNode.superName);
|
||||
List<MethodNode> methods = classNode.methods;
|
||||
|
||||
List<Type> interfaces = new ArrayList<Type>();
|
||||
List<Type> interfaces = new ArrayList<>();
|
||||
for (String interfaceName : classNode.interfaces) {
|
||||
interfaces.add(Type.getObjectType(interfaceName));
|
||||
}
|
||||
@ -1043,7 +1091,7 @@ public class CheckClassAdapter extends ClassVisitor {
|
||||
syperType,
|
||||
interfaces,
|
||||
(classNode.access & Opcodes.ACC_INTERFACE) != 0);
|
||||
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
|
||||
Analyzer<BasicValue> analyzer = new Analyzer<>(verifier);
|
||||
if (loader != null) {
|
||||
verifier.setClassLoader(loader);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ public class CheckFieldAdapter extends FieldVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public CheckFieldAdapter(final FieldVisitor fieldVisitor) {
|
||||
this(Opcodes.ASM7, fieldVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, fieldVisitor);
|
||||
if (getClass() != CheckFieldAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -93,7 +93,8 @@ public class CheckFieldAdapter extends FieldVisitor {
|
||||
* Constructs a new {@link CheckFieldAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param fieldVisitor the field visitor to which this adapter must delegate calls.
|
||||
*/
|
||||
protected CheckFieldAdapter(final int api, final FieldVisitor fieldVisitor) {
|
||||
|
@ -61,6 +61,7 @@ package jdk.internal.org.objectweb.asm.util;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -397,7 +398,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
*/
|
||||
public CheckMethodAdapter(
|
||||
final MethodVisitor methodVisitor, final Map<Label, Integer> labelInsnIndices) {
|
||||
this(Opcodes.ASM7, methodVisitor, labelInsnIndices);
|
||||
this(/* latest api = */ Opcodes.ASM8, methodVisitor, labelInsnIndices);
|
||||
if (getClass() != CheckMethodAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -408,7 +409,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
* data flow check (see {@link #CheckMethodAdapter(int,String,String,MethodVisitor,Map)}).
|
||||
*
|
||||
* @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param methodVisitor the method visitor to which this adapter must delegate calls.
|
||||
* @param labelInsnIndices the index of the instruction designated by each visited label so far
|
||||
* (in other methods). This map is updated with the labels from the visited method.
|
||||
@ -419,8 +421,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
final Map<Label, Integer> labelInsnIndices) {
|
||||
super(api, methodVisitor);
|
||||
this.labelInsnIndices = labelInsnIndices;
|
||||
this.referencedLabels = new HashSet<Label>();
|
||||
this.handlers = new ArrayList<Label>();
|
||||
this.referencedLabels = new HashSet<>();
|
||||
this.handlers = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -443,7 +445,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
final String descriptor,
|
||||
final MethodVisitor methodVisitor,
|
||||
final Map<Label, Integer> labelInsnIndices) {
|
||||
this(Opcodes.ASM7, access, name, descriptor, methodVisitor, labelInsnIndices);
|
||||
this(
|
||||
/* latest api = */ Opcodes.ASM8, access, name, descriptor, methodVisitor, labelInsnIndices);
|
||||
if (getClass() != CheckMethodAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -455,7 +458,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
* instruction IRETURN, or the invalid sequence IADD L2I will be detected.
|
||||
*
|
||||
* @param api the ASM API version implemented by this CheckMethodAdapter. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param access the method's access flags.
|
||||
* @param name the method's name.
|
||||
* @param descriptor the method's descriptor (see {@link Type}).
|
||||
@ -475,7 +479,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
new MethodNode(api, access, name, descriptor, null, null) {
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier());
|
||||
Analyzer<BasicValue> analyzer = new Analyzer<>(new BasicVerifier());
|
||||
try {
|
||||
analyzer.analyze("dummy", this);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
@ -488,7 +492,9 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
} catch (AnalyzerException e) {
|
||||
throwError(analyzer, e);
|
||||
}
|
||||
accept(methodVisitor);
|
||||
if (methodVisitor != null) {
|
||||
accept(methodVisitor);
|
||||
}
|
||||
}
|
||||
|
||||
private void throwError(final Analyzer<BasicValue> analyzer, final Exception e) {
|
||||
@ -735,42 +741,20 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
++insnCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final int opcodeAndSource,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (api < Opcodes.ASM5 && (opcodeAndSource & Opcodes.SOURCE_DEPRECATED) == 0) {
|
||||
// Redirect the call to the deprecated version of this method.
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
int opcode = opcodeAndSource & ~Opcodes.SOURCE_MASK;
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
checkVisitCodeCalled();
|
||||
checkVisitMaxsNotCalled();
|
||||
checkOpcodeMethod(opcode, Method.VISIT_METHOD_INSN);
|
||||
@ -789,13 +773,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
throw new IllegalArgumentException(
|
||||
"INVOKESPECIAL can't be used with interfaces prior to Java 8");
|
||||
}
|
||||
|
||||
// Calling super.visitMethodInsn requires to call the correct version depending on this.api
|
||||
// (otherwise infinite loops can occur). To simplify and to make it easier to automatically
|
||||
// remove the backward compatibility code, we inline the code of the overridden method here.
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
super.visitMethodInsn(opcodeAndSource, owner, name, descriptor, isInterface);
|
||||
++insnCount;
|
||||
}
|
||||
|
||||
@ -879,9 +857,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
checkLabel(labels[i], false, "label at index " + i);
|
||||
}
|
||||
super.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
for (Label label : labels) {
|
||||
referencedLabels.add(label);
|
||||
}
|
||||
Collections.addAll(referencedLabels, labels);
|
||||
++insnCount;
|
||||
}
|
||||
|
||||
@ -898,9 +874,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
}
|
||||
super.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
referencedLabels.add(dflt);
|
||||
for (Label label : labels) {
|
||||
referencedLabels.add(label);
|
||||
}
|
||||
Collections.addAll(referencedLabels, labels);
|
||||
++insnCount;
|
||||
}
|
||||
|
||||
@ -997,6 +971,9 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
checkVisitMaxsNotCalled();
|
||||
checkUnqualifiedName(version, name, "name");
|
||||
checkDescriptor(version, descriptor, false);
|
||||
if (signature != null) {
|
||||
CheckClassAdapter.checkFieldSignature(signature);
|
||||
}
|
||||
checkLabel(start, true, START_LABEL);
|
||||
checkLabel(end, true, END_LABEL);
|
||||
checkUnsignedShort(index, INVALID_LOCAL_VARIABLE_INDEX);
|
||||
@ -1130,7 +1107,8 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
|| value == Opcodes.NULL
|
||||
|| value == Opcodes.UNINITIALIZED_THIS) {
|
||||
return;
|
||||
} else if (value instanceof String) {
|
||||
}
|
||||
if (value instanceof String) {
|
||||
checkInternalName(version, (String) value, "Invalid stack frame value");
|
||||
} else if (value instanceof Label) {
|
||||
referencedLabels.add((Label) value);
|
||||
@ -1314,7 +1292,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
* @param message the message to use in case of error.
|
||||
*/
|
||||
static void checkMethodIdentifier(final int version, final String name, final String message) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
|
||||
}
|
||||
if ((version & 0xFFFF) >= Opcodes.V1_5) {
|
||||
@ -1347,7 +1325,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
* @param message the message to use in case of error.
|
||||
*/
|
||||
static void checkInternalName(final int version, final String name, final String message) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new IllegalArgumentException(INVALID + message + MUST_NOT_BE_NULL_OR_EMPTY);
|
||||
}
|
||||
if (name.charAt(0) == '[') {
|
||||
@ -1370,10 +1348,10 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
int startIndex = 0;
|
||||
int slashIndex;
|
||||
while ((slashIndex = name.indexOf('/', startIndex + 1)) != -1) {
|
||||
CheckMethodAdapter.checkIdentifier(version, name, startIndex, slashIndex, null);
|
||||
checkIdentifier(version, name, startIndex, slashIndex, null);
|
||||
startIndex = slashIndex + 1;
|
||||
}
|
||||
CheckMethodAdapter.checkIdentifier(version, name, startIndex, name.length(), null);
|
||||
checkIdentifier(version, name, startIndex, name.length(), null);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(
|
||||
INVALID + message + " (must be an internal class name): " + name, e);
|
||||
@ -1457,7 +1435,7 @@ public class CheckMethodAdapter extends MethodVisitor {
|
||||
* @param descriptor the string to be checked.
|
||||
*/
|
||||
static void checkMethodDescriptor(final int version, final String descriptor) {
|
||||
if (descriptor == null || descriptor.isEmpty()) {
|
||||
if (descriptor == null || descriptor.length() == 0) {
|
||||
throw new IllegalArgumentException("Invalid method descriptor (must not be null or empty)");
|
||||
}
|
||||
if (descriptor.charAt(0) != '(' || descriptor.length() < 3) {
|
||||
|
@ -102,7 +102,7 @@ public class CheckModuleAdapter extends ModuleVisitor {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public CheckModuleAdapter(final ModuleVisitor moduleVisitor, final boolean isOpen) {
|
||||
this(Opcodes.ASM7, moduleVisitor, isOpen);
|
||||
this(/* latest api = */ Opcodes.ASM8, moduleVisitor, isOpen);
|
||||
if (getClass() != CheckModuleAdapter.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -112,7 +112,8 @@ public class CheckModuleAdapter extends ModuleVisitor {
|
||||
* Constructs a new {@link CheckModuleAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param moduleVisitor the module visitor to which this adapter must delegate calls.
|
||||
* @param isOpen whether the visited module is open. Open modules have their {@link
|
||||
* Opcodes#ACC_OPEN} access flag set in {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitModule}.
|
||||
@ -231,12 +232,12 @@ public class CheckModuleAdapter extends ModuleVisitor {
|
||||
|
||||
NameSet(final String type) {
|
||||
this.type = type;
|
||||
this.names = new HashSet<String>();
|
||||
this.names = new HashSet<>();
|
||||
}
|
||||
|
||||
void checkNameNotAlreadyDeclared(final String name) {
|
||||
if (!names.add(name)) {
|
||||
throw new IllegalArgumentException(type + " " + name + " already declared");
|
||||
throw new IllegalArgumentException(type + " '" + name + "' already declared");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
151
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckRecordComponentAdapter.java
Normal file
151
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/CheckRecordComponentAdapter.java
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -154,14 +154,15 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
* null}.
|
||||
*/
|
||||
public CheckSignatureAdapter(final int type, final SignatureVisitor signatureVisitor) {
|
||||
this(Opcodes.ASM7, type, signatureVisitor);
|
||||
this(/* latest api = */ Opcodes.ASM8, type, signatureVisitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@link CheckSignatureAdapter}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
* @param type the type of signature to be checked. See {@link #CLASS_SIGNATURE}, {@link
|
||||
* #METHOD_SIGNATURE} and {@link #TYPE_SIGNATURE}.
|
||||
* @param signatureVisitor the visitor to which this adapter must delegate calls. May be {@literal
|
||||
@ -202,7 +203,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
@Override
|
||||
public SignatureVisitor visitInterfaceBound() {
|
||||
if (type == TYPE_SIGNATURE || !VISIT_INTERFACE_BOUND_STATES.contains(state)) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
return new CheckSignatureAdapter(
|
||||
TYPE_SIGNATURE, signatureVisitor == null ? null : signatureVisitor.visitInterfaceBound());
|
||||
@ -213,7 +214,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
@Override
|
||||
public SignatureVisitor visitSuperclass() {
|
||||
if (type != CLASS_SIGNATURE || !VISIT_SUPER_CLASS_STATES.contains(state)) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = State.SUPER;
|
||||
return new CheckSignatureAdapter(
|
||||
@ -234,7 +235,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
@Override
|
||||
public SignatureVisitor visitParameterType() {
|
||||
if (type != METHOD_SIGNATURE || !VISIT_PARAMETER_TYPE_STATES.contains(state)) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = State.PARAM;
|
||||
return new CheckSignatureAdapter(
|
||||
@ -244,7 +245,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
@Override
|
||||
public SignatureVisitor visitReturnType() {
|
||||
if (type != METHOD_SIGNATURE || !VISIT_RETURN_TYPE_STATES.contains(state)) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
state = State.RETURN;
|
||||
CheckSignatureAdapter checkSignatureAdapter =
|
||||
@ -272,11 +273,11 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
}
|
||||
if (descriptor == 'V') {
|
||||
if (!canBeVoid) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Base type descriptor can't be V");
|
||||
}
|
||||
} else {
|
||||
if ("ZCBSIFJD".indexOf(descriptor) == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Base type descriptor must be one of ZCBSIFJD");
|
||||
}
|
||||
}
|
||||
state = State.SIMPLE_TYPE;
|
||||
@ -346,7 +347,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if ("+-=".indexOf(wildcard) == -1) {
|
||||
throw new IllegalArgumentException();
|
||||
throw new IllegalArgumentException("Wildcard must be one of +-=");
|
||||
}
|
||||
return new CheckSignatureAdapter(
|
||||
TYPE_SIGNATURE,
|
||||
@ -365,7 +366,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
}
|
||||
|
||||
private void checkClassName(final String name, final String message) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
|
||||
}
|
||||
for (int i = 0; i < name.length(); ++i) {
|
||||
@ -377,7 +378,7 @@ public class CheckSignatureAdapter extends SignatureVisitor {
|
||||
}
|
||||
|
||||
private void checkIdentifier(final String name, final String message) {
|
||||
if (name == null || name.isEmpty()) {
|
||||
if (name == null || name.length() == 0) {
|
||||
throw new IllegalArgumentException(INVALID + message + " (must not be null or empty)");
|
||||
}
|
||||
for (int i = 0; i < name.length(); ++i) {
|
||||
|
@ -72,6 +72,7 @@ import jdk.internal.org.objectweb.asm.Label;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.Type;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
import jdk.internal.org.objectweb.asm.TypeReference;
|
||||
|
||||
/**
|
||||
* An abstract converter from visit events to text.
|
||||
@ -326,13 +327,6 @@ public abstract class Printer {
|
||||
*/
|
||||
protected final int api;
|
||||
|
||||
/**
|
||||
* A buffer that can be used to create strings.
|
||||
*
|
||||
* @deprecated use {@link #stringBuilder} instead.
|
||||
*/
|
||||
@Deprecated protected final StringBuffer buf;
|
||||
|
||||
/** The builder used to build strings in the various visit methods. */
|
||||
protected final StringBuilder stringBuilder;
|
||||
|
||||
@ -360,9 +354,8 @@ public abstract class Printer {
|
||||
*/
|
||||
protected Printer(final int api) {
|
||||
this.api = api;
|
||||
this.buf = null;
|
||||
this.stringBuilder = new StringBuilder();
|
||||
this.text = new ArrayList<Object>();
|
||||
this.text = new ArrayList<>();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -491,6 +484,22 @@ public abstract class Printer {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
|
||||
* will break existing code using it</b>.
|
||||
*
|
||||
* <p>Visits a permitted subtypes. A permitted subtypes is one of the allowed subtypes of the
|
||||
* current class. See {@link
|
||||
* jdk.internal.org.objectweb.asm.ClassVisitor#visitPermittedSubtypeExperimental(String)}.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class inner name. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitInnerClass}.
|
||||
*
|
||||
@ -505,6 +514,22 @@ public abstract class Printer {
|
||||
*/
|
||||
public abstract void visitInnerClass(String name, String outerName, String innerName, int access);
|
||||
|
||||
/**
|
||||
* Visits a record component of the class. See {@link
|
||||
* jdk.internal.org.objectweb.asm.ClassVisitor#visitRecordComponent(String, String, String)}.
|
||||
*
|
||||
* @param name the field's name.
|
||||
* @param descriptor the record component descriptor (see {@link Type}).
|
||||
* @param signature the record component signature. May be {@literal null} if the record component
|
||||
* type does not use generic types.
|
||||
* @return a visitor to visit this record component annotations and attributes, or {@literal null}
|
||||
* if this class visitor is not interested in visiting these annotations and attributes.
|
||||
*/
|
||||
public Printer visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class field. See {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField}.
|
||||
*
|
||||
@ -676,6 +701,63 @@ public abstract class Printer {
|
||||
/** Annotation end. See {@link jdk.internal.org.objectweb.asm.AnnotationVisitor#visitEnd}. */
|
||||
public abstract void visitAnnotationEnd();
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Record components
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Visits an annotation of the record component. See {@link
|
||||
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitAnnotation}.
|
||||
*
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public Printer visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits an annotation on a type in the record component signature. See {@link
|
||||
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitTypeAnnotation}.
|
||||
*
|
||||
* @param typeRef a reference to the annotated type. The sort of this type reference must be
|
||||
* {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
|
||||
* TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
|
||||
* {@link TypeReference}.
|
||||
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
|
||||
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
|
||||
* 'typeRef' as a whole.
|
||||
* @param descriptor the class descriptor of the annotation class.
|
||||
* @param visible {@literal true} if the annotation is visible at runtime.
|
||||
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
|
||||
* interested in visiting this annotation.
|
||||
*/
|
||||
public Printer visitRecordComponentTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a non standard attribute of the record component. See {@link
|
||||
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitAttribute}.
|
||||
*
|
||||
* @param attribute an attribute.
|
||||
*/
|
||||
public void visitRecordComponentAttribute(final Attribute attribute) {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the end of the record component. See {@link
|
||||
* jdk.internal.org.objectweb.asm.RecordComponentVisitor#visitEnd}. This method, which is the last one to be
|
||||
* called, is used to inform the visitor that everything have been visited.
|
||||
*/
|
||||
public void visitRecordComponentEnd() {
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Fields
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -723,7 +805,7 @@ public abstract class Printer {
|
||||
/**
|
||||
* Method parameter. See {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitParameter(String, int)}.
|
||||
*
|
||||
* @param name parameter name or null if none is provided.
|
||||
* @param name parameter name or {@literal null} if none is provided.
|
||||
* @param access the parameter's access flags, only {@code ACC_FINAL}, {@code ACC_SYNTHETIC}
|
||||
* or/and {@code ACC_MANDATED} are allowed (see {@link Opcodes}).
|
||||
*/
|
||||
@ -913,12 +995,10 @@ public abstract class Printer {
|
||||
@Deprecated
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
boolean isInterface = opcode == Opcodes.INVOKEINTERFACE;
|
||||
visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
// This method was abstract before ASM5, and was therefore always overridden (without any
|
||||
// call to 'super'). Thus, at this point we necessarily have api >= ASM5, and we must then
|
||||
// redirect the method call to the ASM5 visitMethodInsn() method.
|
||||
visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -938,13 +1018,6 @@ public abstract class Printer {
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
|
||||
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM 5");
|
||||
}
|
||||
visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedOperationException(UNSUPPORTED_OPERATION);
|
||||
}
|
||||
|
||||
@ -1194,20 +1267,6 @@ public abstract class Printer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a quoted string to the given string buffer.
|
||||
*
|
||||
* @param stringBuffer the buffer where the string must be added.
|
||||
* @param string the string to be added.
|
||||
* @deprecated use {@link #appendString(StringBuilder, String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public static void appendString(final StringBuffer stringBuffer, final String string) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
appendString(stringBuilder, string);
|
||||
stringBuffer.append(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a quoted string to the given string builder.
|
||||
*
|
||||
@ -1244,24 +1303,30 @@ public abstract class Printer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a the given class to the standard output.
|
||||
* Prints a the given class to the given output.
|
||||
*
|
||||
* <p>Command line arguments: [-debug] <binary class name or class file name >
|
||||
*
|
||||
* @param args the command line arguments.
|
||||
* @param usage the help message to show when command line arguments are incorrect.
|
||||
* @param printer the printer to convert the class into text.
|
||||
* @param args the command line arguments.
|
||||
* @param output where to print the result.
|
||||
* @param logger where to log errors.
|
||||
* @throws IOException if the class cannot be found, or if an IOException occurs.
|
||||
*/
|
||||
static void main(final String usage, final Printer printer, final String[] args)
|
||||
static void main(
|
||||
final String[] args,
|
||||
final String usage,
|
||||
final Printer printer,
|
||||
final PrintWriter output,
|
||||
final PrintWriter logger)
|
||||
throws IOException {
|
||||
if (args.length < 1 || args.length > 2 || (args[0].equals("-debug") && args.length != 2)) {
|
||||
System.err.println(usage);
|
||||
logger.println(usage);
|
||||
return;
|
||||
}
|
||||
|
||||
TraceClassVisitor traceClassVisitor =
|
||||
new TraceClassVisitor(null, printer, new PrintWriter(System.out));
|
||||
TraceClassVisitor traceClassVisitor = new TraceClassVisitor(null, printer, output);
|
||||
|
||||
String className;
|
||||
int parsingOptions;
|
||||
|
@ -59,7 +59,11 @@
|
||||
package jdk.internal.org.objectweb.asm.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.Attribute;
|
||||
import jdk.internal.org.objectweb.asm.Handle;
|
||||
@ -77,6 +81,11 @@ import jdk.internal.org.objectweb.asm.signature.SignatureReader;
|
||||
*/
|
||||
public class Textifier extends Printer {
|
||||
|
||||
/** The help message shown when command line arguments are incorrect. */
|
||||
private static final String USAGE =
|
||||
"Prints a disassembled view of the given class.\n"
|
||||
+ "Usage: Textifier [-debug] <fully qualified class name or class file name>";
|
||||
|
||||
/** The type of internal names. See {@link #appendDescriptor}. */
|
||||
public static final int INTERNAL_NAME = 0;
|
||||
|
||||
@ -95,34 +104,17 @@ public class Textifier extends Printer {
|
||||
/** The type of class signatures. See {@link #appendDescriptor}. */
|
||||
public static final int CLASS_SIGNATURE = 5;
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated this constant has never been used.
|
||||
*/
|
||||
@Deprecated public static final int TYPE_DECLARATION = 6;
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated this constant has never been used.
|
||||
*/
|
||||
@Deprecated public static final int CLASS_DECLARATION = 7;
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated this constant has never been used.
|
||||
*/
|
||||
@Deprecated public static final int PARAMETERS_DECLARATION = 8;
|
||||
|
||||
/** The type of method handle descriptors. See {@link #appendDescriptor}. */
|
||||
public static final int HANDLE_DESCRIPTOR = 9;
|
||||
|
||||
private static final String CLASS_SUFFIX = ".class";
|
||||
private static final String DEPRECATED = "// DEPRECATED\n";
|
||||
private static final String RECORD = "// RECORD\n";
|
||||
private static final String INVISIBLE = " // invisible\n";
|
||||
|
||||
private static final List<String> FRAME_TYPES =
|
||||
Collections.unmodifiableList(Arrays.asList("T", "I", "F", "D", "J", "N", "U"));
|
||||
|
||||
/** The indentation of class members at depth level 1 (e.g. fields, methods). */
|
||||
protected String tab = " ";
|
||||
|
||||
@ -151,7 +143,7 @@ public class Textifier extends Printer {
|
||||
* @throws IllegalStateException If a subclass calls this constructor.
|
||||
*/
|
||||
public Textifier() {
|
||||
this(Opcodes.ASM7);
|
||||
this(/* latest api = */ Opcodes.ASM8);
|
||||
if (getClass() != Textifier.class) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
@ -161,7 +153,8 @@ public class Textifier extends Printer {
|
||||
* Constructs a new {@link Textifier}.
|
||||
*
|
||||
* @param api the ASM API version implemented by this visitor. Must be one of {@link
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
|
||||
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
|
||||
* Opcodes#ASM8}.
|
||||
*/
|
||||
protected Textifier(final int api) {
|
||||
super(api);
|
||||
@ -176,10 +169,22 @@ public class Textifier extends Printer {
|
||||
* @throws IOException if the class cannot be found, or if an IOException occurs.
|
||||
*/
|
||||
public static void main(final String[] args) throws IOException {
|
||||
String usage =
|
||||
"Prints a disassembled view of the given class.\n"
|
||||
+ "Usage: Textifier [-debug] <fully qualified class name or class file name>";
|
||||
main(usage, new Textifier(), args);
|
||||
main(args, new PrintWriter(System.out, true), new PrintWriter(System.err, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a disassembled view of the given class to the given output.
|
||||
*
|
||||
* <p>Usage: Textifier [-debug] <binary class name or class file name >
|
||||
*
|
||||
* @param args the command line arguments.
|
||||
* @param output where to print the result.
|
||||
* @param logger where to log errors.
|
||||
* @throws IOException if the class cannot be found, or if an IOException occurs.
|
||||
*/
|
||||
static void main(final String[] args, final PrintWriter output, final PrintWriter logger)
|
||||
throws IOException {
|
||||
main(args, USAGE, new Textifier(), output, logger);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -213,6 +218,9 @@ public class Textifier extends Printer {
|
||||
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
|
||||
stringBuilder.append(DEPRECATED);
|
||||
}
|
||||
if ((access & Opcodes.ACC_RECORD) != 0) {
|
||||
stringBuilder.append(RECORD);
|
||||
}
|
||||
appendRawAccess(access);
|
||||
|
||||
appendDescriptor(CLASS_SIGNATURE, signature);
|
||||
@ -329,6 +337,22 @@ public class Textifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("PERMITTEDSUBTYPE ");
|
||||
appendDescriptor(INTERNAL_NAME, permittedSubtype);
|
||||
stringBuilder.append('\n');
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(
|
||||
final String name, final String outerName, final String innerName, final int access) {
|
||||
@ -347,6 +371,28 @@ public class Textifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Printer visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("RECORDCOMPONENT ");
|
||||
if (signature != null) {
|
||||
stringBuilder.append(tab);
|
||||
appendDescriptor(FIELD_SIGNATURE, signature);
|
||||
stringBuilder.append(tab);
|
||||
appendJavaDeclaration(name, signature);
|
||||
}
|
||||
|
||||
stringBuilder.append(tab);
|
||||
|
||||
appendDescriptor(FIELD_DESCRIPTOR, descriptor);
|
||||
stringBuilder.append(' ').append(name);
|
||||
|
||||
stringBuilder.append('\n');
|
||||
text.add(stringBuilder.toString());
|
||||
return addNewTextifier(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Textifier visitField(
|
||||
final int access,
|
||||
@ -482,30 +528,20 @@ public class Textifier extends Printer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitExport(final String export, final int access, final String... modules) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("exports ");
|
||||
stringBuilder.append(export);
|
||||
if (modules != null && modules.length > 0) {
|
||||
stringBuilder.append(" to");
|
||||
} else {
|
||||
stringBuilder.append(';');
|
||||
}
|
||||
appendRawAccess(access);
|
||||
if (modules != null && modules.length > 0) {
|
||||
for (int i = 0; i < modules.length; ++i) {
|
||||
stringBuilder.append(tab2).append(modules[i]);
|
||||
stringBuilder.append(i != modules.length - 1 ? ",\n" : ";\n");
|
||||
}
|
||||
}
|
||||
text.add(stringBuilder.toString());
|
||||
public void visitExport(final String packaze, final int access, final String... modules) {
|
||||
visitExportOrOpen("exports ", packaze, access, modules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitOpen(final String export, final int access, final String... modules) {
|
||||
public void visitOpen(final String packaze, final int access, final String... modules) {
|
||||
visitExportOrOpen("opens ", packaze, access, modules);
|
||||
}
|
||||
|
||||
private void visitExportOrOpen(
|
||||
final String method, final String packaze, final int access, final String... modules) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("opens ");
|
||||
stringBuilder.append(export);
|
||||
stringBuilder.append(tab).append(method);
|
||||
stringBuilder.append(packaze);
|
||||
if (modules != null && modules.length > 0) {
|
||||
stringBuilder.append(" to");
|
||||
} else {
|
||||
@ -712,6 +748,31 @@ public class Textifier extends Printer {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Record components
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public Textifier visitRecordComponentAnnotation(final String descriptor, final boolean visible) {
|
||||
return visitAnnotation(descriptor, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Printer visitRecordComponentTypeAnnotation(
|
||||
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
|
||||
return visitTypeAnnotation(typeRef, typePath, descriptor, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordComponentAttribute(final Attribute attribute) {
|
||||
visitAttribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRecordComponentEnd() {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
// Fields
|
||||
// -----------------------------------------------------------------------------------------------
|
||||
@ -796,19 +857,7 @@ public class Textifier extends Printer {
|
||||
|
||||
@Override
|
||||
public void visitMethodAttribute(final Attribute attribute) {
|
||||
stringBuilder.setLength(0);
|
||||
stringBuilder.append(tab).append("ATTRIBUTE ");
|
||||
appendDescriptor(-1, attribute.type);
|
||||
|
||||
if (attribute instanceof Textifiable) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
((Textifiable) attribute).textify(stringBuffer, labelNames);
|
||||
stringBuilder.append(stringBuffer.toString());
|
||||
} else {
|
||||
stringBuilder.append(" : unknown\n");
|
||||
}
|
||||
|
||||
text.add(stringBuilder.toString());
|
||||
visitAttribute(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -904,37 +953,8 @@ public class Textifier extends Printer {
|
||||
text.add(stringBuilder.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
}
|
||||
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
||||
private void doVisitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
@ -1261,10 +1281,11 @@ public class Textifier extends Printer {
|
||||
stringBuilder.append(tab).append("ATTRIBUTE ");
|
||||
appendDescriptor(-1, attribute.type);
|
||||
|
||||
if (attribute instanceof Textifiable) {
|
||||
StringBuffer stringBuffer = new StringBuffer();
|
||||
((Textifiable) attribute).textify(stringBuffer, null);
|
||||
stringBuilder.append(stringBuffer.toString());
|
||||
if (attribute instanceof TextifierSupport) {
|
||||
if (labelNames == null) {
|
||||
labelNames = new HashMap<>();
|
||||
}
|
||||
((TextifierSupport) attribute).textify(stringBuilder, labelNames);
|
||||
} else {
|
||||
stringBuilder.append(" : unknown\n");
|
||||
}
|
||||
@ -1340,8 +1361,7 @@ public class Textifier extends Printer {
|
||||
*
|
||||
* @param type the type of 'value'. Must be one of {@link #INTERNAL_NAME}, {@link
|
||||
* #FIELD_DESCRIPTOR}, {@link #FIELD_SIGNATURE}, {@link #METHOD_DESCRIPTOR}, {@link
|
||||
* #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE}, {@link #TYPE_DECLARATION}, {@link
|
||||
* #CLASS_DECLARATION}, {@link #PARAMETERS_DECLARATION} of {@link #HANDLE_DESCRIPTOR}.
|
||||
* #METHOD_SIGNATURE}, {@link #CLASS_SIGNATURE} or {@link #HANDLE_DESCRIPTOR}.
|
||||
* @param value an internal name, type descriptor or a type signature. May be {@literal null}.
|
||||
*/
|
||||
protected void appendDescriptor(final int type, final String value) {
|
||||
@ -1384,7 +1404,7 @@ public class Textifier extends Printer {
|
||||
*/
|
||||
protected void appendLabel(final Label label) {
|
||||
if (labelNames == null) {
|
||||
labelNames = new HashMap<Label, String>();
|
||||
labelNames = new HashMap<>();
|
||||
}
|
||||
String name = labelNames.get(label);
|
||||
if (name == null) {
|
||||
@ -1587,31 +1607,7 @@ public class Textifier extends Printer {
|
||||
appendDescriptor(INTERNAL_NAME, descriptor);
|
||||
}
|
||||
} else if (frameTypes[i] instanceof Integer) {
|
||||
switch (((Integer) frameTypes[i]).intValue()) {
|
||||
case 0:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "T");
|
||||
break;
|
||||
case 1:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "I");
|
||||
break;
|
||||
case 2:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "F");
|
||||
break;
|
||||
case 3:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "D");
|
||||
break;
|
||||
case 4:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "J");
|
||||
break;
|
||||
case 5:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "N");
|
||||
break;
|
||||
case 6:
|
||||
appendDescriptor(FIELD_DESCRIPTOR, "U");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
stringBuilder.append(FRAME_TYPES.get(((Integer) frameTypes[i]).intValue()));
|
||||
} else {
|
||||
appendLabel((Label) frameTypes[i]);
|
||||
}
|
||||
@ -1639,6 +1635,6 @@ public class Textifier extends Printer {
|
||||
* @return a new {@link Textifier}.
|
||||
*/
|
||||
protected Textifier createTextifier() {
|
||||
return new Textifier();
|
||||
return new Textifier(api);
|
||||
}
|
||||
}
|
||||
|
78
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TextifierSupport.java
Normal file
78
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TextifierSupport.java
Normal 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);
|
||||
}
|
@ -88,7 +88,7 @@ public final class TraceAnnotationVisitor extends AnnotationVisitor {
|
||||
* @param printer the printer to convert the visited annotation into text.
|
||||
*/
|
||||
public TraceAnnotationVisitor(final AnnotationVisitor annotationVisitor, final Printer printer) {
|
||||
super(Opcodes.ASM7, annotationVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM8, annotationVisitor);
|
||||
this.printer = printer;
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,7 @@ import jdk.internal.org.objectweb.asm.FieldVisitor;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.ModuleVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.RecordComponentVisitor;
|
||||
import jdk.internal.org.objectweb.asm.TypePath;
|
||||
|
||||
/**
|
||||
@ -147,9 +148,10 @@ public final class TraceClassVisitor extends ClassVisitor {
|
||||
* @param printer the printer to convert the visited class into text.
|
||||
* @param printWriter the print writer to be used to print the class. May be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public TraceClassVisitor(
|
||||
final ClassVisitor classVisitor, final Printer printer, final PrintWriter printWriter) {
|
||||
super(Opcodes.ASM7, classVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM9_EXPERIMENTAL, classVisitor);
|
||||
this.printWriter = printWriter;
|
||||
this.p = printer;
|
||||
}
|
||||
@ -217,6 +219,19 @@ public final class TraceClassVisitor extends ClassVisitor {
|
||||
super.visitNestMember(nestMember);
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Experimental, use at your own risk.</b>.
|
||||
*
|
||||
* @param permittedSubtype the internal name of a permitted subtype.
|
||||
* @deprecated this API is experimental.
|
||||
*/
|
||||
@Override
|
||||
@Deprecated
|
||||
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
|
||||
p.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
super.visitPermittedSubtypeExperimental(permittedSubtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(
|
||||
final String name, final String outerName, final String innerName, final int access) {
|
||||
@ -224,6 +239,14 @@ public final class TraceClassVisitor extends ClassVisitor {
|
||||
super.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordComponentVisitor visitRecordComponent(
|
||||
final String name, final String descriptor, final String signature) {
|
||||
Printer recordComponentPrinter = p.visitRecordComponent(name, descriptor, signature);
|
||||
return new TraceRecordComponentVisitor(
|
||||
super.visitRecordComponent(name, descriptor, signature), recordComponentPrinter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(
|
||||
final int access,
|
||||
|
@ -91,7 +91,7 @@ public final class TraceFieldVisitor extends FieldVisitor {
|
||||
* @param printer the printer to convert the visited field into text.
|
||||
*/
|
||||
public TraceFieldVisitor(final FieldVisitor fieldVisitor, final Printer printer) {
|
||||
super(Opcodes.ASM7, fieldVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM8, fieldVisitor);
|
||||
this.p = printer;
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,7 @@ public final class TraceMethodVisitor extends MethodVisitor {
|
||||
* @param printer the printer to convert the visited method into text.
|
||||
*/
|
||||
public TraceMethodVisitor(final MethodVisitor methodVisitor, final Printer printer) {
|
||||
super(Opcodes.ASM7, methodVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM8, methodVisitor);
|
||||
this.p = printer;
|
||||
}
|
||||
|
||||
@ -192,37 +192,27 @@ public final class TraceMethodVisitor extends MethodVisitor {
|
||||
super.visitFieldInsn(opcode, owner, name, descriptor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated.
|
||||
*
|
||||
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public void visitMethodInsn(
|
||||
final int opcode, final String owner, final String name, final String descriptor) {
|
||||
if (api >= Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
return;
|
||||
}
|
||||
p.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
public void visitMethodInsn(
|
||||
final int opcode,
|
||||
final String owner,
|
||||
final String name,
|
||||
final String descriptor,
|
||||
final boolean isInterface) {
|
||||
if (api < Opcodes.ASM5) {
|
||||
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
return;
|
||||
// Call the method that p is supposed to implement, depending on its api version.
|
||||
if (p.api < Opcodes.ASM5) {
|
||||
if (isInterface != (opcode == Opcodes.INVOKEINTERFACE)) {
|
||||
throw new IllegalArgumentException("INVOKESPECIAL/STATIC on interfaces require ASM5");
|
||||
}
|
||||
// If p is an ASMifier (resp. Textifier), or a subclass that does not override the old
|
||||
// visitMethodInsn method, the default implementation in Printer will redirect this to the
|
||||
// new method in ASMifier (resp. Textifier). In all other cases, p overrides the old method
|
||||
// and this call executes it.
|
||||
p.visitMethodInsn(opcode, owner, name, descriptor);
|
||||
} else {
|
||||
p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
p.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
if (mv != null) {
|
||||
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public final class TraceModuleVisitor extends ModuleVisitor {
|
||||
* @param printer the printer to convert the visited module into text.
|
||||
*/
|
||||
public TraceModuleVisitor(final ModuleVisitor moduleVisitor, final Printer printer) {
|
||||
super(Opcodes.ASM7, moduleVisitor);
|
||||
super(/* latest api = */ Opcodes.ASM8, moduleVisitor);
|
||||
this.p = printer;
|
||||
}
|
||||
|
||||
|
127
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceRecordComponentVisitor.java
Normal file
127
src/java.base/share/classes/jdk/internal/org/objectweb/asm/util/TraceRecordComponentVisitor.java
Normal 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();
|
||||
}
|
||||
}
|
@ -58,6 +58,9 @@
|
||||
*/
|
||||
package jdk.internal.org.objectweb.asm.util;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
|
||||
|
||||
@ -74,6 +77,22 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
|
||||
private static final String EXTENDS_SEPARATOR = " extends ";
|
||||
private static final String IMPLEMENTS_SEPARATOR = " implements ";
|
||||
|
||||
private static final Map<Character, String> BASE_TYPES;
|
||||
|
||||
static {
|
||||
HashMap<Character, String> baseTypes = new HashMap<>();
|
||||
baseTypes.put('Z', "boolean");
|
||||
baseTypes.put('B', "byte");
|
||||
baseTypes.put('C', "char");
|
||||
baseTypes.put('S', "short");
|
||||
baseTypes.put('I', "int");
|
||||
baseTypes.put('J', "long");
|
||||
baseTypes.put('F', "float");
|
||||
baseTypes.put('D', "double");
|
||||
baseTypes.put('V', "void");
|
||||
BASE_TYPES = Collections.unmodifiableMap(baseTypes);
|
||||
}
|
||||
|
||||
/** Whether the visited signature is a class signature of a Java interface. */
|
||||
private final boolean isInterface;
|
||||
|
||||
@ -121,13 +140,13 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
|
||||
* @param accessFlags for class type signatures, the access flags of the class.
|
||||
*/
|
||||
public TraceSignatureVisitor(final int accessFlags) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.isInterface = (accessFlags & Opcodes.ACC_INTERFACE) != 0;
|
||||
this.declaration = new StringBuilder();
|
||||
}
|
||||
|
||||
private TraceSignatureVisitor(final StringBuilder stringBuilder) {
|
||||
super(Opcodes.ASM7);
|
||||
super(/* latest api = */ Opcodes.ASM8);
|
||||
this.isInterface = false;
|
||||
this.declaration = stringBuilder;
|
||||
}
|
||||
@ -212,37 +231,11 @@ public final class TraceSignatureVisitor extends SignatureVisitor {
|
||||
|
||||
@Override
|
||||
public void visitBaseType(final char descriptor) {
|
||||
switch (descriptor) {
|
||||
case 'V':
|
||||
declaration.append("void");
|
||||
break;
|
||||
case 'B':
|
||||
declaration.append("byte");
|
||||
break;
|
||||
case 'J':
|
||||
declaration.append("long");
|
||||
break;
|
||||
case 'Z':
|
||||
declaration.append("boolean");
|
||||
break;
|
||||
case 'I':
|
||||
declaration.append("int");
|
||||
break;
|
||||
case 'S':
|
||||
declaration.append("short");
|
||||
break;
|
||||
case 'C':
|
||||
declaration.append("char");
|
||||
break;
|
||||
case 'F':
|
||||
declaration.append("float");
|
||||
break;
|
||||
case 'D':
|
||||
declaration.append("double");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
String baseType = BASE_TYPES.get(descriptor);
|
||||
if (baseType == null) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
declaration.append(baseType);
|
||||
endType();
|
||||
}
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
ASM_7_0
|
||||
ASM_8_0_1
|
||||
origin http://gitlab.ow2.org/asm/asm.git (fetch)
|
||||
|
@ -1,4 +1,4 @@
|
||||
## ASM Bytecode Manipulation Framework v7.0
|
||||
## ASM Bytecode Manipulation Framework v8.0.1
|
||||
|
||||
### ASM License
|
||||
<pre>
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -217,7 +217,7 @@ public class BadCanonicalCtrTest {
|
||||
static class RemoveCanonicalCtrVisitor extends ClassVisitor {
|
||||
static final String CTR_NAME = "<init>";
|
||||
RemoveCanonicalCtrVisitor(ClassVisitor cv) {
|
||||
super(ASM7, cv);
|
||||
super(ASM8, cv);
|
||||
}
|
||||
volatile boolean foundCanonicalCtr;
|
||||
@Override
|
||||
@ -250,7 +250,7 @@ public class BadCanonicalCtrTest {
|
||||
/** Replaces whatever <init> method it finds with <init>(Ljava/lang/Object;)V. */
|
||||
static class ModifyCanonicalCtrVisitor extends ClassVisitor {
|
||||
ModifyCanonicalCtrVisitor(ClassVisitor cv) {
|
||||
super(ASM7, cv);
|
||||
super(ASM8, cv);
|
||||
}
|
||||
boolean foundCanonicalCtr;
|
||||
String className;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -246,7 +246,7 @@ public class ProhibitedMethods {
|
||||
static abstract class AbstractVisitor extends ClassVisitor {
|
||||
final String nameOfMethodToAdd;
|
||||
AbstractVisitor(ClassVisitor cv, String nameOfMethodToAdd) {
|
||||
super(ASM7, cv);
|
||||
super(ASM8, cv);
|
||||
this.nameOfMethodToAdd = nameOfMethodToAdd;
|
||||
}
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -237,7 +237,7 @@ public class SerialPersistentFieldsTest {
|
||||
final ObjectStreamField[] spf;
|
||||
String className;
|
||||
SerialPersistentFieldsVisitor(ClassVisitor cv, ObjectStreamField[] spf) {
|
||||
super(ASM7, cv);
|
||||
super(ASM8, cv);
|
||||
this.spf = spf;
|
||||
}
|
||||
@Override
|
||||
|
Loading…
x
Reference in New Issue
Block a user