8213480: update internal ASM version to 7.0

Reviewed-by: dholmes, iignatyev, alanb
This commit is contained in:
Vicente Romero 2018-11-13 23:33:17 -05:00
parent 147fc3ed13
commit 61082e6b25
155 changed files with 29496 additions and 27123 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2018, 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
@ -43,7 +43,7 @@ public class Main {
/**
* ASM version to be used by nasgen tool.
*/
public static final int ASM_VERSION = Opcodes.ASM5;
public static final int ASM_VERSION = Opcodes.ASM7;
private static final boolean DEBUG = Boolean.getBoolean("nasgen.debug");

View file

@ -1433,7 +1433,7 @@ public final class Module implements AnnotatedElement {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
@Override
public void visit(int version,
int access,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2018, 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
@ -35,7 +35,7 @@ import static sun.invoke.util.Wrapper.*;
class TypeConvertingMethodAdapter extends MethodVisitor {
TypeConvertingMethodAdapter(MethodVisitor mv) {
super(Opcodes.ASM5, mv);
super(Opcodes.ASM7, mv);
}
private static final int NUM_WRAPPERS = Wrapper.COUNT;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, 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
@ -153,7 +153,7 @@ public final class ModuleInfoExtender {
ClassReader cr = new ClassReader(in);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) {
ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
@Override
public ModuleVisitor visitModule(String name, int flags, String version) {
Version v = ModuleInfoExtender.this.version;
@ -170,7 +170,7 @@ public final class ModuleInfoExtender {
packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/')));
}
return new ModuleVisitor(Opcodes.ASM6, mv) {
return new ModuleVisitor(Opcodes.ASM7, mv) {
public void visitMainClass(String existingMainClass) {
// skip main class if there is a new value
if (mainClass == null) {

View file

@ -59,9 +59,9 @@
package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a Java annotation. The methods of this class must be
* called in the following order: ( <tt>visit</tt> | <tt>visitEnum</tt> |
* <tt>visitAnnotation</tt> | <tt>visitArray</tt> )* <tt>visitEnd</tt>.
* A visitor to visit a Java annotation. The methods of this class must be called in the following
* order: ( {@code visit} | {@code visitEnum} | {@code visitAnnotation} | {@code visitArray} )*
* {@code visitEnd}.
*
* @author Eric Bruneton
* @author Eugene Kuleshov
@ -69,23 +69,19 @@ package jdk.internal.org.objectweb.asm;
public abstract class AnnotationVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
protected final int api;
/**
* The annotation visitor to which this visitor must delegate method calls.
* May be null.
*/
/** The annotation visitor to which this visitor must delegate method calls. May be null. */
protected AnnotationVisitor av;
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public AnnotationVisitor(final int api) {
this(api, null);
@ -94,37 +90,31 @@ public abstract class AnnotationVisitor {
/**
* Constructs a new {@link AnnotationVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param av
* the annotation visitor to which this visitor must delegate
* method calls. May be null.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* @param annotationVisitor the annotation visitor to which this visitor must delegate method
* calls. May be null.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor av) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
}
this.api = api;
this.av = av;
this.av = annotationVisitor;
}
/**
* Visits a primitive value of the annotation.
*
* @param name
* the value name.
* @param value
* the actual value, whose type must be {@link Byte},
* {@link Boolean}, {@link Character}, {@link Short},
* {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} of OBJECT or ARRAY sort. This
* value can also be an array of byte, boolean, short, char, int,
* long, float or double values (this is equivalent to using
* {@link #visitArray visitArray} and visiting each array element
* in turn, but is more convenient).
* @param name the value name.
* @param value the actual value, whose type must be {@link Byte}, {@link Boolean}, {@link
* Character}, {@link Short}, {@link Integer} , {@link Long}, {@link Float}, {@link Double},
* {@link String} or {@link Type} of {@link Type#OBJECT} or {@link Type#ARRAY} sort. This
* value can also be an array of byte, boolean, short, char, int, long, float or double values
* (this is equivalent to using {@link #visitArray} and visiting each array element in turn,
* but is more convenient).
*/
public void visit(String name, Object value) {
public void visit(final String name, final Object value) {
if (av != null) {
av.visit(name, value);
}
@ -133,63 +123,51 @@ public abstract class AnnotationVisitor {
/**
* Visits an enumeration value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the enumeration class.
* @param value
* the actual enumeration value.
* @param name the value name.
* @param descriptor the class descriptor of the enumeration class.
* @param value the actual enumeration value.
*/
public void visitEnum(String name, String desc, String value) {
public void visitEnum(final String name, final String descriptor, final String value) {
if (av != null) {
av.visitEnum(name, desc, value);
av.visitEnum(name, descriptor, value);
}
}
/**
* Visits a nested annotation value of the annotation.
*
* @param name
* the value name.
* @param desc
* the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or
* <tt>null</tt> if this visitor is not interested in visiting this
* nested annotation. <i>The nested annotation value must be fully
* visited before calling other methods on this annotation
* visitor</i>.
* @param name the value name.
* @param descriptor the class descriptor of the nested annotation class.
* @return a visitor to visit the actual nested annotation value, or {@literal null} if this
* visitor is not interested in visiting this nested annotation. <i>The nested annotation
* value must be fully visited before calling other methods on this annotation visitor</i>.
*/
public AnnotationVisitor visitAnnotation(String name, String desc) {
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
if (av != null) {
return av.visitAnnotation(name, desc);
return av.visitAnnotation(name, descriptor);
}
return null;
}
/**
* Visits an array value of the annotation. Note that arrays of primitive
* types (such as byte, boolean, short, char, int, long, float or double)
* can be passed as value to {@link #visit visit}. This is what
* {@link ClassReader} does.
* Visits an array value of the annotation. Note that arrays of primitive types (such as byte,
* boolean, short, char, int, long, float or double) can be passed as value to {@link #visit
* visit}. This is what {@link ClassReader} does.
*
* @param name
* the value name.
* @return a visitor to visit the actual array value elements, or
* <tt>null</tt> if this visitor is not interested in visiting these
* values. The 'name' parameters passed to the methods of this
* visitor are ignored. <i>All the array values must be visited
* before calling other methods on this annotation visitor</i>.
* @param name the value name.
* @return a visitor to visit the actual array value elements, or {@literal null} if this visitor
* is not interested in visiting these values. The 'name' parameters passed to the methods of
* this visitor are ignored. <i>All the array values must be visited before calling other
* methods on this annotation visitor</i>.
*/
public AnnotationVisitor visitArray(String name) {
public AnnotationVisitor visitArray(final String name) {
if (av != null) {
return av.visitArray(name);
}
return null;
}
/**
* Visits the end of the annotation.
*/
/** Visits the end of the annotation. */
public void visitEnd() {
if (av != null) {
av.visitEnd();

View file

@ -59,342 +59,391 @@
package jdk.internal.org.objectweb.asm;
/**
* An {@link AnnotationVisitor} that generates annotations in bytecode form.
* An {@link AnnotationVisitor} that generates a corresponding 'annotation' or 'type_annotation'
* structure, as defined in the Java Virtual Machine Specification (JVMS). AnnotationWriter
* instances can be chained in a doubly linked list, from which Runtime[In]Visible[Type]Annotations
* attributes can be generated with the {@link #putAnnotations} method. Similarly, arrays of such
* lists can be used to generate Runtime[In]VisibleParameterAnnotations attributes.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16">JVMS
* 4.7.16</a>
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
* 4.7.20</a>
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
final class AnnotationWriter extends AnnotationVisitor {
/**
* The class writer to which this annotation must be added.
*/
private final ClassWriter cw;
/** Where the constants used in this AnnotationWriter must be stored. */
private final SymbolTable symbolTable;
/**
* The number of values in this annotation.
* Whether values are named or not. AnnotationWriter instances used for annotation default and
* annotation arrays use unnamed values (i.e. they generate an 'element_value' structure for each
* value, instead of an element_name_index followed by an element_value).
*/
private int size;
private final boolean useNamedValues;
/**
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
* writers used for annotation default and annotation arrays use unnamed
* values.
* The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
* visited so far. All the fields of these structures, except the last one - the
* element_value_pairs array, must be set before this ByteVector is passed to the constructor
* (num_element_value_pairs can be set to 0, it is reset to the correct value in {@link
* #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
* methods.
*
* <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
* single element_value by definition), this ByteVector is initially empty when passed to the
* constructor, and {@link #numElementValuePairsOffset} is set to -1.
*/
private final boolean named;
private final ByteVector annotation;
/**
* The annotation values in bytecode form. This byte vector only contains
* the values themselves, i.e. the number of values must be stored as a
* unsigned short just before these bytes.
* The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
* the case of AnnotationDefault attributes).
*/
private final ByteVector bv;
private final int numElementValuePairsOffset;
/** The number of element value pairs visited so far. */
private int numElementValuePairs;
/**
* The byte vector to be used to store the number of values of this
* annotation. See {@link #bv}.
* The previous AnnotationWriter. This field is used to store the list of annotations of a
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
* (annotation values of annotation type), or for AnnotationDefault attributes.
*/
private final ByteVector parent;
private final AnnotationWriter previousAnnotation;
/**
* Where the number of values of this annotation must be stored in
* {@link #parent}.
* The next AnnotationWriter. This field is used to store the list of annotations of a
* Runtime[In]Visible[Type]Annotations attribute. It is unused for nested or array annotations
* (annotation values of annotation type), or for AnnotationDefault attributes.
*/
private final int offset;
private AnnotationWriter nextAnnotation;
/**
* Next annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter next;
/**
* Previous annotation writer. This field is used to store annotation lists.
*/
AnnotationWriter prev;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------------------------
/**
* Constructs a new {@link AnnotationWriter}.
*
* @param cw
* the class writer to which this annotation must be added.
* @param named
* <tt>true<tt> if values are named, <tt>false</tt> otherwise.
* @param bv
* where the annotation values must be stored.
* @param parent
* where the number of annotation values must be stored.
* @param offset
* where in <tt>parent</tt> the number of annotation values must
* be stored.
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
* @param useNamedValues whether values are named or not. AnnotationDefault and annotation arrays
* use unnamed values.
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
* the visited content must be stored. This ByteVector must already contain all the fields of
* the structure except the last one (the element_value_pairs array).
* @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
* other cases (e.g. nested or array annotations).
*/
AnnotationWriter(final ClassWriter cw, final boolean named,
final ByteVector bv, final ByteVector parent, final int offset) {
super(Opcodes.ASM6);
this.cw = cw;
this.named = named;
this.bv = bv;
this.parent = parent;
this.offset = offset;
AnnotationWriter(
final SymbolTable symbolTable,
final boolean useNamedValues,
final ByteVector annotation,
final AnnotationWriter previousAnnotation) {
super(Opcodes.ASM7);
this.symbolTable = symbolTable;
this.useNamedValues = useNamedValues;
this.annotation = annotation;
// By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
this.previousAnnotation = previousAnnotation;
if (previousAnnotation != null) {
previousAnnotation.nextAnnotation = this;
}
}
// ------------------------------------------------------------------------
/**
* Constructs a new {@link AnnotationWriter} using named values.
*
* @param symbolTable where the constants used in this AnnotationWriter must be stored.
* @param annotation where the 'annotation' or 'type_annotation' JVMS structure corresponding to
* the visited content must be stored. This ByteVector must already contain all the fields of
* the structure except the last one (the element_value_pairs array).
* @param previousAnnotation the previously visited annotation of the
* Runtime[In]Visible[Type]Annotations attribute to which this annotation belongs, or null in
* other cases (e.g. nested or array annotations).
*/
AnnotationWriter(
final SymbolTable symbolTable,
final ByteVector annotation,
final AnnotationWriter previousAnnotation) {
this(symbolTable, /* useNamedValues = */ true, annotation, previousAnnotation);
}
// -----------------------------------------------------------------------------------------------
// Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
@Override
public void visit(final String name, final Object value) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
// Case of an element_value with a const_value_index, class_info_index or array_index field.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
}
if (value instanceof String) {
bv.put12('s', cw.newUTF8((String) value));
annotation.put12('s', symbolTable.addConstantUtf8((String) value));
} else if (value instanceof Byte) {
bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
annotation.put12('B', symbolTable.addConstantInteger(((Byte) value).byteValue()).index);
} else if (value instanceof Boolean) {
int v = ((Boolean) value).booleanValue() ? 1 : 0;
bv.put12('Z', cw.newInteger(v).index);
int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
} else if (value instanceof Character) {
bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
annotation.put12('C', symbolTable.addConstantInteger(((Character) value).charValue()).index);
} else if (value instanceof Short) {
bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
annotation.put12('S', symbolTable.addConstantInteger(((Short) value).shortValue()).index);
} else if (value instanceof Type) {
bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
annotation.put12('c', symbolTable.addConstantUtf8(((Type) value).getDescriptor()));
} else if (value instanceof byte[]) {
byte[] v = (byte[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('B', cw.newInteger(v[i]).index);
byte[] byteArray = (byte[]) value;
annotation.put12('[', byteArray.length);
for (byte byteValue : byteArray) {
annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
}
} else if (value instanceof boolean[]) {
boolean[] v = (boolean[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
boolean[] booleanArray = (boolean[]) value;
annotation.put12('[', booleanArray.length);
for (boolean booleanValue : booleanArray) {
annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
}
} else if (value instanceof short[]) {
short[] v = (short[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('S', cw.newInteger(v[i]).index);
short[] shortArray = (short[]) value;
annotation.put12('[', shortArray.length);
for (short shortValue : shortArray) {
annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
}
} else if (value instanceof char[]) {
char[] v = (char[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('C', cw.newInteger(v[i]).index);
char[] charArray = (char[]) value;
annotation.put12('[', charArray.length);
for (char charValue : charArray) {
annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
}
} else if (value instanceof int[]) {
int[] v = (int[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('I', cw.newInteger(v[i]).index);
int[] intArray = (int[]) value;
annotation.put12('[', intArray.length);
for (int intValue : intArray) {
annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
}
} else if (value instanceof long[]) {
long[] v = (long[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('J', cw.newLong(v[i]).index);
long[] longArray = (long[]) value;
annotation.put12('[', longArray.length);
for (long longValue : longArray) {
annotation.put12('J', symbolTable.addConstantLong(longValue).index);
}
} else if (value instanceof float[]) {
float[] v = (float[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('F', cw.newFloat(v[i]).index);
float[] floatArray = (float[]) value;
annotation.put12('[', floatArray.length);
for (float floatValue : floatArray) {
annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
}
} else if (value instanceof double[]) {
double[] v = (double[]) value;
bv.put12('[', v.length);
for (int i = 0; i < v.length; i++) {
bv.put12('D', cw.newDouble(v[i]).index);
double[] doubleArray = (double[]) value;
annotation.put12('[', doubleArray.length);
for (double doubleValue : doubleArray) {
annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
}
} else {
Item i = cw.newConstItem(value);
bv.put12(".s.IFJDCS".charAt(i.type), i.index);
Symbol symbol = symbolTable.addConstant(value);
annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
}
}
@Override
public void visitEnum(final String name, final String desc,
final String value) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
public void visitEnum(final String name, final String descriptor, final String value) {
// Case of an element_value with an enum_const_value field.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
}
bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
annotation
.put12('e', symbolTable.addConstantUtf8(descriptor))
.putShort(symbolTable.addConstantUtf8(value));
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
// Case of an element_value with an annotation_value field.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
}
// write tag and type, and reserve space for values count
bv.put12('@', cw.newUTF8(desc)).putShort(0);
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
// Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
return new AnnotationWriter(symbolTable, annotation, null);
}
@Override
public AnnotationVisitor visitArray(final String name) {
++size;
if (named) {
bv.putShort(cw.newUTF8(name));
// Case of an element_value with an array_value field.
// https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
}
// write tag, and reserve space for array size
bv.put12('[', 0);
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
// Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
// end of an element_value of array type is similar to the end of an 'annotation' structure: an
// unsigned short num_values followed by num_values element_value, versus an unsigned short
// num_element_value_pairs, followed by num_element_value_pairs { element_name_index,
// element_value } tuples. This allows us to use an AnnotationWriter with unnamed values to
// visit the array elements. Its num_element_value_pairs will correspond to the number of array
// elements and will be stored in what is in fact num_values.
annotation.put12('[', 0);
return new AnnotationWriter(symbolTable, /* useNamedValues = */ false, annotation, null);
}
@Override
public void visitEnd() {
if (parent != null) {
byte[] data = parent.data;
data[offset] = (byte) (size >>> 8);
data[offset + 1] = (byte) size;
if (numElementValuePairsOffset != -1) {
byte[] data = annotation.data;
data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
}
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Returns the size of this annotation writer list.
* Returns the size of a Runtime[In]Visible[Type]Annotations attribute containing this annotation
* and all its <i>predecessors</i> (see {@link #previousAnnotation}. Also adds the attribute name
* to the constant pool of the class (if not null).
*
* @return the size of this annotation writer list.
* @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
* @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
* annotation and all its predecessors. This includes the size of the attribute_name_index and
* attribute_length fields.
*/
int getSize() {
int size = 0;
AnnotationWriter aw = this;
while (aw != null) {
size += aw.bv.length;
aw = aw.next;
int computeAnnotationsSize(final String attributeName) {
if (attributeName != null) {
symbolTable.addConstantUtf8(attributeName);
}
return size;
// The attribute_name_index, attribute_length and num_annotations fields use 8 bytes.
int attributeSize = 8;
AnnotationWriter annotationWriter = this;
while (annotationWriter != null) {
attributeSize += annotationWriter.annotation.length;
annotationWriter = annotationWriter.previousAnnotation;
}
return attributeSize;
}
/**
* Puts the annotations of this annotation writer list into the given byte
* vector.
* Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
* <i>predecessors</i> (see {@link #previousAnnotation} in the given ByteVector. Annotations are
* put in the same order they have been visited.
*
* @param out
* where the annotations must be put.
* @param attributeNameIndex the constant pool index of the attribute name (one of
* "Runtime[In]Visible[Type]Annotations").
* @param output where the attribute must be put.
*/
void put(final ByteVector out) {
int n = 0;
int size = 2;
AnnotationWriter aw = this;
AnnotationWriter last = null;
while (aw != null) {
++n;
size += aw.bv.length;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
void putAnnotations(final int attributeNameIndex, final ByteVector output) {
int attributeLength = 2; // For num_annotations.
int numAnnotations = 0;
AnnotationWriter annotationWriter = this;
AnnotationWriter firstAnnotation = null;
while (annotationWriter != null) {
// In case the user forgot to call visitEnd().
annotationWriter.visitEnd();
attributeLength += annotationWriter.annotation.length;
numAnnotations++;
firstAnnotation = annotationWriter;
annotationWriter = annotationWriter.previousAnnotation;
}
out.putInt(size);
out.putShort(n);
aw = last;
while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
output.putShort(attributeNameIndex);
output.putInt(attributeLength);
output.putShort(numAnnotations);
annotationWriter = firstAnnotation;
while (annotationWriter != null) {
output.putByteArray(annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
annotationWriter = annotationWriter.nextAnnotation;
}
}
/**
* Puts the given annotation lists into the given byte vector.
* Returns the size of a Runtime[In]VisibleParameterAnnotations attribute containing all the
* annotation lists from the given AnnotationWriter sub-array. Also adds the attribute name to the
* constant pool of the class.
*
* @param panns
* an array of annotation writer lists.
* @param off
* index of the first annotation to be written.
* @param out
* where the annotations must be put.
* @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
* element).
* @param annotableParameterCount the number of elements in annotationWriters to take into account
* (elements [0..annotableParameterCount[ are taken into account).
* @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
* to the given sub-array of AnnotationWriter lists. This includes the size of the
* attribute_name_index and attribute_length fields.
*/
static void put(final AnnotationWriter[] panns, final int off,
final ByteVector out) {
int size = 1 + 2 * (panns.length - off);
for (int i = off; i < panns.length; ++i) {
size += panns[i] == null ? 0 : panns[i].getSize();
}
out.putInt(size).putByte(panns.length - off);
for (int i = off; i < panns.length; ++i) {
AnnotationWriter aw = panns[i];
AnnotationWriter last = null;
int n = 0;
while (aw != null) {
++n;
aw.visitEnd(); // in case user forgot to call visitEnd
aw.prev = last;
last = aw;
aw = aw.next;
}
out.putShort(n);
aw = last;
while (aw != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length);
aw = aw.prev;
}
static int computeParameterAnnotationsSize(
final String attributeName,
final AnnotationWriter[] annotationWriters,
final int annotableParameterCount) {
// Note: attributeName is added to the constant pool by the call to computeAnnotationsSize
// below. This assumes that there is at least one non-null element in the annotationWriters
// sub-array (which is ensured by the lazy instantiation of this array in MethodWriter).
// The attribute_name_index, attribute_length and num_parameters fields use 7 bytes, and each
// element of the parameter_annotations array uses 2 bytes for its num_annotations field.
int attributeSize = 7 + 2 * annotableParameterCount;
for (int i = 0; i < annotableParameterCount; ++i) {
AnnotationWriter annotationWriter = annotationWriters[i];
attributeSize +=
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(attributeName) - 8;
}
return attributeSize;
}
/**
* Puts the given type reference and type path into the given bytevector.
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
* Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
* from the given AnnotationWriter sub-array in the given ByteVector.
*
* @param typeRef
* a reference to the annotated type. 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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param out
* where the type reference and type path must be put.
* @param attributeNameIndex constant pool index of the attribute name (one of
* Runtime[In]VisibleParameterAnnotations).
* @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
* element).
* @param annotableParameterCount the number of elements in annotationWriters to put (elements
* [0..annotableParameterCount[ are put).
* @param output where the attribute must be put.
*/
static void putTarget(int typeRef, TypePath typePath, ByteVector out) {
switch (typeRef >>> 24) {
case 0x00: // CLASS_TYPE_PARAMETER
case 0x01: // METHOD_TYPE_PARAMETER
case 0x16: // METHOD_FORMAL_PARAMETER
out.putShort(typeRef >>> 16);
break;
case 0x13: // FIELD
case 0x14: // METHOD_RETURN
case 0x15: // METHOD_RECEIVER
out.putByte(typeRef >>> 24);
break;
case 0x47: // CAST
case 0x48: // CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
case 0x49: // METHOD_INVOCATION_TYPE_ARGUMENT
case 0x4A: // CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
case 0x4B: // METHOD_REFERENCE_TYPE_ARGUMENT
out.putInt(typeRef);
break;
// case 0x10: // CLASS_EXTENDS
// case 0x11: // CLASS_TYPE_PARAMETER_BOUND
// case 0x12: // METHOD_TYPE_PARAMETER_BOUND
// case 0x17: // THROWS
// case 0x42: // EXCEPTION_PARAMETER
// case 0x43: // INSTANCEOF
// case 0x44: // NEW
// case 0x45: // CONSTRUCTOR_REFERENCE
// case 0x46: // METHOD_REFERENCE
default:
out.put12(typeRef >>> 24, (typeRef & 0xFFFF00) >> 8);
break;
static void putParameterAnnotations(
final int attributeNameIndex,
final AnnotationWriter[] annotationWriters,
final int annotableParameterCount,
final ByteVector output) {
// The num_parameters field uses 1 byte, and each element of the parameter_annotations array
// uses 2 bytes for its num_annotations field.
int attributeLength = 1 + 2 * annotableParameterCount;
for (int i = 0; i < annotableParameterCount; ++i) {
AnnotationWriter annotationWriter = annotationWriters[i];
attributeLength +=
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
}
output.putShort(attributeNameIndex);
output.putInt(attributeLength);
output.putByte(annotableParameterCount);
for (int i = 0; i < annotableParameterCount; ++i) {
AnnotationWriter annotationWriter = annotationWriters[i];
AnnotationWriter firstAnnotation = null;
int numAnnotations = 0;
while (annotationWriter != null) {
// In case user the forgot to call visitEnd().
annotationWriter.visitEnd();
numAnnotations++;
firstAnnotation = annotationWriter;
annotationWriter = annotationWriter.previousAnnotation;
}
output.putShort(numAnnotations);
annotationWriter = firstAnnotation;
while (annotationWriter != null) {
output.putByteArray(
annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
annotationWriter = annotationWriter.nextAnnotation;
}
if (typePath == null) {
out.putByte(0);
} else {
int length = typePath.b[typePath.offset] * 2 + 1;
out.putByteArray(typePath.b, typePath.offset, length);
}
}
}

View file

@ -58,55 +58,62 @@
*/
package jdk.internal.org.objectweb.asm;
import java.util.Arrays;
/**
* A non standard class, field, method or code attribute.
* A non standard class, field, method or code attribute, as defined in the Java Virtual Machine
* Specification (JVMS).
*
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7">JVMS
* 4.7</a>
* @see <a href= "https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
* 4.7.3</a>
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
public class Attribute {
/**
* The type of this attribute.
*/
/** The type of this attribute, also called its name in the JVMS. */
public final String type;
/**
* The raw value of this attribute, used only for unknown attributes.
* The raw content of this attribute, only used for unknown attributes (see {@link #isUnknown()}).
* The 6 header bytes of the attribute (attribute_name_index and attribute_length) are <i>not</i>
* included.
*/
byte[] value;
private byte[] content;
/**
* The next attribute in this attribute list. May be <tt>null</tt>.
* The next attribute in this attribute list (Attribute instances can be linked via this field to
* store a list of class, field, method or code attributes). May be {@literal null}.
*/
Attribute next;
Attribute nextAttribute;
/**
* Constructs a new empty attribute.
*
* @param type
* the type of the attribute.
* @param type the type of the attribute.
*/
protected Attribute(final String type) {
this.type = type;
}
/**
* Returns <tt>true</tt> if this type of attribute is unknown. The default
* implementation of this method always returns <tt>true</tt>.
* Returns {@literal true} if this type of attribute is unknown. This means that the attribute
* content can't be parsed to extract constant pool references, labels, etc. Instead, the
* attribute content is read as an opaque byte array, and written back as is. This can lead to
* invalid attributes, if the content actually contains constant pool references, labels, or other
* symbolic references that need to be updated when there are changes to the constant pool, the
* method bytecode, etc. The default implementation of this method always returns {@literal true}.
*
* @return <tt>true</tt> if this type of attribute is unknown.
* @return {@literal true} if this type of attribute is unknown.
*/
public boolean isUnknown() {
return true;
}
/**
* Returns <tt>true</tt> if this type of attribute is a code attribute.
* Returns {@literal true} if this type of attribute is a code attribute.
*
* @return <tt>true</tt> 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;
@ -115,240 +122,235 @@ public class Attribute {
/**
* Returns the labels corresponding to this attribute.
*
* @return the labels corresponding to this attribute, or <tt>null</tt> if
* this attribute is not a code attribute that contains labels.
* @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
* a code attribute that contains labels.
*/
protected Label[] getLabels() {
return null;
return new Label[0];
}
/**
* Reads a {@link #type type} attribute. This method must return a
* <i>new</i> {@link Attribute} object, of type {@link #type type},
* corresponding to the <tt>len</tt> bytes starting at the given offset, in
* the given class reader.
* Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
* of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
* ClassReader.
*
* @param cr
* the class that contains the attribute to be read.
* @param off
* index of the first byte of the attribute's content in
* {@link ClassReader#b cr.b}. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param len
* the length of the attribute's content.
* @param buf
* buffer to be used to call {@link ClassReader#readUTF8
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass}
* or {@link ClassReader#readConst readConst}.
* @param codeOff
* index of the first byte of code's attribute content in
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read
* is not a code attribute. The 6 attribute header bytes,
* containing the type and the length of the attribute, are not
* taken into account here.
* @param labels
* the labels of the method's code, or <tt>null</tt> if the
* attribute to be read is not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the given
* bytes.
*/
protected Attribute read(final ClassReader cr, final int off,
final int len, final char[] buf, final int codeOff,
final Label[] labels) {
Attribute attr = new Attribute(type);
attr.value = new byte[len];
System.arraycopy(cr.b, off, attr.value, 0, len);
return attr;
}
/**
* Returns the byte array form of this attribute.
*
* @param cw
* the class to which this attribute must be added. This
* parameter can be used to add to the constant pool of this
* class the items that corresponds to this attribute.
* @param code
* the bytecode of the method corresponding to this code
* attribute, or <tt>null</tt> if this attribute is not a code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to this
* code attribute, or <tt>null</tt> 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
* @param classReader the class that contains the attribute to be read.
* @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
* 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here.
* @param length the length of the attribute's content (excluding the 6 attribute header bytes).
* @param charBuffer the buffer to be used to call the ClassReader methods requiring a
* 'charBuffer' parameter.
* @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
* in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
* attribute header bytes (attribute_name_index and attribute_length) are not taken into
* account here.
* @param labels the labels of the method's code, or {@literal null} if the attribute to be read
* is not a code attribute.
* @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
*/
protected Attribute read(
final ClassReader classReader,
final int offset,
final int length,
final char[] charBuffer,
final int codeAttributeOffset,
final Label[] labels) {
Attribute attribute = new Attribute(type);
attribute.content = new byte[length];
System.arraycopy(classReader.b, offset, attribute.content, 0, length);
return attribute;
}
/**
* Returns the byte array form of the content of this attribute. The 6 header bytes
* (attribute_name_index and attribute_length) must <i>not</i> be added in the returned
* ByteVector.
*
* @param classWriter the class to which this attribute must be added. This parameter can be used
* to add the items that corresponds to this attribute to the constant pool of this class.
* @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
* if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
* attribute.
* @param codeLength the length of the bytecode of the method corresponding to this code
* attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
* field of the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to this code attribute, or
* -1 if this attribute is not a code attribute.
* @param maxLocals the maximum number of local variables of the method corresponding to this code
* attribute, or -1 if this attribute is not a code attribute.
* @return the byte array form of this attribute.
*/
protected ByteVector write(final ClassWriter cw, final byte[] code,
final int len, final int maxStack, final int maxLocals) {
ByteVector v = new ByteVector();
v.data = value;
v.length = value.length;
return v;
protected ByteVector write(
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
return new ByteVector(content);
}
/**
* Returns the length of the attribute list that begins with this attribute.
* Returns the number of attributes of the attribute list that begins with this attribute.
*
* @return the length of the attribute list that begins with this attribute.
* @return the number of attributes of the attribute list that begins with this attribute.
*/
final int getCount() {
final int getAttributeCount() {
int count = 0;
Attribute attr = this;
while (attr != null) {
Attribute attribute = this;
while (attribute != null) {
count += 1;
attr = attr.next;
attribute = attribute.nextAttribute;
}
return count;
}
/**
* Returns the size of all the attributes in this attribute list.
* Returns the total size in bytes of all the attributes in the attribute list that begins with
* this attribute. This size includes the 6 header bytes (attribute_name_index and
* attribute_length) per attribute. Also adds the attribute type names to the constant pool.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @return the size of all the attributes in this attribute list. This size
* includes the size of the attribute headers.
* @param symbolTable where the constants used in the attributes must be stored.
* @return the size of all the attributes in this attribute list. This size includes the size of
* the attribute headers.
*/
final int getSize(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals) {
Attribute attr = this;
final int computeAttributesSize(final SymbolTable symbolTable) {
final byte[] code = null;
final int codeLength = 0;
final int maxStack = -1;
final int maxLocals = -1;
return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
}
/**
* Returns the total size in bytes of all the attributes in the attribute list that begins with
* this attribute. This size includes the 6 header bytes (attribute_name_index and
* attribute_length) per attribute. Also adds the attribute type names to the constant pool.
*
* @param symbolTable where the constants used in the attributes must be stored.
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
* attribute.
* @param codeLength the length of the bytecode of the method corresponding to these code
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
* the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
* -1 if they are not code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these
* code attributes, or -1 if they are not code attribute.
* @return the size of all the attributes in this attribute list. This size includes the size of
* the attribute headers.
*/
final int computeAttributesSize(
final SymbolTable symbolTable,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
final ClassWriter classWriter = symbolTable.classWriter;
int size = 0;
while (attr != null) {
cw.newUTF8(attr.type);
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6;
attr = attr.next;
Attribute attribute = this;
while (attribute != null) {
symbolTable.addConstantUtf8(attribute.type);
size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
attribute = attribute.nextAttribute;
}
return size;
}
/**
* Writes all the attributes of this attribute list in the given byte
* vector.
* Puts all the attributes of the attribute list that begins with this attribute, in the given
* byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
* attribute.
*
* @param cw
* the class writer to be used to convert the attributes into
* byte arrays, with the {@link #write write} method.
* @param code
* the bytecode of the method corresponding to these code
* attributes, or <tt>null</tt> if these attributes are not code
* attributes.
* @param len
* the length of the bytecode of the method corresponding to
* these code attributes, or <tt>null</tt> if these attributes
* are not code attributes.
* @param maxStack
* the maximum stack size of the method corresponding to these
* code attributes, or -1 if these attributes are not code
* attributes.
* @param maxLocals
* the maximum number of local variables of the method
* corresponding to these code attributes, or -1 if these
* attributes are not code attributes.
* @param out
* where the attributes must be written.
* @param symbolTable where the constants used in the attributes must be stored.
* @param output where the attributes must be written.
*/
final void put(final ClassWriter cw, final byte[] code, final int len,
final int maxStack, final int maxLocals, final ByteVector out) {
Attribute attr = this;
while (attr != null) {
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals);
out.putShort(cw.newUTF8(attr.type)).putInt(b.length);
out.putByteArray(b.data, 0, b.length);
attr = attr.next;
final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
final byte[] code = null;
final int codeLength = 0;
final int maxStack = -1;
final int maxLocals = -1;
putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
}
/**
* Puts all the attributes of the attribute list that begins with this attribute, in the given
* byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
* attribute.
*
* @param symbolTable where the constants used in the attributes must be stored.
* @param code the bytecode of the method corresponding to these code attributes, or {@literal
* null} if they are not code attributes. Corresponds to the 'code' field of the Code
* attribute.
* @param codeLength the length of the bytecode of the method corresponding to these code
* attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
* the Code attribute.
* @param maxStack the maximum stack size of the method corresponding to these code attributes, or
* -1 if they are not code attributes.
* @param maxLocals the maximum number of local variables of the method corresponding to these
* code attributes, or -1 if they are not code attribute.
* @param output where the attributes must be written.
*/
final void putAttributes(
final SymbolTable symbolTable,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals,
final ByteVector output) {
final ClassWriter classWriter = symbolTable.classWriter;
Attribute attribute = this;
while (attribute != null) {
ByteVector attributeContent =
attribute.write(classWriter, code, codeLength, maxStack, maxLocals);
// Put attribute_name_index and attribute_length.
output.putShort(symbolTable.addConstantUtf8(attribute.type)).putInt(attributeContent.length);
output.putByteArray(attributeContent.data, 0, attributeContent.length);
attribute = attribute.nextAttribute;
}
}
//The stuff below is temporary - once proper support for nestmate attribute has been added, it can be safely removed.
//see also changes in ClassReader.accept.
/** A set of attribute prototypes (attributes with the same type are considered equal). */
static final class Set {
public static class NestMembers extends Attribute {
public NestMembers() {
super("NestMembers");
}
private static final int SIZE_INCREMENT = 6;
byte[] bytes;
String[] classes;
private int size;
private Attribute[] data = new Attribute[SIZE_INCREMENT];
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off;
NestMembers a = new NestMembers();
int size = cr.readShort(off);
a.classes = new String[size];
off += 2;
for (int i = 0; i < size ; i++) {
a.classes[i] = cr.readClass(off, buf);
off += 2;
void addAttributes(final Attribute attributeList) {
Attribute attribute = attributeList;
while (attribute != null) {
if (!contains(attribute)) {
add(attribute);
}
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a;
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length);
v.putShort(classes.length);
for (String s : classes) {
v.putShort(cw.newClass(s));
}
return v;
attribute = attribute.nextAttribute;
}
}
public static class NestHost extends Attribute {
byte[] bytes;
String clazz;
public NestHost() {
super("NestHost");
Attribute[] toArray() {
Attribute[] result = new Attribute[size];
System.arraycopy(data, 0, result, 0, size);
return result;
}
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) {
int offset = off;
NestHost a = new NestHost();
a.clazz = cr.readClass(off, buf);
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a;
private boolean contains(final Attribute attribute) {
for (int i = 0; i < size; ++i) {
if (data[i].type.equals(attribute.type)) {
return true;
}
}
return false;
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) {
ByteVector v = new ByteVector(bytes.length);
v.putShort(cw.newClass(clazz));
return v;
private void add(final Attribute attribute) {
if (size >= data.length) {
Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
data[size++] = attribute;
}
}
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
new NestMembers(),
new NestHost()
};
}

View file

@ -59,309 +59,333 @@
package jdk.internal.org.objectweb.asm;
/**
* A dynamically extensible vector of bytes. This class is roughly equivalent to
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient.
* A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
* on top of a ByteArrayOutputStream, but is more efficient.
*
* @author Eric Bruneton
*/
public class ByteVector {
/**
* The content of this vector.
*/
/** The content of this vector. Only the first {@link #length} bytes contain real data. */
byte[] data;
/**
* Actual number of bytes in this vector.
*/
/** The actual number of bytes in this vector. */
int length;
/**
* Constructs a new {@link ByteVector ByteVector} with a default initial
* size.
*/
/** Constructs a new {@link ByteVector} with a default initial capacity. */
public ByteVector() {
data = new byte[64];
}
/**
* Constructs a new {@link ByteVector ByteVector} with the given initial
* size.
* Constructs a new {@link ByteVector} with the given initial capacity.
*
* @param initialSize
* the initial size of the byte vector to be constructed.
* @param initialCapacity the initial capacity of the byte vector to be constructed.
*/
public ByteVector(final int initialSize) {
data = new byte[initialSize];
public ByteVector(final int initialCapacity) {
data = new byte[initialCapacity];
}
/**
* Puts a byte into this byte vector. The byte vector is automatically
* enlarged if necessary.
* Constructs a new {@link ByteVector} from the given initial data.
*
* @param b
* a byte.
* @param data the initial data of the new byte vector.
*/
ByteVector(final byte[] data) {
this.data = data;
this.length = data.length;
}
/**
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param byteValue a byte.
* @return this byte vector.
*/
public ByteVector putByte(final int b) {
int length = this.length;
if (length + 1 > data.length) {
public ByteVector putByte(final int byteValue) {
int currentLength = length;
if (currentLength + 1 > data.length) {
enlarge(1);
}
data[length++] = (byte) b;
this.length = length;
data[currentLength++] = (byte) byteValue;
length = currentLength;
return this;
}
/**
* Puts two bytes into this byte vector. The byte vector is automatically
* enlarged if necessary.
* Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param b1
* a byte.
* @param b2
* another byte.
* @param byteValue1 a byte.
* @param byteValue2 another byte.
* @return this byte vector.
*/
ByteVector put11(final int b1, final int b2) {
int length = this.length;
if (length + 2 > data.length) {
final ByteVector put11(final int byteValue1, final int byteValue2) {
int currentLength = length;
if (currentLength + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) b1;
data[length++] = (byte) b2;
this.length = length;
byte[] currentData = data;
currentData[currentLength++] = (byte) byteValue1;
currentData[currentLength++] = (byte) byteValue2;
length = currentLength;
return this;
}
/**
* Puts a short into this byte vector. The byte vector is automatically
* enlarged if necessary.
* Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param s
* a short.
* @param shortValue a short.
* @return this byte vector.
*/
public ByteVector putShort(final int s) {
int length = this.length;
if (length + 2 > data.length) {
public ByteVector putShort(final int shortValue) {
int currentLength = length;
if (currentLength + 2 > data.length) {
enlarge(2);
}
byte[] data = this.data;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
byte[] currentData = data;
currentData[currentLength++] = (byte) (shortValue >>> 8);
currentData[currentLength++] = (byte) shortValue;
length = currentLength;
return this;
}
/**
* Puts a byte and a short into this byte vector. The byte vector is
* automatically enlarged if necessary.
* Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
* necessary.
*
* @param b
* a byte.
* @param s
* a short.
* @param byteValue a byte.
* @param shortValue a short.
* @return this byte vector.
*/
ByteVector put12(final int b, final int s) {
int length = this.length;
if (length + 3 > data.length) {
final ByteVector put12(final int byteValue, final int shortValue) {
int currentLength = length;
if (currentLength + 3 > data.length) {
enlarge(3);
}
byte[] data = this.data;
data[length++] = (byte) b;
data[length++] = (byte) (s >>> 8);
data[length++] = (byte) s;
this.length = length;
byte[] currentData = data;
currentData[currentLength++] = (byte) byteValue;
currentData[currentLength++] = (byte) (shortValue >>> 8);
currentData[currentLength++] = (byte) shortValue;
length = currentLength;
return this;
}
/**
* Puts an int into this byte vector. The byte vector is automatically
* enlarged if necessary.
* Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
* necessary.
*
* @param i
* an int.
* @param byteValue1 a byte.
* @param byteValue2 another byte.
* @param shortValue a short.
* @return this byte vector.
*/
public ByteVector putInt(final int i) {
int length = this.length;
if (length + 4 > data.length) {
final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
int currentLength = length;
if (currentLength + 4 > data.length) {
enlarge(4);
}
byte[] data = this.data;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
byte[] currentData = data;
currentData[currentLength++] = (byte) byteValue1;
currentData[currentLength++] = (byte) byteValue2;
currentData[currentLength++] = (byte) (shortValue >>> 8);
currentData[currentLength++] = (byte) shortValue;
length = currentLength;
return this;
}
/**
* Puts a long into this byte vector. The byte vector is automatically
* enlarged if necessary.
* Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param l
* a long.
* @param intValue an int.
* @return this byte vector.
*/
public ByteVector putLong(final long l) {
int length = this.length;
if (length + 8 > data.length) {
public ByteVector putInt(final int intValue) {
int currentLength = length;
if (currentLength + 4 > data.length) {
enlarge(4);
}
byte[] currentData = data;
currentData[currentLength++] = (byte) (intValue >>> 24);
currentData[currentLength++] = (byte) (intValue >>> 16);
currentData[currentLength++] = (byte) (intValue >>> 8);
currentData[currentLength++] = (byte) intValue;
length = currentLength;
return this;
}
/**
* Puts one byte and two shorts into this byte vector. The byte vector is automatically enlarged
* if necessary.
*
* @param byteValue a byte.
* @param shortValue1 a short.
* @param shortValue2 another short.
* @return this byte vector.
*/
final ByteVector put122(final int byteValue, final int shortValue1, final int shortValue2) {
int currentLength = length;
if (currentLength + 5 > data.length) {
enlarge(5);
}
byte[] currentData = data;
currentData[currentLength++] = (byte) byteValue;
currentData[currentLength++] = (byte) (shortValue1 >>> 8);
currentData[currentLength++] = (byte) shortValue1;
currentData[currentLength++] = (byte) (shortValue2 >>> 8);
currentData[currentLength++] = (byte) shortValue2;
length = currentLength;
return this;
}
/**
* Puts a long into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param longValue a long.
* @return this byte vector.
*/
public ByteVector putLong(final long longValue) {
int currentLength = length;
if (currentLength + 8 > data.length) {
enlarge(8);
}
byte[] data = this.data;
int i = (int) (l >>> 32);
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
i = (int) l;
data[length++] = (byte) (i >>> 24);
data[length++] = (byte) (i >>> 16);
data[length++] = (byte) (i >>> 8);
data[length++] = (byte) i;
this.length = length;
byte[] currentData = data;
int intValue = (int) (longValue >>> 32);
currentData[currentLength++] = (byte) (intValue >>> 24);
currentData[currentLength++] = (byte) (intValue >>> 16);
currentData[currentLength++] = (byte) (intValue >>> 8);
currentData[currentLength++] = (byte) intValue;
intValue = (int) longValue;
currentData[currentLength++] = (byte) (intValue >>> 24);
currentData[currentLength++] = (byte) (intValue >>> 16);
currentData[currentLength++] = (byte) (intValue >>> 8);
currentData[currentLength++] = (byte) intValue;
length = currentLength;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary.
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
* necessary.
*
* @param s
* a String whose UTF8 encoded length must be less than 65536.
* @param stringValue a String whose UTF8 encoded length must be less than 65536.
* @return this byte vector.
*/
public ByteVector putUTF8(final String s) {
int charLength = s.length();
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public ByteVector putUTF8(final String stringValue) {
int charLength = stringValue.length();
if (charLength > 65535) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("UTF8 string too large");
}
int len = length;
if (len + 2 + charLength > data.length) {
int currentLength = length;
if (currentLength + 2 + charLength > data.length) {
enlarge(2 + charLength);
}
byte[] data = this.data;
// optimistic algorithm: instead of computing the byte length and then
// serializing the string (which requires two loops), we assume the byte
// length is equal to char length (which is the most frequent case), and
// we start serializing the string right away. During the serialization,
// if we find that this assumption is wrong, we continue with the
// general method.
data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength;
byte[] currentData = data;
// Optimistic algorithm: instead of computing the byte length and then serializing the string
// (which requires two loops), we assume the byte length is equal to char length (which is the
// most frequent case), and we start serializing the string right away. During the
// serialization, if we find that this assumption is wrong, we continue with the general method.
currentData[currentLength++] = (byte) (charLength >>> 8);
currentData[currentLength++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
char charValue = stringValue.charAt(i);
if (charValue >= '\u0001' && charValue <= '\u007F') {
currentData[currentLength++] = (byte) charValue;
} else {
length = len;
return encodeUTF8(s, i, 65535);
length = currentLength;
return encodeUtf8(stringValue, i, 65535);
}
}
length = len;
length = currentLength;
return this;
}
/**
* Puts an UTF8 string into this byte vector. The byte vector is
* automatically enlarged if necessary. The string length is encoded in two
* bytes before the encoded characters, if there is space for that (i.e. if
* this.length - i - 2 >= 0).
* Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
* necessary. The string length is encoded in two bytes before the encoded characters, if there is
* space for that (i.e. if this.length - offset - 2 &gt;= 0).
*
* @param s
* the String to encode.
* @param i
* the index of the first character to encode. The previous
* characters are supposed to have already been encoded, using
* only one byte per character.
* @param maxByteLength
* the maximum byte length of the encoded string, including the
* already encoded characters.
* @param stringValue the String to encode.
* @param offset the index of the first character to encode. The previous characters are supposed
* to have already been encoded, using only one byte per character.
* @param maxByteLength the maximum byte length of the encoded string, including the already
* encoded characters.
* @return this byte vector.
*/
ByteVector encodeUTF8(final String s, int i, int maxByteLength) {
int charLength = s.length();
int byteLength = i;
char c;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
int charLength = stringValue.length();
int byteLength = offset;
for (int i = offset; i < charLength; ++i) {
char charValue = stringValue.charAt(i);
if (charValue >= 0x0001 && charValue <= 0x007F) {
byteLength++;
} else if (c > '\u07FF') {
byteLength += 3;
} else {
} else if (charValue <= 0x07FF) {
byteLength += 2;
} else {
byteLength += 3;
}
}
if (byteLength > maxByteLength) {
throw new IllegalArgumentException();
throw new IllegalArgumentException("UTF8 string too large");
}
int start = length - i - 2;
if (start >= 0) {
data[start] = (byte) (byteLength >>> 8);
data[start + 1] = (byte) byteLength;
// Compute where 'byteLength' must be stored in 'data', and store it at this location.
int byteLengthOffset = length - offset - 2;
if (byteLengthOffset >= 0) {
data[byteLengthOffset] = (byte) (byteLength >>> 8);
data[byteLengthOffset + 1] = (byte) byteLength;
}
if (length + byteLength - i > data.length) {
enlarge(byteLength - i);
if (length + byteLength - offset > data.length) {
enlarge(byteLength - offset);
}
int len = length;
for (int j = i; j < charLength; ++j) {
c = s.charAt(j);
if (c >= '\001' && c <= '\177') {
data[len++] = (byte) c;
} else if (c > '\u07FF') {
data[len++] = (byte) (0xE0 | c >> 12 & 0xF);
data[len++] = (byte) (0x80 | c >> 6 & 0x3F);
data[len++] = (byte) (0x80 | c & 0x3F);
int currentLength = length;
for (int i = offset; i < charLength; ++i) {
char charValue = stringValue.charAt(i);
if (charValue >= 0x0001 && charValue <= 0x007F) {
data[currentLength++] = (byte) charValue;
} else if (charValue <= 0x07FF) {
data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
} else {
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F);
data[len++] = (byte) (0x80 | c & 0x3F);
data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
}
}
length = len;
length = currentLength;
return this;
}
/**
* Puts an array of bytes into this byte vector. The byte vector is
* automatically enlarged if necessary.
* Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
* necessary.
*
* @param b
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt>
* null bytes into this byte vector.
* @param off
* index of the fist byte of b that must be copied.
* @param len
* number of bytes of b that must be copied.
* @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
* bytes into this byte vector.
* @param byteOffset index of the first byte of byteArrayValue that must be copied.
* @param byteLength number of bytes of byteArrayValue that must be copied.
* @return this byte vector.
*/
public ByteVector putByteArray(final byte[] b, final int off, final int len) {
if (length + len > data.length) {
enlarge(len);
public ByteVector putByteArray(
final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
if (length + byteLength > data.length) {
enlarge(byteLength);
}
if (b != null) {
System.arraycopy(b, off, data, length, len);
if (byteArrayValue != null) {
System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
}
length += len;
length += byteLength;
return this;
}
/**
* Enlarge this byte vector so that it can receive n more bytes.
* Enlarges this byte vector so that it can receive 'size' more bytes.
*
* @param size
* number of additional bytes that this byte vector should be
* able to receive.
* @param size number of additional bytes that this byte vector should be able to receive.
*/
private void enlarge(final int size) {
int length1 = 2 * data.length;
int length2 = length + size;
byte[] newData = new byte[length1 > length2 ? length1 : length2];
int doubleCapacity = 2 * data.length;
int minimalCapacity = length + size;
byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
System.arraycopy(data, 0, newData, 0, length);
data = newData;
}

View file

@ -0,0 +1,102 @@
/*
* 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;
/**
* Exception thrown when the constant pool of a class produced by a {@link ClassWriter} is too
* large.
*
* @author Jason Zaugg
*/
public final class ClassTooLargeException extends IndexOutOfBoundsException {
private static final long serialVersionUID = 160715609518896765L;
private final String className;
private final int constantPoolCount;
/**
* Constructs a new {@link ClassTooLargeException}.
*
* @param className the internal name of the class.
* @param constantPoolCount the number of constant pool items of the class.
*/
public ClassTooLargeException(final String className, final int constantPoolCount) {
super("Class too large: " + className);
this.className = className;
this.constantPoolCount = constantPoolCount;
}
/**
* Returns the internal name of the class.
*
* @return the internal name of the class.
*/
public String getClassName() {
return className;
}
/**
* Returns the number of constant pool items of the class.
*
* @return the number of constant pool items of the class.
*/
public int getConstantPoolCount() {
return constantPoolCount;
}
}

View file

@ -59,35 +59,30 @@
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: <tt>visit</tt> [ <tt>visitSource</tt> ] [
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* (
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )*
* <tt>visitEnd</tt>.
* 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}.
*
* @author Eric Bruneton
*/
public abstract class ClassVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
protected final int api;
/**
* The 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 null. */
protected ClassVisitor cv;
/**
* 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} or {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public ClassVisitor(final int api) {
this(api, null);
@ -96,48 +91,42 @@ 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} or {@link Opcodes#ASM6}.
* @param cv
* the class visitor to which this visitor must delegate method
* calls. May be null.
* @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 classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.
*/
public ClassVisitor(final int api, final ClassVisitor cv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
}
this.api = api;
this.cv = cv;
this.cv = classVisitor;
}
/**
* Visits the header of the class.
*
* @param version
* the class version.
* @param access
* the class's access flags (see {@link Opcodes}). This parameter
* also indicates if the class is deprecated.
* @param name
* the internal name of the class (see
* {@link Type#getInternalName() getInternalName}).
* @param signature
* the signature of this class. May be <tt>null</tt> if the class
* is not a generic one, and does not extend or implement generic
* classes or interfaces.
* @param superName
* the internal of name of the super class (see
* {@link Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be
* <tt>null</tt>, but only for the {@link Object} class.
* @param interfaces
* the internal names of the class's interfaces (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @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.
* @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.
* @param superName the internal of name of the super class (see {@link Type#getInternalName()}).
* For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
* {@link Object} class.
* @param interfaces the internal names of the class's interfaces (see {@link
* Type#getInternalName()}). May be {@literal null}.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces);
}
@ -146,15 +135,12 @@ public abstract class ClassVisitor {
/**
* Visits the source of the class.
*
* @param source
* the name of the source file from which the class was compiled.
* May be <tt>null</tt>.
* @param debug
* additional debug information to compute the correspondance
* between source and compiled elements of the class. May be
* <tt>null</tt>.
* @param source the name of the source file from which the class was compiled. May be {@literal
* null}.
* @param debug additional debug information to compute the correspondence between source and
* compiled elements of the class. May be {@literal null}.
*/
public void visitSource(String source, String debug) {
public void visitSource(final String source, final String debug) {
if (cv != null) {
cv.visitSource(source, debug);
}
@ -162,19 +148,17 @@ public abstract class ClassVisitor {
/**
* Visit the module corresponding to the class.
* @param name
* module name
* @param access
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
* and {@code ACC_MANDATED}.
* @param version
* module version or null.
* @return a visitor to visit the module values, or <tt>null</tt> if
* this visitor is not interested in visiting this module.
*
* @param name the fully qualified name (using dots) of the module.
* @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
* ACC_MANDATED}.
* @param version the module version, or {@literal null}.
* @return a visitor to visit the module values, or {@literal null} if this visitor is not
* interested in visiting this module.
*/
public ModuleVisitor visitModule(String name, int access, String version) {
public ModuleVisitor visitModule(final String name, final int access, final String version) {
if (api < Opcodes.ASM6) {
throw new RuntimeException();
throw new UnsupportedOperationException("This feature requires ASM6");
}
if (cv != null) {
return cv.visitModule(name, access, version);
@ -183,39 +167,51 @@ public abstract class ClassVisitor {
}
/**
* Visits the enclosing class of the class. This method must be called only
* if the class has an enclosing class.
* Visits the nest host class of the class. A nest is a set of classes of the same package that
* share access to their private members. One of these classes, called the host, lists the other
* members of the nest, which in turn should link to the host of their nest. This method must be
* called only once and only if the visited class is a non-host member of a nest. A class is
* implicitly its own nest, so it's invalid to call this method with the visited class name as
* argument.
*
* @param owner
* internal name of the enclosing class of the class.
* @param name
* the name of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
* @param desc
* the descriptor of the method that contains the class, or
* <tt>null</tt> if the class is not enclosed in a method of its
* enclosing class.
* @param nestHost the internal name of the host class of the nest.
*/
public void visitOuterClass(String owner, String name, String desc) {
public void visitNestHost(final String nestHost) {
if (api < Opcodes.ASM7) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (cv != null) {
cv.visitOuterClass(owner, name, desc);
cv.visitNestHost(nestHost);
}
}
/**
* Visits the enclosing class of the class. This method must be called only if the class has an
* enclosing class.
*
* @param owner internal name of the enclosing class of the class.
* @param name the name of the method that contains the class, or {@literal null} if the class is
* not enclosed in a method of its enclosing class.
* @param descriptor the descriptor of the method that contains the class, or {@literal null} if
* the class is not enclosed in a method of its enclosing class.
*/
public void visitOuterClass(final String owner, final String name, final String descriptor) {
if (cv != null) {
cv.visitOuterClass(owner, name, descriptor);
}
}
/**
* Visits an annotation of the class.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
* @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(String desc, boolean visible) {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (cv != null) {
return cv.visitAnnotation(desc, visible);
return cv.visitAnnotation(descriptor, visible);
}
return null;
}
@ -223,32 +219,25 @@ public abstract class ClassVisitor {
/**
* Visits an annotation on a type in the class signature.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER
* CLASS_TYPE_PARAMETER},
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND
* CLASS_TYPE_PARAMETER_BOUND} or
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See
* @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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
* @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(int typeRef,
TypePath typePath, String desc, boolean visible) {
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
throw new UnsupportedOperationException("This feature requires ASM5");
}
if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible);
return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
return null;
}
@ -256,35 +245,46 @@ public abstract class ClassVisitor {
/**
* Visits a non standard attribute of the class.
*
* @param attr
* an attribute.
* @param attribute an attribute.
*/
public void visitAttribute(Attribute attr) {
public void visitAttribute(final Attribute attribute) {
if (cv != null) {
cv.visitAttribute(attr);
cv.visitAttribute(attribute);
}
}
/**
* Visits information about an inner class. This inner class is not
* necessarily a member of the class being visited.
* Visits a member of the nest. A nest is a set of classes of the same package that share access
* to their private members. One of these classes, called the host, lists the other members of the
* nest, which in turn should link to the host of their nest. This method must be called only if
* the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
* it's invalid to call this method with the visited class name as argument.
*
* @param name
* the internal name of an inner class (see
* {@link Type#getInternalName() getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link Type#getInternalName() getInternalName}).
* May be <tt>null</tt> for not member classes.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
* @param nestMember the internal name of a nest member.
*/
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
public void visitNestMember(final String nestMember) {
if (api < Opcodes.ASM7) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (cv != null) {
cv.visitNestMember(nestMember);
}
}
/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited.
*
* @param name the internal name of an inner class (see {@link Type#getInternalName()}).
* @param outerName the internal name of the class to which the inner class belongs (see {@link
* Type#getInternalName()}). May be {@literal null} for not member classes.
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
* {@literal null} for anonymous inner classes.
* @param access the access flags of the inner class as originally declared in the enclosing
* class.
*/
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
if (cv != null) {
cv.visitInnerClass(name, outerName, innerName, access);
}
@ -293,75 +293,64 @@ public abstract class ClassVisitor {
/**
* Visits a field of the class.
*
* @param access
* the field's access flags (see {@link Opcodes}). This parameter
* also indicates if the field is synthetic and/or deprecated.
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type Type}).
* @param signature
* the field's signature. May be <tt>null</tt> if the field's
* type does not use generic types.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String} (for <tt>int</tt>,
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields
* respectively). <i>This parameter is only used for static
* fields</i>. Its value is ignored for non static fields, which
* must be initialized through bytecode instructions in
* constructors or methods.
* @return a visitor to visit field annotations and attributes, or
* <tt>null</tt> if this class visitor is not interested in visiting
* these annotations and attributes.
* @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
* the field is synthetic and/or deprecated.
* @param name the field's name.
* @param descriptor the field's descriptor (see {@link Type}).
* @param signature the field's signature. May be {@literal null} if the field's type does not use
* generic types.
* @param value the field's initial value. This parameter, which may be {@literal null} if the
* field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
* Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long}
* or {@code String} fields respectively). <i>This parameter is only used for static
* fields</i>. Its value is ignored for non static fields, which must be initialized through
* bytecode instructions in constructors or methods.
* @return a visitor to visit field annotations and attributes, or {@literal null} if this class
* visitor is not interested in visiting these annotations and attributes.
*/
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
if (cv != null) {
return cv.visitField(access, name, desc, signature, value);
return cv.visitField(access, name, descriptor, signature, value);
}
return null;
}
/**
* Visits a method of the class. This method <i>must</i> return a new
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called,
* i.e., it should not return a previously returned visitor.
* Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
* instance (or {@literal null}) each time it is called, i.e., it should not return a previously
* returned visitor.
*
* @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.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param signature
* the method's signature. May be <tt>null</tt> if the method
* parameters, return type and exceptions do not use generic
* types.
* @param exceptions
* the internal names of the method's exception classes (see
* {@link Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* @return an object to visit the byte code of the method, or <tt>null</tt>
* if this class visitor is not interested in visiting the code of
* this method.
* @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.
* @param descriptor the method's descriptor (see {@link Type}).
* @param signature the method's signature. May be {@literal null} if the method parameters,
* return type and exceptions do not use generic types.
* @param exceptions the internal names of the method's exception classes (see {@link
* Type#getInternalName()}). May be {@literal null}.
* @return an object to visit the byte code of the method, or {@literal null} if this class
* visitor is not interested in visiting the code of this method.
*/
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
if (cv != null) {
return cv.visitMethod(access, name, desc, signature, exceptions);
return cv.visitMethod(access, name, descriptor, signature, exceptions);
}
return null;
}
/**
* Visits the end of the class. This method, which is the last one to be
* called, is used to inform the visitor that all the fields and methods of
* the class have been visited.
* Visits the end of the class. This method, which is the last one to be called, is used to inform
* the visitor that all the fields and methods of the class have been visited.
*/
public void visitEnd() {
if (cv != null) {

View file

@ -0,0 +1,209 @@
/*
* 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;
import java.util.Arrays;
/**
* A constant whose value is computed at runtime, with a bootstrap method.
*
* @author Remi Forax
*/
public final class ConstantDynamic {
/** The constant name (can be arbitrary). */
private final String name;
/** The constant type (must be a field descriptor). */
private final String descriptor;
/** The bootstrap method to use to compute the constant value at runtime. */
private final Handle bootstrapMethod;
/**
* The arguments to pass to the bootstrap method, in order to compute the constant value at
* runtime.
*/
private final Object[] bootstrapMethodArguments;
/**
* Constructs a new {@link ConstantDynamic}.
*
* @param name the constant name (can be arbitrary).
* @param descriptor the constant type (must be a field descriptor).
* @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
* @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
* compute the constant value at runtime.
*/
public ConstantDynamic(
final String name,
final String descriptor,
final Handle bootstrapMethod,
final Object... bootstrapMethodArguments) {
this.name = name;
this.descriptor = descriptor;
this.bootstrapMethod = bootstrapMethod;
this.bootstrapMethodArguments = bootstrapMethodArguments;
}
/**
* Returns the name of this constant.
*
* @return the name of this constant.
*/
public String getName() {
return name;
}
/**
* Returns the type of this constant.
*
* @return the type of this constant, as a field descriptor.
*/
public String getDescriptor() {
return descriptor;
}
/**
* Returns the bootstrap method used to compute the value of this constant.
*
* @return the bootstrap method used to compute the value of this constant.
*/
public Handle getBootstrapMethod() {
return bootstrapMethod;
}
/**
* Returns the number of arguments passed to the bootstrap method, in order to compute the value
* of this constant.
*
* @return the number of arguments passed to the bootstrap method, in order to compute the value
* of this constant.
*/
public int getBootstrapMethodArgumentCount() {
return bootstrapMethodArguments.length;
}
/**
* Returns an argument passed to the bootstrap method, in order to compute the value of this
* constant.
*
* @param index an argument index, between 0 and {@link #getBootstrapMethodArgumentCount()}
* (exclusive).
* @return the argument passed to the bootstrap method, with the given index.
*/
public Object getBootstrapMethodArgument(final int index) {
return bootstrapMethodArguments[index];
}
/**
* Returns the arguments to pass to the bootstrap method, in order to compute the value of this
* constant. WARNING: this array must not be modified, and must not be returned to the user.
*
* @return the arguments to pass to the bootstrap method, in order to compute the value of this
* constant.
*/
Object[] getBootstrapMethodArgumentsUnsafe() {
return bootstrapMethodArguments;
}
/**
* Returns the size of this constant.
*
* @return the size of this constant, i.e., 2 for {@code long} and {@code double}, 1 otherwise.
*/
public int getSize() {
char firstCharOfDescriptor = descriptor.charAt(0);
return (firstCharOfDescriptor == 'J' || firstCharOfDescriptor == 'D') ? 2 : 1;
}
@Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (!(object instanceof ConstantDynamic)) {
return false;
}
ConstantDynamic constantDynamic = (ConstantDynamic) object;
return name.equals(constantDynamic.name)
&& descriptor.equals(constantDynamic.descriptor)
&& bootstrapMethod.equals(constantDynamic.bootstrapMethod)
&& Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
}
@Override
public int hashCode() {
return name.hashCode()
^ Integer.rotateLeft(descriptor.hashCode(), 8)
^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
}
@Override
public String toString() {
return name
+ " : "
+ descriptor
+ ' '
+ bootstrapMethod
+ ' '
+ Arrays.toString(bootstrapMethodArguments);
}
}

View file

@ -0,0 +1,208 @@
/*
* 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;
/**
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
* API.
*
* @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 {
// 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.
static final String CONSTANT_VALUE = "ConstantValue";
static final String CODE = "Code";
static final String STACK_MAP_TABLE = "StackMapTable";
static final String EXCEPTIONS = "Exceptions";
static final String INNER_CLASSES = "InnerClasses";
static final String ENCLOSING_METHOD = "EnclosingMethod";
static final String SYNTHETIC = "Synthetic";
static final String SIGNATURE = "Signature";
static final String SOURCE_FILE = "SourceFile";
static final String SOURCE_DEBUG_EXTENSION = "SourceDebugExtension";
static final String LINE_NUMBER_TABLE = "LineNumberTable";
static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
static final String LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable";
static final String DEPRECATED = "Deprecated";
static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations";
static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
"RuntimeInvisibleParameterAnnotations";
static final String RUNTIME_VISIBLE_TYPE_ANNOTATIONS = "RuntimeVisibleTypeAnnotations";
static final String RUNTIME_INVISIBLE_TYPE_ANNOTATIONS = "RuntimeInvisibleTypeAnnotations";
static final String ANNOTATION_DEFAULT = "AnnotationDefault";
static final String BOOTSTRAP_METHODS = "BootstrapMethods";
static final String METHOD_PARAMETERS = "MethodParameters";
static final String MODULE = "Module";
static final String MODULE_PACKAGES = "ModulePackages";
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers";
// ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
// 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).
static final int ACC_CONSTRUCTOR = 0x40000; // method access flag.
// ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
/**
* A frame inserted between already existing frames. This internal stack map frame type (in
* addition to the ones declared in {@link Opcodes}) can only be used if the frame content can be
* computed from the previous existing frame and from the instructions between this existing frame
* and the inserted one, without any knowledge of the type hierarchy. This kind of frame is only
* used when an unconditional jump is inserted in a method while expanding an ASM specific
* instruction. Keep in sync with Opcodes.java.
*/
static final int F_INSERT = 256;
// The JVM opcode values which are not part of the ASM public API.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
static final int LDC_W = 19;
static final int LDC2_W = 20;
static final int ILOAD_0 = 26;
static final int ILOAD_1 = 27;
static final int ILOAD_2 = 28;
static final int ILOAD_3 = 29;
static final int LLOAD_0 = 30;
static final int LLOAD_1 = 31;
static final int LLOAD_2 = 32;
static final int LLOAD_3 = 33;
static final int FLOAD_0 = 34;
static final int FLOAD_1 = 35;
static final int FLOAD_2 = 36;
static final int FLOAD_3 = 37;
static final int DLOAD_0 = 38;
static final int DLOAD_1 = 39;
static final int DLOAD_2 = 40;
static final int DLOAD_3 = 41;
static final int ALOAD_0 = 42;
static final int ALOAD_1 = 43;
static final int ALOAD_2 = 44;
static final int ALOAD_3 = 45;
static final int ISTORE_0 = 59;
static final int ISTORE_1 = 60;
static final int ISTORE_2 = 61;
static final int ISTORE_3 = 62;
static final int LSTORE_0 = 63;
static final int LSTORE_1 = 64;
static final int LSTORE_2 = 65;
static final int LSTORE_3 = 66;
static final int FSTORE_0 = 67;
static final int FSTORE_1 = 68;
static final int FSTORE_2 = 69;
static final int FSTORE_3 = 70;
static final int DSTORE_0 = 71;
static final int DSTORE_1 = 72;
static final int DSTORE_2 = 73;
static final int DSTORE_3 = 74;
static final int ASTORE_0 = 75;
static final int ASTORE_1 = 76;
static final int ASTORE_2 = 77;
static final int ASTORE_3 = 78;
static final int WIDE = 196;
static final int GOTO_W = 200;
static final int JSR_W = 201;
// 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;
// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.
// The delta between the ASM_IFEQ, ..., ASM_IF_ACMPNE, ASM_GOTO and ASM_JSR opcodes
// and IFEQ, ..., IF_ACMPNE, GOTO and JSR.
static final int ASM_OPCODE_DELTA = 49;
// The delta between the ASM_IFNULL and ASM_IFNONNULL opcodes and IFNULL and IFNONNULL.
static final int ASM_IFNULL_OPCODE_DELTA = 20;
// 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_GOTO_W = 220;
private Constants() {}
}

View file

@ -56,7 +56,6 @@
* 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;
/**
@ -64,111 +63,105 @@ package jdk.internal.org.objectweb.asm;
*
* @author Eric Bruneton
*/
class Context {
final class Context {
/** The prototypes of the attributes that must be parsed in this class. */
Attribute[] attributePrototypes;
/**
* Prototypes of the attributes that must be parsed for this class.
* The options used to parse this class. One or more of {@link ClassReader#SKIP_CODE}, {@link
* ClassReader#SKIP_DEBUG}, {@link ClassReader#SKIP_FRAMES}, {@link ClassReader#EXPAND_FRAMES} or
* {@link ClassReader#EXPAND_ASM_INSNS}.
*/
Attribute[] attrs;
int parsingOptions;
/** The buffer used to read strings in the constant pool. */
char[] charBuffer;
// Information about the current method, i.e. the one read in the current (or latest) call
// to {@link ClassReader#readMethod()}.
/** The access flags of the current method. */
int currentMethodAccessFlags;
/** The name of the current method. */
String currentMethodName;
/** The descriptor of the current method. */
String currentMethodDescriptor;
/**
* The {@link ClassReader} option flags for the parsing of this class.
* The labels of the current method, indexed by bytecode offset (only bytecode offsets for which a
* label is needed have a non null associated Label).
*/
int flags;
Label[] currentMethodLabels;
// Information about the current type annotation target, i.e. the one read in the current
// (or latest) call to {@link ClassReader#readAnnotationTarget()}.
/**
* The buffer used to read strings.
* The target_type and target_info of the current type annotation target, encoded as described in
* {@link TypeReference}.
*/
char[] buffer;
int currentTypeAnnotationTarget;
/** The target_path of the current type annotation target. */
TypePath currentTypeAnnotationTargetPath;
/** The start of each local variable range in the current local variable annotation. */
Label[] currentLocalVariableAnnotationRangeStarts;
/** The end of each local variable range in the current local variable annotation. */
Label[] currentLocalVariableAnnotationRangeEnds;
/**
* The start index of each bootstrap method.
* The local variable index of each local variable range in the current local variable annotation.
*/
int[] bootstrapMethods;
int[] currentLocalVariableAnnotationRangeIndices;
// Information about the current stack map frame, i.e. the one read in the current (or latest)
// call to {@link ClassReader#readFrame()}.
/** The bytecode offset of the current stack map frame. */
int currentFrameOffset;
/**
* The access flags of the method currently being parsed.
* The type of the current stack map frame. One of {@link Opcodes#F_FULL}, {@link
* Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or {@link Opcodes#F_SAME1}.
*/
int access;
int currentFrameType;
/**
* The name of the method currently being parsed.
* The number of local variable types in the current stack map frame. Each type is represented
* with a single array element (even long and double).
*/
String name;
int currentFrameLocalCount;
/**
* The descriptor of the method currently being parsed.
* The delta number of local variable types in the current stack map frame (each type is
* represented with a single array element - even long and double). This is the number of local
* variable types in this frame, minus the number of local variable types in the previous frame.
*/
String desc;
int currentFrameLocalCountDelta;
/**
* The label objects, indexed by bytecode offset, of the method currently
* being parsed (only bytecode offsets for which a label is needed have a
* non null associated Label object).
* The types of the local variables in the current stack map frame. Each type is represented with
* a single array element (even long and double), using the format described in {@link
* MethodVisitor#visitFrame}. Depending on {@link #currentFrameType}, this contains the types of
* all the local variables, or only those of the additional ones (compared to the previous frame).
*/
Label[] labels;
Object[] currentFrameLocalTypes;
/**
* The target of the type annotation currently being parsed.
* The number stack element types in the current stack map frame. Each type is represented with a
* single array element (even long and double).
*/
int typeRef;
int currentFrameStackCount;
/**
* The path of the type annotation currently being parsed.
* The types of the stack elements in the current stack map frame. Each type is represented with a
* single array element (even long and double), using the format described in {@link
* MethodVisitor#visitFrame}.
*/
TypePath typePath;
/**
* The offset of the latest stack map frame that has been parsed.
*/
int offset;
/**
* The labels corresponding to the start of the local variable ranges in the
* local variable type annotation currently being parsed.
*/
Label[] start;
/**
* The labels corresponding to the end of the local variable ranges in the
* local variable type annotation currently being parsed.
*/
Label[] end;
/**
* The local variable indices for each local variable range in the local
* variable type annotation currently being parsed.
*/
int[] index;
/**
* The encoding of the latest stack map frame that has been parsed.
*/
int mode;
/**
* The number of locals in the latest stack map frame that has been parsed.
*/
int localCount;
/**
* The number locals in the latest stack map frame that has been parsed,
* minus the number of locals in the previous frame.
*/
int localDiff;
/**
* The local values of the latest stack map frame that has been parsed.
*/
Object[] local;
/**
* The stack size of the latest stack map frame that has been parsed.
*/
int stackCount;
/**
* The stack values of the latest stack map frame that has been parsed.
*/
Object[] stack;
Object[] currentFrameStackTypes;
}

View file

@ -56,30 +56,31 @@
* 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;
/**
* Information about the input stack map frame at the "current" instruction of a
* method. This is implemented as a Frame subclass for a "basic block"
* containing only one instruction.
* Information about the input stack map frame at the "current" instruction of a method. This is
* implemented as a Frame subclass for a "basic block" containing only one instruction.
*
* @author Eric Bruneton
*/
class CurrentFrame extends Frame {
final class CurrentFrame extends Frame {
CurrentFrame(final Label owner) {
super(owner);
}
/**
* Sets this CurrentFrame to the input stack map frame of the next "current"
* instruction, i.e. the instruction just after the given one. It is assumed
* that the value of this object when this method is called is the stack map
* frame status just before the given instruction is executed.
* Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the
* instruction just after the given one. It is assumed that the value of this object when this
* method is called is the stack map frame status just before the given instruction is executed.
*/
@Override
void execute(int opcode, int arg, ClassWriter cw, Item item) {
super.execute(opcode, arg, cw, item);
Frame successor = new Frame();
merge(cw, successor, 0);
set(successor);
owner.inputStackTop = 0;
void execute(
final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) {
super.execute(opcode, arg, symbolArg, symbolTable);
Frame successor = new Frame(null);
merge(symbolTable, successor, 0);
copyFrom(successor);
}
}

View file

@ -59,46 +59,64 @@
package jdk.internal.org.objectweb.asm;
/**
* An edge in the control flow graph of a method body. See {@link Label Label}.
* An edge in the control flow graph of a method. Each node of this graph is a basic block,
* represented with the Label corresponding to its first instruction. Each edge goes from one node
* to another, i.e. from one basic block to another (called the predecessor and successor blocks,
* respectively). An edge corresponds either to a jump or ret instruction or to an exception
* handler.
*
* @see Label
* @author Eric Bruneton
*/
class Edge {
final class Edge {
/**
* Denotes a normal control flow graph edge.
* A control flow graph edge corresponding to a jump or ret instruction. Only used with {@link
* ClassWriter#COMPUTE_FRAMES}.
*/
static final int NORMAL = 0;
static final int JUMP = 0;
/**
* Denotes a control flow graph edge corresponding to an exception handler.
* More precisely any {@link Edge} whose {@link #info} is strictly positive
* corresponds to an exception handler. The actual value of {@link #info} is
* the index, in the {@link ClassWriter} type table, of the exception that
* is catched.
* A control flow graph edge corresponding to an exception handler. Only used with {@link
* ClassWriter#COMPUTE_MAXS}.
*/
static final int EXCEPTION = 0x7FFFFFFF;
/**
* Information about this control flow graph edge. If
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative)
* stack size in the basic block from which this edge originates. This size
* is equal to the stack size at the "jump" instruction to which this edge
* corresponds, relatively to the stack size at the beginning of the
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used,
* this field is the kind of this control flow graph edge (i.e. NORMAL or
* EXCEPTION).
* Information about this control flow graph edge.
*
* <ul>
* <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
* delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
* edge corresponding to an exception handler). The stack size delta is the stack size just
* after the jump instruction, minus the stack size at the beginning of the predecessor
* basic block, i.e. the one containing the jump instruction.
* <li>If {@link ClassWriter#COMPUTE_FRAMES} is used, this field contains either the value JUMP
* (for an edge corresponding to a jump instruction), or the index, in the {@link
* ClassWriter} type table, of the exception type that is handled (for an edge corresponding
* to an exception handler).
* </ul>
*/
int info;
final int info;
/** The successor block of this control flow graph edge. */
final Label successor;
/**
* The successor block of the basic block from which this edge originates.
* The next edge in the list of outgoing edges of a basic block. See {@link Label#outgoingEdges}.
*/
Label successor;
Edge nextEdge;
/**
* The next edge in the list of successors of the originating basic block.
* See {@link Label#successors successors}.
* Constructs a new Edge.
*
* @param info see {@link #info}.
* @param successor see {@link #successor}.
* @param nextEdge see {@link #nextEdge}.
*/
Edge next;
Edge(final int info, final Label successor, final Edge nextEdge) {
this.info = info;
this.successor = successor;
this.nextEdge = nextEdge;
}
}

View file

@ -59,32 +59,28 @@
package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a Java field. The methods of this class must be called in
* the following order: ( <tt>visitAnnotation</tt> |
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* <tt>visitEnd</tt>.
* A visitor to visit a Java field. The methods of this class must be called in the following order:
* ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code visitAttribute} )* {@code
* visitEnd}.
*
* @author Eric Bruneton
*/
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} or {@link Opcodes#ASM6}.
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
protected final int api;
/**
* The 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 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} or {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public FieldVisitor(final int api) {
this(api, null);
@ -93,34 +89,30 @@ 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} or {@link Opcodes#ASM6}.
* @param fv
* the field visitor to which this visitor must delegate method
* calls. May be null.
* @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 fieldVisitor the field visitor to which this visitor must delegate method calls. May be
* null.
*/
public FieldVisitor(final int api, final FieldVisitor fv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
public FieldVisitor(final int api, final FieldVisitor fieldVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
}
this.api = api;
this.fv = fv;
this.fv = fieldVisitor;
}
/**
* Visits an annotation of the field.
*
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
* @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(String desc, boolean visible) {
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (fv != null) {
return fv.visitAnnotation(desc, visible);
return fv.visitAnnotation(descriptor, visible);
}
return null;
}
@ -128,28 +120,23 @@ public abstract class FieldVisitor {
/**
* Visits an annotation on the type of the field.
*
* @param typeRef
* a reference to the annotated type. The sort of this type
* reference must be {@link TypeReference#FIELD FIELD}. 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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or <tt>null</tt> if
* this visitor is not interested in visiting this annotation.
* @param typeRef a reference to the annotated type. The sort of this type reference must be
* {@link TypeReference#FIELD}. 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(int typeRef,
TypePath typePath, String desc, boolean visible) {
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
throw new RuntimeException();
throw new UnsupportedOperationException("This feature requires ASM5");
}
if (fv != null) {
return fv.visitTypeAnnotation(typeRef, typePath, desc, visible);
return fv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
}
return null;
}
@ -157,19 +144,17 @@ public abstract class FieldVisitor {
/**
* Visits a non standard attribute of the field.
*
* @param attr
* an attribute.
* @param attribute an attribute.
*/
public void visitAttribute(Attribute attr) {
public void visitAttribute(final Attribute attribute) {
if (fv != null) {
fv.visitAttribute(attr);
fv.visitAttribute(attribute);
}
}
/**
* Visits the end of the field. This method, which is the last one to be
* called, is used to inform the visitor that all the annotations and
* attributes of the field have been visited.
* Visits the end of the field. This method, which is the last one to be called, is used to inform
* the visitor that all the annotations and attributes of the field have been visited.
*/
public void visitEnd() {
if (fv != null) {

View file

@ -59,294 +59,319 @@
package jdk.internal.org.objectweb.asm;
/**
* An {@link FieldVisitor} that generates Java fields in bytecode form.
* A {@link FieldVisitor} that generates a corresponding 'field_info' structure, 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.5">JVMS
* 4.5</a>
* @author Eric Bruneton
*/
final class FieldWriter extends FieldVisitor {
/**
* The class writer to which this field must be added.
*/
private final ClassWriter cw;
/** Where the constants used in this FieldWriter must be stored. */
private final SymbolTable symbolTable;
// Note: fields are ordered as in the field_info structure, and those related to attributes are
// ordered as in Section 4.7 of the JVMS.
/**
* Access flags of this field.
* The access_flags field of the field_info JVMS structure. This field can contain ASM specific
* access flags, such as {@link Opcodes#ACC_DEPRECATED}, which are removed when generating the
* ClassFile structure.
*/
private final int access;
private final int accessFlags;
/** The name_index field of the field_info JVMS structure. */
private final int nameIndex;
/** The descriptor_index field of the field_info JVMS structure. */
private final int descriptorIndex;
/**
* The index of the constant pool item that contains the name of this
* method.
* The signature_index field of the Signature attribute of this field_info, or 0 if there is no
* Signature attribute.
*/
private final int name;
private int signatureIndex;
/**
* The index of the constant pool item that contains the descriptor of this
* field.
* The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there
* is no ConstantValue attribute.
*/
private final int desc;
private int constantValueIndex;
/**
* The index of the constant pool item that contains the signature of this
* field.
* The last runtime visible annotation of this field. The previous ones can be accessed with the
* {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private int signature;
private AnnotationWriter lastRuntimeVisibleAnnotation;
/**
* The index of the constant pool item that contains the constant value of
* this field.
* The last runtime invisible annotation of this field. The previous ones can be accessed with the
* {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private int value;
private AnnotationWriter lastRuntimeInvisibleAnnotation;
/**
* The runtime visible annotations of this field. May be <tt>null</tt>.
* The last runtime visible type annotation of this field. The previous ones can be accessed with
* the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter anns;
private AnnotationWriter lastRuntimeVisibleTypeAnnotation;
/**
* The runtime invisible annotations of this field. May be <tt>null</tt>.
* The last runtime invisible type annotation of this field. The previous ones can be accessed
* with the {@link AnnotationWriter#previousAnnotation} field. May be {@literal null}.
*/
private AnnotationWriter ianns;
private AnnotationWriter lastRuntimeInvisibleTypeAnnotation;
/**
* The runtime visible type annotations of this field. May be <tt>null</tt>.
* The first non standard attribute of this field. 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}. The {@link
* #putFieldInfo} method writes the attributes in the order defined by this list, i.e. in the
* reverse order specified by the user.
*/
private AnnotationWriter tanns;
private Attribute firstAttribute;
/**
* The runtime invisible type annotations of this field. May be
* <tt>null</tt>.
*/
private AnnotationWriter itanns;
/**
* The non standard attributes of this field. May be <tt>null</tt>.
*/
private Attribute attrs;
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Constructs a new {@link FieldWriter}.
*
* @param cw
* the class writer to which this field must be added.
* @param access
* the field's access flags (see {@link Opcodes}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link Type}).
* @param signature
* the field's signature. May be <tt>null</tt>.
* @param value
* the field's constant value. May be <tt>null</tt>.
* @param symbolTable where the constants used in this FieldWriter must be stored.
* @param access the field's access flags (see {@link Opcodes}).
* @param name the field's name.
* @param descriptor the field's descriptor (see {@link Type}).
* @param signature the field's signature. May be {@literal null}.
* @param constantValue the field's constant value. May be {@literal null}.
*/
FieldWriter(final ClassWriter cw, final int access, final String name,
final String desc, final String signature, final Object value) {
super(Opcodes.ASM6);
if (cw.firstField == null) {
cw.firstField = this;
} else {
cw.lastField.fv = this;
}
cw.lastField = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
FieldWriter(
final SymbolTable symbolTable,
final int access,
final String name,
final String descriptor,
final String signature,
final Object constantValue) {
super(Opcodes.ASM7);
this.symbolTable = symbolTable;
this.accessFlags = access;
this.nameIndex = symbolTable.addConstantUtf8(name);
this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
if (signature != null) {
this.signature = cw.newUTF8(signature);
this.signatureIndex = symbolTable.addConstantUtf8(signature);
}
if (value != null) {
this.value = cw.newConstItem(value).index;
if (constantValue != null) {
this.constantValueIndex = symbolTable.addConstant(constantValue).index;
}
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
ByteVector bv = new ByteVector();
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2);
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) {
aw.next = anns;
anns = aw;
return lastRuntimeVisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
} else {
aw.next = ianns;
ianns = aw;
return lastRuntimeInvisibleAnnotation =
new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
}
return aw;
}
@Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef,
final TypePath typePath, final String desc, final boolean visible) {
ByteVector bv = new ByteVector();
// write target_type and target_info
AnnotationWriter.putTarget(typeRef, typePath, bv);
// write type, and reserve space for values count
bv.putShort(cw.newUTF8(desc)).putShort(0);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv,
bv.length - 2);
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) {
aw.next = tanns;
tanns = aw;
return lastRuntimeVisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
} else {
aw.next = itanns;
itanns = aw;
return lastRuntimeInvisibleTypeAnnotation =
new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
}
return aw;
}
@Override
public void visitAttribute(final Attribute attr) {
attr.next = attrs;
attrs = attr;
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 this field.
* Returns the size of the field_info JVMS structure generated by this FieldWriter. Also adds the
* names of the attributes of this field in the constant pool.
*
* @return the size of this field.
* @return the size in bytes of the field_info JVMS structure.
*/
int getSize() {
int computeFieldInfoSize() {
// The access_flags, name_index, descriptor_index and attributes_count fields use 8 bytes.
int size = 8;
if (value != 0) {
cw.newUTF8("ConstantValue");
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
if (constantValueIndex != 0) {
// ConstantValue attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
size += 8;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
cw.newUTF8("Synthetic");
// 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 ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated");
size += 6;
}
if (signature != 0) {
cw.newUTF8("Signature");
if (signatureIndex != 0) {
// Signature attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.SIGNATURE);
size += 8;
}
if (anns != null) {
cw.newUTF8("RuntimeVisibleAnnotations");
size += 8 + anns.getSize();
// 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 (ianns != null) {
cw.newUTF8("RuntimeInvisibleAnnotations");
size += 8 + ianns.getSize();
if (lastRuntimeVisibleAnnotation != null) {
size +=
lastRuntimeVisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
}
if (tanns != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations");
size += 8 + tanns.getSize();
if (lastRuntimeInvisibleAnnotation != null) {
size +=
lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
}
if (itanns != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations");
size += 8 + itanns.getSize();
if (lastRuntimeVisibleTypeAnnotation != null) {
size +=
lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
}
if (attrs != null) {
size += attrs.getSize(cw, null, 0, -1, -1);
if (lastRuntimeInvisibleTypeAnnotation != null) {
size +=
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
}
if (firstAttribute != null) {
size += firstAttribute.computeAttributesSize(symbolTable);
}
return size;
}
/**
* Puts the content of this field into the given byte vector.
* Puts the content of the field_info JVMS structure generated by this FieldWriter into the given
* ByteVector.
*
* @param out
* where the content of this field must be put.
* @param output where the field_info structure must be put.
*/
void put(final ByteVector out) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC;
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR);
out.putShort(access & ~mask).putShort(name).putShort(desc);
int attributeCount = 0;
if (value != 0) {
++attributeCount;
void putFieldInfo(final ByteVector output) {
boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
// Put the access_flags, name_index and descriptor_index fields.
int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
output.putShort(accessFlags & ~mask).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 (constantValueIndex != 0) {
++attributesCount;
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount;
if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
++attributesCount;
}
if (signatureIndex != 0) {
++attributesCount;
}
if ((accessFlags & Opcodes.ACC_DEPRECATED) != 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);
// Put the field_info attributes.
// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
if (constantValueIndex != 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE))
.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);
}
if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, output);
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount;
}
if (signature != 0) {
++attributeCount;
}
if (anns != null) {
++attributeCount;
}
if (ianns != null) {
++attributeCount;
}
if (tanns != null) {
++attributeCount;
}
if (itanns != null) {
++attributeCount;
}
if (attrs != null) {
attributeCount += attrs.getCount();
}
out.putShort(attributeCount);
if (value != 0) {
out.putShort(cw.newUTF8("ConstantValue"));
out.putInt(2).putShort(value);
}
if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0);
}
if (signature != 0) {
out.putShort(cw.newUTF8("Signature"));
out.putInt(2).putShort(signature);
}
if (anns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations"));
anns.put(out);
}
if (ianns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations"));
ianns.put(out);
}
if (tanns != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations"));
tanns.put(out);
}
if (itanns != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations"));
itanns.put(out);
}
if (attrs != null) {
attrs.put(cw, null, 0, -1, -1, out);
}
/**
* Collects the attributes of this field into the given set of attribute prototypes.
*
* @param attributePrototypes a set of attribute prototypes.
*/
final void collectAttributePrototypes(final Attribute.Set attributePrototypes) {
attributePrototypes.addAttributes(firstAttribute);
}
}

View file

@ -56,7 +56,6 @@
* 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;
/**
@ -68,117 +67,88 @@ package jdk.internal.org.objectweb.asm;
public final class Handle {
/**
* The kind of field or method designated by this Handle. Should be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
*/
final int tag;
private final int tag;
/**
* The internal name of the class that owns the field or method designated
* by this handle.
*/
final String owner;
/** The internal name of the class that owns the field or method designated by this handle. */
private final String owner;
/**
* The name of the field or method designated by this handle.
*/
final String name;
/** The name of the field or method designated by this handle. */
private final String name;
/**
* The descriptor of the field or method designated by this handle.
*/
final String desc;
/** The descriptor of the field or method designated by this handle. */
private final String descriptor;
/**
* Indicate if the owner is an interface or not.
*/
final boolean itf;
/** Whether the owner is an interface or not. */
private final boolean isInterface;
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* @param tag the kind of field or method designated by this Handle. Must be {@link
* Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
* Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
*
* @deprecated this constructor has been superseded
* by {@link #Handle(int, String, String, String, boolean)}.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @deprecated this constructor has been superseded by {@link #Handle(int, String, String, String,
* boolean)}.
*/
@Deprecated
public Handle(int tag, String owner, String name, String desc) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE);
public Handle(final int tag, final String owner, final String name, final String descriptor) {
this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
}
/**
* Constructs a new field or method handle.
*
* @param tag
* the kind of field or method designated by this Handle. Must be
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL},
* {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @param owner
* the internal name of the class that owns the field or method
* designated by this handle.
* @param name
* the name of the field or method designated by this handle.
* @param desc
* the descriptor of the field or method designated by this
* @param tag the kind of field or method designated by this Handle. Must be {@link
* Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
* Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* Opcodes#H_INVOKEINTERFACE}.
* @param owner the internal name of the class that owns the field or method designated by this
* handle.
* @param itf
* true if the owner is an interface.
* @param name the name of the field or method designated by this handle.
* @param descriptor the descriptor of the field or method designated by this handle.
* @param isInterface whether the owner is an interface or not.
*/
public Handle(int tag, String owner, String name, String desc, boolean itf) {
public Handle(
final int tag,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
this.tag = tag;
this.owner = owner;
this.name = name;
this.desc = desc;
this.itf = itf;
this.descriptor = descriptor;
this.isInterface = isInterface;
}
/**
* Returns the kind of field or method designated by this handle.
*
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or
* {@link Opcodes#H_INVOKEINTERFACE}.
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
* {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
* Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
* Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
*/
public int getTag() {
return tag;
}
/**
* Returns the internal name of the class that owns the field or method
* designated by this handle.
* Returns the internal name of the class that owns the field or method designated by this handle.
*
* @return the internal name of the class that owns the field or method
* designated by this handle.
* @return the internal name of the class that owns the field or method designated by this handle.
*/
public String getOwner() {
return owner;
@ -199,53 +169,51 @@ public final class Handle {
* @return the descriptor of the field or method designated by this handle.
*/
public String getDesc() {
return desc;
return descriptor;
}
/**
* Returns true if the owner of the field or method designated
* by this handle is an interface.
* Returns true if the owner of the field or method designated by this handle is an interface.
*
* @return true if the owner of the field or method designated
* by this handle is an interface.
* @return true if the owner of the field or method designated by this handle is an interface.
*/
public boolean isInterface() {
return itf;
return isInterface;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (!(obj instanceof Handle)) {
if (!(object instanceof Handle)) {
return false;
}
Handle h = (Handle) obj;
return tag == h.tag && itf == h.itf && owner.equals(h.owner)
&& name.equals(h.name) && desc.equals(h.desc);
Handle handle = (Handle) object;
return tag == handle.tag
&& isInterface == handle.isInterface
&& owner.equals(handle.owner)
&& name.equals(handle.name)
&& descriptor.equals(handle.descriptor);
}
@Override
public int hashCode() {
return tag + (itf? 64: 0) + owner.hashCode() * name.hashCode() * desc.hashCode();
return tag
+ (isInterface ? 64 : 0)
+ owner.hashCode() * name.hashCode() * descriptor.hashCode();
}
/**
* Returns the textual representation of this handle. The textual
* representation is:
* Returns the textual representation of this handle. The textual representation is:
*
* <pre>
* for a reference to a class:
* owner '.' name desc ' ' '(' tag ')'
* for a reference to an interface:
* owner '.' name desc ' ' '(' tag ' ' itf ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
* <ul>
* <li>for a reference to a class: owner "." name descriptor " (" tag ")",
* <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
* </ul>
*/
@Override
public String toString() {
return owner + '.' + name + desc + " (" + tag + (itf? " itf": "") + ')';
return owner + '.' + name + descriptor + " (" + tag + (isInterface ? " itf" : "") + ')';
}
}

View file

@ -59,92 +59,171 @@
package jdk.internal.org.objectweb.asm;
/**
* Information about an exception handler block.
* Information about an exception handler. Corresponds to an element of the exception_table array of
* a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances
* can be chained together, with their {@link #nextHandler} field, to describe a full JVMS
* exception_table array.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS
* 4.7.3</a>
* @author Eric Bruneton
*/
class Handler {
final class Handler {
/**
* Beginning of the exception handler's scope (inclusive).
* The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the
* exception handler's scope (inclusive).
*/
Label start;
final Label startPc;
/**
* End of the exception handler's scope (exclusive).
* The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception
* handler's scope (exclusive).
*/
Label end;
final Label endPc;
/**
* Beginning of the exception handler's code.
* The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the
* exception handler's code.
*/
Label handler;
final Label handlerPc;
/**
* Internal name of the type of exceptions handled by this handler, or
* <tt>null</tt> to catch any exceptions.
* The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
* internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions.
*/
String desc;
final int catchType;
/**
* Constant pool index of the internal name of the type of exceptions
* handled by this handler, or 0 to catch any exceptions.
* The internal name of the type of exceptions handled by this handler, or {@literal null} to
* catch any exceptions.
*/
int type;
final String catchTypeDescriptor;
/** The next exception handler. */
Handler nextHandler;
/**
* Next exception handler block info.
*/
Handler next;
/**
* Removes the range between start and end from the given exception
* handlers.
* Constructs a new Handler.
*
* @param h
* an exception handler list.
* @param start
* the start of the range to be removed.
* @param end
* the end of the range to be removed. Maybe null.
* @param startPc the start_pc field of this JVMS exception_table entry.
* @param endPc the end_pc field of this JVMS exception_table entry.
* @param handlerPc the handler_pc field of this JVMS exception_table entry.
* @param catchType The catch_type field of this JVMS exception_table entry.
* @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler,
* or {@literal null} to catch any exceptions.
*/
Handler(
final Label startPc,
final Label endPc,
final Label handlerPc,
final int catchType,
final String catchTypeDescriptor) {
this.startPc = startPc;
this.endPc = endPc;
this.handlerPc = handlerPc;
this.catchType = catchType;
this.catchTypeDescriptor = catchTypeDescriptor;
}
/**
* Constructs a new Handler from the given one, with a different scope.
*
* @param handler an existing Handler.
* @param startPc the start_pc field of this JVMS exception_table entry.
* @param endPc the end_pc field of this JVMS exception_table entry.
*/
Handler(final Handler handler, final Label startPc, final Label endPc) {
this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
this.nextHandler = handler.nextHandler;
}
/**
* Removes the range between start and end from the Handler list that begins with the given
* element.
*
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
* @param start the start of the range to be removed.
* @param end the end of the range to be removed. Maybe {@literal null}.
* @return the exception handler list with the start-end range removed.
*/
static Handler remove(Handler h, Label start, Label end) {
if (h == null) {
static Handler removeRange(final Handler firstHandler, final Label start, final Label end) {
if (firstHandler == null) {
return null;
} else {
h.next = remove(h.next, start, end);
firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
}
int hstart = h.start.position;
int hend = h.end.position;
int s = start.position;
int e = end == null ? Integer.MAX_VALUE : end.position;
// if [hstart,hend[ and [s,e[ intervals intersect...
if (s < hend && e > hstart) {
if (s <= hstart) {
if (e >= hend) {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
int handlerStart = firstHandler.startPc.bytecodeOffset;
int handlerEnd = firstHandler.endPc.bytecodeOffset;
int rangeStart = start.bytecodeOffset;
int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset;
// Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
return firstHandler;
}
if (rangeStart <= handlerStart) {
if (rangeEnd >= handlerEnd) {
// If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
return firstHandler.nextHandler;
} else {
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
return new Handler(firstHandler, end, firstHandler.endPc);
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else if (rangeEnd >= handlerEnd) {
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
return new Handler(firstHandler, firstHandler.startPc, start);
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
g.start = end;
g.end = h.end;
g.handler = h.handler;
g.desc = h.desc;
g.type = h.type;
g.next = h.next;
h.end = start;
h.next = g;
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
// [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
return new Handler(firstHandler, firstHandler.startPc, start);
}
}
return h;
/**
* Returns the number of elements of the Handler list that begins with the given element.
*
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
* @return the number of elements of the Handler list that begins with 'handler'.
*/
static int getExceptionTableLength(final Handler firstHandler) {
int length = 0;
Handler handler = firstHandler;
while (handler != null) {
length++;
handler = handler.nextHandler;
}
return length;
}
/**
* Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that
* begins with the given element. <i>This includes the exception_table_length field.</i>
*
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
* @return the size in bytes of the exception_table_length and exception_table structures.
*/
static int getExceptionTableSize(final Handler firstHandler) {
return 2 + 8 * getExceptionTableLength(firstHandler);
}
/**
* Puts the JVMS exception_table corresponding to the Handler list that begins with the given
* element. <i>This includes the exception_table_length field.</i>
*
* @param firstHandler the beginning of a Handler list. May be {@literal null}.
* @param output where the exception_table_length and exception_table structures must be put.
*/
static void putExceptionTable(final Handler firstHandler, final ByteVector output) {
output.putShort(getExceptionTableLength(firstHandler));
Handler handler = firstHandler;
while (handler != null) {
output
.putShort(handler.startPc.bytecodeOffset)
.putShort(handler.endPc.bytecodeOffset)
.putShort(handler.handlerPc.bytecodeOffset)
.putShort(handler.catchType);
handler = handler.nextHandler;
}
}
}

View file

@ -1,347 +0,0 @@
/*
* 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 constant pool item. Constant pool items can be created with the 'newXXX'
* methods in the {@link ClassWriter} class.
*
* @author Eric Bruneton
*/
final class Item {
/**
* Index of this item in the constant pool.
*/
int index;
/**
* Type of this constant pool item. A single class is used to represent all
* constant pool item types, in order to minimize the bytecode size of this
* package. The value of this field is one of {@link ClassWriter#INT},
* {@link ClassWriter#LONG}, {@link ClassWriter#FLOAT},
* {@link ClassWriter#DOUBLE}, {@link ClassWriter#UTF8},
* {@link ClassWriter#STR}, {@link ClassWriter#CLASS},
* {@link ClassWriter#NAME_TYPE}, {@link ClassWriter#FIELD},
* {@link ClassWriter#METH}, {@link ClassWriter#IMETH},
* {@link ClassWriter#MODULE}, {@link ClassWriter#PACKAGE},
* {@link ClassWriter#MTYPE}, {@link ClassWriter#INDY}.
*
* MethodHandle constant 9 variations are stored using a range of 9 values
* from {@link ClassWriter#HANDLE_BASE} + 1 to
* {@link ClassWriter#HANDLE_BASE} + 9.
*
* Special Item types are used for Items that are stored in the ClassWriter
* {@link ClassWriter#typeTable}, instead of the constant pool, in order to
* avoid clashes with normal constant pool items in the ClassWriter constant
* pool's hash table. These special item types are
* {@link ClassWriter#TYPE_NORMAL}, {@link ClassWriter#TYPE_UNINIT} and
* {@link ClassWriter#TYPE_MERGED}.
*/
int type;
/**
* Value of this item, for an integer item.
*/
int intVal;
/**
* Value of this item, for a long item.
*/
long longVal;
/**
* First part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal1;
/**
* Second part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal2;
/**
* Third part of the value of this item, for items that do not hold a
* primitive value.
*/
String strVal3;
/**
* The hash code value of this constant pool item.
*/
int hashCode;
/**
* Link to another constant pool item, used for collision lists in the
* constant pool's hash table.
*/
Item next;
/**
* Constructs an uninitialized {@link Item}.
*/
Item() {
}
/**
* Constructs an uninitialized {@link Item} for constant pool element at
* given position.
*
* @param index
* index of the item to be constructed.
*/
Item(final int index) {
this.index = index;
}
/**
* Constructs a copy of the given item.
*
* @param index
* index of the item to be constructed.
* @param i
* the item that must be copied into the item to be constructed.
*/
Item(final int index, final Item i) {
this.index = index;
type = i.type;
intVal = i.intVal;
longVal = i.longVal;
strVal1 = i.strVal1;
strVal2 = i.strVal2;
strVal3 = i.strVal3;
hashCode = i.hashCode;
}
/**
* Sets this item to an integer item.
*
* @param intVal
* the value of this item.
*/
void set(final int intVal) {
this.type = ClassWriter.INT;
this.intVal = intVal;
this.hashCode = 0x7FFFFFFF & (type + intVal);
}
/**
* Sets this item to a long item.
*
* @param longVal
* the value of this item.
*/
void set(final long longVal) {
this.type = ClassWriter.LONG;
this.longVal = longVal;
this.hashCode = 0x7FFFFFFF & (type + (int) longVal);
}
/**
* Sets this item to a float item.
*
* @param floatVal
* the value of this item.
*/
void set(final float floatVal) {
this.type = ClassWriter.FLOAT;
this.intVal = Float.floatToRawIntBits(floatVal);
this.hashCode = 0x7FFFFFFF & (type + (int) floatVal);
}
/**
* Sets this item to a double item.
*
* @param doubleVal
* the value of this item.
*/
void set(final double doubleVal) {
this.type = ClassWriter.DOUBLE;
this.longVal = Double.doubleToRawLongBits(doubleVal);
this.hashCode = 0x7FFFFFFF & (type + (int) doubleVal);
}
/**
* Sets this item to an item that do not hold a primitive value.
*
* @param type
* the type of this item.
* @param strVal1
* first part of the value of this item.
* @param strVal2
* second part of the value of this item.
* @param strVal3
* third part of the value of this item.
*/
@SuppressWarnings("fallthrough")
void set(final int type, final String strVal1, final String strVal2,
final String strVal3) {
this.type = type;
this.strVal1 = strVal1;
this.strVal2 = strVal2;
this.strVal3 = strVal3;
switch (type) {
case ClassWriter.CLASS:
this.intVal = 0; // intVal of a class must be zero, see visitInnerClass
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.MTYPE:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.TYPE_NORMAL:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode());
return;
case ClassWriter.NAME_TYPE: {
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode());
return;
}
// ClassWriter.FIELD:
// ClassWriter.METH:
// ClassWriter.IMETH:
// ClassWriter.HANDLE_BASE + 1..9
default:
hashCode = 0x7FFFFFFF & (type + strVal1.hashCode()
* strVal2.hashCode() * strVal3.hashCode());
}
}
/**
* Sets the item to an InvokeDynamic item.
*
* @param name
* invokedynamic's name.
* @param desc
* invokedynamic's desc.
* @param bsmIndex
* zero based index into the class attribute BootrapMethods.
*/
void set(String name, String desc, int bsmIndex) {
this.type = ClassWriter.INDY;
this.longVal = bsmIndex;
this.strVal1 = name;
this.strVal2 = desc;
this.hashCode = 0x7FFFFFFF & (ClassWriter.INDY + bsmIndex
* strVal1.hashCode() * strVal2.hashCode());
}
/**
* Sets the item to a BootstrapMethod item.
*
* @param position
* position in byte in the class attribute BootrapMethods.
* @param hashCode
* hashcode of the item. This hashcode is processed from the
* hashcode of the bootstrap method and the hashcode of all
* bootstrap arguments.
*/
void set(int position, int hashCode) {
this.type = ClassWriter.BSM;
this.intVal = position;
this.hashCode = hashCode;
}
/**
* Indicates if the given item is equal to this one. <i>This method assumes
* that the two items have the same {@link #type}</i>.
*
* @param i
* the item to be compared to this one. Both items must have the
* same {@link #type}.
* @return <tt>true</tt> if the given item if equal to this one,
* <tt>false</tt> otherwise.
*/
boolean isEqualTo(final Item i) {
switch (type) {
case ClassWriter.UTF8:
case ClassWriter.STR:
case ClassWriter.CLASS:
case ClassWriter.MODULE:
case ClassWriter.PACKAGE:
case ClassWriter.MTYPE:
case ClassWriter.TYPE_NORMAL:
return i.strVal1.equals(strVal1);
case ClassWriter.TYPE_MERGED:
case ClassWriter.LONG:
case ClassWriter.DOUBLE:
return i.longVal == longVal;
case ClassWriter.INT:
case ClassWriter.FLOAT:
return i.intVal == intVal;
case ClassWriter.TYPE_UNINIT:
return i.intVal == intVal && i.strVal1.equals(strVal1);
case ClassWriter.NAME_TYPE:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2);
case ClassWriter.INDY: {
return i.longVal == longVal && i.strVal1.equals(strVal1)
&& i.strVal2.equals(strVal2);
}
// case ClassWriter.FIELD:
// case ClassWriter.METH:
// case ClassWriter.IMETH:
// case ClassWriter.HANDLE_BASE + 1..9
default:
return i.strVal1.equals(strVal1) && i.strVal2.equals(strVal2)
&& i.strVal3.equals(strVal3);
}
}
}

View file

@ -59,10 +59,9 @@
package jdk.internal.org.objectweb.asm;
/**
* A label represents a position in the bytecode of a method. Labels are used
* for jump, goto, and switch instructions, and for try catch blocks. A label
* designates the <i>instruction</i> that is just after. Note however that there
* can be other elements between a label and the instruction it designates (such
* A position in the bytecode of a method. Labels are used for jump, goto, and switch instructions,
* and for try catch blocks. A label designates the <i>instruction</i> that is just after. Note
* however that there can be other elements between a label and the instruction it designates (such
* as other labels, stack map frames, line numbers, etc.).
*
* @author Eric Bruneton
@ -70,516 +69,576 @@ package jdk.internal.org.objectweb.asm;
public class Label {
/**
* Indicates if this label is only used for debug attributes. Such a label
* is not the start of a basic block, the target of a jump instruction, or
* an exception handler. It can be safely ignored in control flow graph
* analysis algorithms (for optimization purposes).
* A flag indicating that a label is only used for debug attributes. Such a label is not the start
* of a basic block, the target of a jump instruction, or an exception handler. It can be safely
* ignored in control flow graph analysis algorithms (for optimization purposes).
*/
static final int DEBUG = 1;
static final int FLAG_DEBUG_ONLY = 1;
/**
* Indicates if the position of this label is known.
* A flag indicating that a label is the target of a jump instruction, or the start of an
* exception handler.
*/
static final int RESOLVED = 2;
static final int FLAG_JUMP_TARGET = 2;
/** A flag indicating that the bytecode offset of a label is known. */
static final int FLAG_RESOLVED = 4;
/** A flag indicating that a label corresponds to a reachable basic block. */
static final int FLAG_REACHABLE = 8;
/**
* Indicates if this label has been updated, after instruction resizing.
* A flag indicating that the basic block corresponding to a label ends with a subroutine call. By
* construction in {@link MethodWriter#visitJumpInsn}, labels with this flag set have at least two
* outgoing edges:
*
* <ul>
* <li>the first one corresponds to the instruction that follows the jsr instruction in the
* bytecode, i.e. where execution continues when it returns from the jsr call. This is a
* virtual control flow edge, since execution never goes directly from the jsr to the next
* instruction. Instead, it goes to the subroutine and eventually returns to the instruction
* following the jsr. This virtual edge is used to compute the real outgoing edges of the
* basic blocks ending with a ret instruction, in {@link #addSubroutineRetSuccessors}.
* <li>the second one corresponds to the target of the jsr instruction,
* </ul>
*/
static final int RESIZED = 4;
static final int FLAG_SUBROUTINE_CALLER = 16;
/**
* Indicates if this basic block has been pushed in the basic block stack.
* See {@link MethodWriter#visitMaxs visitMaxs}.
* A flag indicating that the basic block corresponding to a label is the start of a subroutine.
*/
static final int PUSHED = 8;
static final int FLAG_SUBROUTINE_START = 32;
/** A flag indicating that the basic block corresponding to a label is the end of a subroutine. */
static final int FLAG_SUBROUTINE_END = 64;
/**
* Indicates if this label is the target of a jump instruction, or the start
* of an exception handler.
* The number of elements to add to the {@link #otherLineNumbers} array when it needs to be
* resized to store a new source line number.
*/
static final int TARGET = 16;
static final int LINE_NUMBERS_CAPACITY_INCREMENT = 4;
/**
* Indicates if a stack map frame must be stored for this label.
* The number of elements to add to the {@link #forwardReferences} array when it needs to be
* resized to store a new forward reference.
*/
static final int STORE = 32;
static final int FORWARD_REFERENCES_CAPACITY_INCREMENT = 6;
/**
* Indicates if this label corresponds to a reachable basic block.
* The bit mask to extract the type of a forward reference to this label. The extracted type is
* either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link #FORWARD_REFERENCE_TYPE_WIDE}.
*
* @see #forwardReferences
*/
static final int REACHABLE = 64;
static final int FORWARD_REFERENCE_TYPE_MASK = 0xF0000000;
/**
* Indicates if this basic block ends with a JSR instruction.
* The type of forward references stored with two bytes in the bytecode. This is the case, for
* instance, of a forward reference from an ifnull instruction.
*/
static final int JSR = 128;
static final int FORWARD_REFERENCE_TYPE_SHORT = 0x10000000;
/**
* Indicates if this basic block ends with a RET instruction.
* The type of forward references stored in four bytes in the bytecode. This is the case, for
* instance, of a forward reference from a lookupswitch instruction.
*/
static final int RET = 256;
static final int FORWARD_REFERENCE_TYPE_WIDE = 0x20000000;
/**
* Indicates if this basic block is the start of a subroutine.
* The bit mask to extract the 'handle' of a forward reference to this label. The extracted handle
* is the bytecode offset where the forward reference value is stored (using either 2 or 4 bytes,
* as indicated by the {@link #FORWARD_REFERENCE_TYPE_MASK}).
*
* @see #forwardReferences
*/
static final int SUBROUTINE = 512;
static final int FORWARD_REFERENCE_HANDLE_MASK = 0x0FFFFFFF;
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(null, ...) call.
* A sentinel element used to indicate the end of a list of labels.
*
* @see #nextListElement
*/
static final int VISITED = 1024;
static final Label EMPTY_LIST = new Label();
/**
* Indicates if this subroutine basic block has been visited by a
* visitSubroutine(!null, ...) call.
*/
static final int VISITED2 = 2048;
/**
* Field used to associate user information to a label. Warning: this field
* is used by the ASM tree package. In order to use it with the ASM tree
* package you must override the
* {@link jdk.internal.org.objectweb.asm.tree.MethodNode#getLabelNode} method.
* A user managed state associated with this label. Warning: this field is used by the ASM tree
* package. In order to use it with the ASM tree package you must override the getLabelNode method
* in MethodNode.
*/
public Object info;
/**
* Flags that indicate the status of this label.
* The type and status of this label or its corresponding basic block. Must be zero or more of
* {@link #FLAG_DEBUG_ONLY}, {@link #FLAG_JUMP_TARGET}, {@link #FLAG_RESOLVED}, {@link
* #FLAG_REACHABLE}, {@link #FLAG_SUBROUTINE_CALLER}, {@link #FLAG_SUBROUTINE_START}, {@link
* #FLAG_SUBROUTINE_END}.
*/
short flags;
/**
* The source line number corresponding to this label, or 0. If there are several source line
* numbers corresponding to this label, the first one is stored in this field, and the remaining
* ones are stored in {@link #otherLineNumbers}.
*/
private short lineNumber;
/**
* The source line numbers corresponding to this label, in addition to {@link #lineNumber}, or
* null. The first element of this array is the number n of source line numbers it contains, which
* are stored between indices 1 and n (inclusive).
*/
private int[] otherLineNumbers;
/**
* The offset of this label in the bytecode of its method, in bytes. This value is set if and only
* if the {@link #FLAG_RESOLVED} flag is set.
*/
int bytecodeOffset;
/**
* The forward references to this label. The first element is the number of forward references,
* times 2 (this corresponds to the index of the last element actually used in this array). Then,
* each forward reference is described with two consecutive integers noted
* 'sourceInsnBytecodeOffset' and 'reference':
*
* @see #DEBUG
* @see #RESOLVED
* @see #RESIZED
* @see #PUSHED
* @see #TARGET
* @see #STORE
* @see #REACHABLE
* @see #JSR
* @see #RET
*/
int status;
/**
* The line number corresponding to this label, if known. If there are
* several lines, each line is stored in a separate label, all linked via
* their next field (these links are created in ClassReader and removed just
* before visitLabel is called, so that this does not impact the rest of the
* code).
*/
int line;
/**
* The position of this label in the code, if known.
*/
int position;
/**
* Number of forward references to this label, times two.
*/
private int referenceCount;
/**
* Informations about forward references. Each forward reference is
* described by two consecutive integers in this array: the first one is the
* position of the first byte of the bytecode instruction that contains the
* forward reference, while the second is the position of the first byte of
* the forward reference itself. In fact the sign of the first integer
* indicates if this reference uses 2 or 4 bytes, and its absolute value
* gives the position of the bytecode instruction. This array is also used
* as a bitset to store the subroutines to which a basic block belongs. This
* information is needed in {@linked MethodWriter#visitMaxs}, after all
* forward references have been resolved. Hence the same array can be used
* for both purposes without problems.
*/
private int[] srcAndRefPositions;
// ------------------------------------------------------------------------
/*
* Fields for the control flow and data flow graph analysis algorithms (used
* to compute the maximum stack size or the stack map frames). A control
* flow graph contains one node per "basic block", and one edge per "jump"
* from one basic block to another. Each node (i.e., each basic block) is
* represented by the Label object that corresponds to the first instruction
* of this basic block. Each node also stores the list of its successors in
* the graph, as a linked list of Edge objects.
* <ul>
* <li>'sourceInsnBytecodeOffset' is the bytecode offset of the instruction that contains the
* forward reference,
* <li>'reference' contains the type and the offset in the bytecode where the forward reference
* value must be stored, which can be extracted with {@link #FORWARD_REFERENCE_TYPE_MASK}
* and {@link #FORWARD_REFERENCE_HANDLE_MASK}.
* </ul>
*
* The control flow analysis algorithms used to compute the maximum stack
* size or the stack map frames are similar and use two steps. The first
* step, during the visit of each instruction, builds information about the
* state of the local variables and the operand stack at the end of each
* basic block, called the "output frame", <i>relatively</i> to the frame
* state at the beginning of the basic block, which is called the "input
* frame", and which is <i>unknown</i> during this step. The second step, in
* {@link MethodWriter#visitMaxs}, is a fix point algorithm that computes
* information about the input frame of each basic block, from the input
* state of the first basic block (known from the method signature), and by
* the using the previously computed relative output frames.
*
* The algorithm used to compute the maximum stack size only computes the
* relative output and absolute input stack heights, while the algorithm
* used to compute stack map frames computes relative output frames and
* absolute input frames.
* <p>For instance, for an ifnull instruction at bytecode offset x, 'sourceInsnBytecodeOffset' is
* equal to x, and 'reference' is of type {@link #FORWARD_REFERENCE_TYPE_SHORT} with value x + 1
* (because the ifnull instruction uses a 2 bytes bytecode offset operand stored one byte after
* the start of the instruction itself). For the default case of a lookupswitch instruction at
* bytecode offset x, 'sourceInsnBytecodeOffset' is equal to x, and 'reference' is of type {@link
* #FORWARD_REFERENCE_TYPE_WIDE} with value between x + 1 and x + 4 (because the lookupswitch
* instruction uses a 4 bytes bytecode offset operand stored one to four bytes after the start of
* the instruction itself).
*/
private int[] forwardReferences;
// -----------------------------------------------------------------------------------------------
// Fields for the control flow and data flow graph analysis algorithms (used to compute the
// maximum stack size or the stack map frames). A control flow graph contains one node per "basic
// block", and one edge per "jump" from one basic block to another. Each node (i.e., each basic
// block) is represented with the Label object that corresponds to the first instruction of this
// basic block. Each node also stores the list of its successors in the graph, as a linked list of
// Edge objects.
//
// The control flow analysis algorithms used to compute the maximum stack size or the stack map
// frames are similar and use two steps. The first step, during the visit of each instruction,
// builds information about the state of the local variables and the operand stack at the end of
// each basic block, called the "output frame", <i>relatively</i> to the frame state at the
// beginning of the basic block, which is called the "input frame", and which is <i>unknown</i>
// during this step. The second step, in {@link MethodWriter#computeAllFrames} and {@link
// MethodWriter#computeMaxStackAndLocal}, is a fix point algorithm
// that computes information about the input frame of each basic block, from the input state of
// the first basic block (known from the method signature), and by the using the previously
// computed relative output frames.
//
// The algorithm used to compute the maximum stack size only computes the relative output and
// absolute input stack heights, while the algorithm used to compute stack map frames computes
// relative output frames and absolute input frames.
/**
* Start of the output stack relatively to the input stack. The exact
* semantics of this field depends on the algorithm that is used.
*
* When only the maximum stack size is computed, this field is the number of
* elements in the input stack.
*
* When the stack map frames are completely computed, this field is the
* offset of the first output stack element relatively to the top of the
* input stack. This offset is always negative or null. A null offset means
* that the output stack must be appended to the input stack. A -n offset
* means that the first n output stack elements must replace the top n input
* stack elements, and that the other elements must be appended to the input
* stack.
* The number of elements in the input stack of the basic block corresponding to this label. This
* field is computed in {@link MethodWriter#computeMaxStackAndLocal}.
*/
int inputStackTop;
short inputStackSize;
/**
* Maximum height reached by the output stack, relatively to the top of the
* input stack. This maximum is always positive or null.
* The number of elements in the output stack, at the end of the basic block corresponding to this
* label. This field is only computed for basic blocks that end with a RET instruction.
*/
int outputStackMax;
short outputStackSize;
/**
* Information about the input and output stack map frames of this basic
* block. This field is only used when {@link ClassWriter#COMPUTE_FRAMES}
* option is used.
* 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.
*/
short outputStackMax;
/**
* The id of the subroutine to which this basic block belongs, or 0. If the basic block belongs to
* several subroutines, this is the id of the "oldest" subroutine that contains it (with the
* convention that a subroutine calling another one is "older" than the callee). This field is
* computed in {@link MethodWriter#computeMaxStackAndLocal}, if the method contains JSR
* instructions.
*/
short subroutineId;
/**
* The input and output stack map frames of the basic block corresponding to this label. This
* field is only used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} or {@link
* MethodWriter#COMPUTE_INSERTED_FRAMES} option is used.
*/
Frame frame;
/**
* The successor of this label, in the order they are visited. This linked
* list does not include labels used for debug info only. If
* {@link ClassWriter#COMPUTE_FRAMES} option is used then, in addition, it
* does not contain successive labels that denote the same bytecode position
* (in this case only the first label appears in this list).
* The successor of this label, in the order they are visited in {@link MethodVisitor#visitLabel}.
* This linked list does not include labels used for debug info only. If the {@link
* MethodWriter#COMPUTE_ALL_FRAMES} or {@link MethodWriter#COMPUTE_INSERTED_FRAMES} option is used
* then it does not contain either successive labels that denote the same bytecode offset (in this
* case only the first label appears in this list).
*/
Label successor;
Label nextBasicBlock;
/**
* The successors of this node in the control flow graph. These successors
* are stored in a linked list of {@link Edge Edge} objects, linked to each
* other by their {@link Edge#next} field.
* The outgoing edges of the basic block corresponding to this label, in the control flow graph of
* its method. These edges are stored in a linked list of {@link Edge} objects, linked to each
* other by their {@link Edge#nextEdge} field.
*/
Edge successors;
Edge outgoingEdges;
/**
* The next basic block in the basic block stack. This stack is used in the
* main loop of the fix point algorithm used in the second step of the
* control flow analysis algorithms. It is also used in
* {@link #visitSubroutine} to avoid using a recursive method, and in
* ClassReader to temporarily store multiple source lines for a label.
* 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).
*
* @see MethodWriter#visitMaxs
* <p>List of labels are used in {@link MethodWriter#computeAllFrames} and {@link
* MethodWriter#computeMaxStackAndLocal} to compute stack map frames and the maximum stack size,
* respectively, as well as in {@link #markSubroutine} and {@link #addSubroutineRetSuccessors} to
* compute the basic blocks belonging to subroutines and their outgoing edges. Outside of these
* methods, this field should be null (this property is a precondition and a postcondition of
* these methods).
*/
Label next;
Label nextListElement;
// ------------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Constructor and accessors
// -----------------------------------------------------------------------------------------------
/**
* Constructs a new label.
*/
/** Constructs a new label. */
public Label() {
// Nothing to do.
}
// ------------------------------------------------------------------------
// Methods to compute offsets and to manage forward references
// ------------------------------------------------------------------------
/**
* Returns the offset corresponding to this label. This offset is computed
* from the start of the method's bytecode. <i>This method is intended for
* {@link Attribute} sub classes, and is normally not needed by class
* generators or adapters.</i>
* Returns the bytecode offset corresponding to this label. This offset is computed from the start
* of the method's bytecode. <i>This method is intended for {@link Attribute} sub classes, and is
* normally not needed by class generators or adapters.</i>
*
* @return the offset corresponding to this label.
* @throws IllegalStateException
* if this label is not resolved yet.
* @return the bytecode offset corresponding to this label.
* @throws IllegalStateException if this label is not resolved yet.
*/
public int getOffset() {
if ((status & RESOLVED) == 0) {
throw new IllegalStateException(
"Label offset position has not been resolved yet");
if ((flags & FLAG_RESOLVED) == 0) {
throw new IllegalStateException("Label offset position has not been resolved yet");
}
return position;
return bytecodeOffset;
}
/**
* Puts a reference to this label in the bytecode of a method. If the
* position of the label is known, the offset is computed and written
* directly. Otherwise, a null offset is written and a new forward reference
* is declared for this label.
* Returns the "canonical" {@link Label} instance corresponding to this label's bytecode offset,
* if known, otherwise the label itself. The canonical instance is the first label (in the order
* of their visit by {@link MethodVisitor#visitLabel}) corresponding to this bytecode offset. It
* cannot be known for labels which have not been visited yet.
*
* @param owner
* the code writer that calls this method.
* @param out
* the bytecode of the method.
* @param source
* the position of first byte of the bytecode instruction that
* contains this label.
* @param wideOffset
* <tt>true</tt> if the reference must be stored in 4 bytes, or
* <tt>false</tt> if it must be stored with 2 bytes.
* @throws IllegalArgumentException
* if this label has not been created by the given code writer.
*/
void put(final MethodWriter owner, final ByteVector out, final int source,
final boolean wideOffset) {
if ((status & RESOLVED) == 0) {
if (wideOffset) {
addReference(-1 - source, out.length);
out.putInt(-1);
} else {
addReference(source, out.length);
out.putShort(-1);
}
} else {
if (wideOffset) {
out.putInt(position - source);
} else {
out.putShort(position - source);
}
}
}
/**
* Adds a forward reference to this label. This method must be called only
* for a true forward reference, i.e. only if this label is not resolved
* yet. For backward references, the offset of the reference can be, and
* must be, computed and stored directly.
* <p><i>This method should only be used when the {@link MethodWriter#COMPUTE_ALL_FRAMES} option
* is used.</i>
*
* @param sourcePosition
* the position of the referencing instruction. This position
* will be used to compute the offset of this forward reference.
* @param referencePosition
* the position where the offset for this forward reference must
* be stored.
* @return the label itself if {@link #frame} is null, otherwise the Label's frame owner. This
* corresponds to the "canonical" label instance described above thanks to the way the label
* frame is set in {@link MethodWriter#visitLabel}.
*/
private void addReference(final int sourcePosition,
final int referencePosition) {
if (srcAndRefPositions == null) {
srcAndRefPositions = new int[6];
}
if (referenceCount >= srcAndRefPositions.length) {
int[] a = new int[srcAndRefPositions.length + 6];
System.arraycopy(srcAndRefPositions, 0, a, 0,
srcAndRefPositions.length);
srcAndRefPositions = a;
}
srcAndRefPositions[referenceCount++] = sourcePosition;
srcAndRefPositions[referenceCount++] = referencePosition;
}
/**
* Resolves all forward references to this label. This method must be called
* when this label is added to the bytecode of the method, i.e. when its
* position becomes known. This method fills in the blanks that where left
* in the bytecode by each forward reference previously added to this label.
*
* @param owner
* the code writer that calls this method.
* @param position
* the position of this label in the bytecode.
* @param data
* the bytecode of the method.
* @return <tt>true</tt> if a blank that was left for this label was too
* small to store the offset. In such a case the corresponding jump
* instruction is replaced with a pseudo instruction (using unused
* opcodes) using an unsigned two bytes offset. These pseudo
* instructions will be replaced with standard bytecode instructions
* with wider offsets (4 bytes instead of 2), in ClassReader.
* @throws IllegalArgumentException
* if this label has already been resolved, or if it has not
* been created by the given code writer.
*/
boolean resolve(final MethodWriter owner, final int position,
final byte[] data) {
boolean needUpdate = false;
this.status |= RESOLVED;
this.position = position;
int i = 0;
while (i < referenceCount) {
int source = srcAndRefPositions[i++];
int reference = srcAndRefPositions[i++];
int offset;
if (source >= 0) {
offset = position - source;
if (offset < Short.MIN_VALUE || offset > Short.MAX_VALUE) {
/*
* changes the opcode of the jump instruction, in order to
* be able to find it later (see resizeInstructions in
* MethodWriter). These temporary opcodes are similar to
* jump instruction opcodes, except that the 2 bytes offset
* is unsigned (and can therefore represent values from 0 to
* 65535, which is sufficient since the size of a method is
* limited to 65535 bytes).
*/
int opcode = data[reference - 1] & 0xFF;
if (opcode <= Opcodes.JSR) {
// changes IFEQ ... JSR to opcodes 202 to 217
data[reference - 1] = (byte) (opcode + 49);
} else {
// changes IFNULL and IFNONNULL to opcodes 218 and 219
data[reference - 1] = (byte) (opcode + 20);
}
needUpdate = true;
}
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
} else {
offset = position + source + 1;
data[reference++] = (byte) (offset >>> 24);
data[reference++] = (byte) (offset >>> 16);
data[reference++] = (byte) (offset >>> 8);
data[reference] = (byte) offset;
}
}
return needUpdate;
}
/**
* Returns the first label of the series to which this label belongs. For an
* isolated label or for the first label in a series of successive labels,
* this method returns the label itself. For other labels it returns the
* first label of the series.
*
* @return the first label of the series to which this label belongs.
*/
Label getFirst() {
final Label getCanonicalInstance() {
return frame == null ? this : frame.owner;
}
// ------------------------------------------------------------------------
// Methods related to subroutines
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Methods to manage line numbers
// -----------------------------------------------------------------------------------------------
/**
* Returns true is this basic block belongs to the given subroutine.
* Adds a source line number corresponding to this label.
*
* @param id
* a subroutine id.
* @return true is this basic block belongs to the given subroutine.
* @param lineNumber a source line number (which should be strictly positive).
*/
boolean inSubroutine(final long id) {
if ((status & Label.VISITED) != 0) {
return (srcAndRefPositions[(int) (id >>> 32)] & (int) id) != 0;
final void addLineNumber(final int lineNumber) {
if (this.lineNumber == 0) {
this.lineNumber = (short) lineNumber;
} else {
if (otherLineNumbers == null) {
otherLineNumbers = new int[LINE_NUMBERS_CAPACITY_INCREMENT];
}
int otherLineNumberIndex = ++otherLineNumbers[0];
if (otherLineNumberIndex >= otherLineNumbers.length) {
int[] newLineNumbers = new int[otherLineNumbers.length + LINE_NUMBERS_CAPACITY_INCREMENT];
System.arraycopy(otherLineNumbers, 0, newLineNumbers, 0, otherLineNumbers.length);
otherLineNumbers = newLineNumbers;
}
otherLineNumbers[otherLineNumberIndex] = lineNumber;
}
return false;
}
/**
* Returns true if this basic block and the given one belong to a common
* subroutine.
* Makes the given visitor visit this label and its source line numbers, if applicable.
*
* @param block
* another basic block.
* @return true if this basic block and the given one belong to a common
* subroutine.
* @param methodVisitor a method visitor.
* @param visitLineNumbers whether to visit of the label's source line numbers, if any.
*/
boolean inSameSubroutine(final Label block) {
if ((status & VISITED) == 0 || (block.status & VISITED) == 0) {
return false;
}
for (int i = 0; i < srcAndRefPositions.length; ++i) {
if ((srcAndRefPositions[i] & block.srcAndRefPositions[i]) != 0) {
return true;
final void accept(final MethodVisitor methodVisitor, final boolean visitLineNumbers) {
methodVisitor.visitLabel(this);
if (visitLineNumbers && lineNumber != 0) {
methodVisitor.visitLineNumber(lineNumber & 0xFFFF, this);
if (otherLineNumbers != null) {
for (int i = 1; i <= otherLineNumbers[0]; ++i) {
methodVisitor.visitLineNumber(otherLineNumbers[i], this);
}
}
return false;
}
}
// -----------------------------------------------------------------------------------------------
// Methods to compute offsets and to manage forward references
// -----------------------------------------------------------------------------------------------
/**
* Marks this basic block as belonging to the given subroutine.
* Puts a reference to this label in the bytecode of a method. If the bytecode offset of the label
* is known, the relative bytecode offset between the label and the instruction referencing it is
* computed and written directly. Otherwise, a null relative offset is written and a new forward
* reference is declared for this label.
*
* @param id
* a subroutine id.
* @param nbSubroutines
* the total number of subroutines in the method.
* @param code the bytecode of the method. This is where the reference is appended.
* @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
* reference to be appended.
* @param wideReference whether the reference must be stored in 4 bytes (instead of 2 bytes).
*/
void addToSubroutine(final long id, final int nbSubroutines) {
if ((status & VISITED) == 0) {
status |= VISITED;
srcAndRefPositions = new int[nbSubroutines / 32 + 1];
}
srcAndRefPositions[(int) (id >>> 32)] |= (int) id;
}
/**
* Finds the basic blocks that belong to a given subroutine, and marks these
* blocks as belonging to this subroutine. This method follows the control
* flow graph to find all the blocks that are reachable from the current
* block WITHOUT following any JSR target.
*
* @param JSR
* a JSR block that jumps to this subroutine. If this JSR is not
* null it is added to the successor of the RET blocks found in
* the subroutine.
* @param id
* the id of this subroutine.
* @param nbSubroutines
* the total number of subroutines in the method.
*/
void visitSubroutine(final Label JSR, final long id, final int nbSubroutines) {
// user managed stack of labels, to avoid using a recursive method
// (recursivity can lead to stack overflow with very large methods)
Label stack = this;
while (stack != null) {
// removes a label l from the stack
Label l = stack;
stack = l.next;
l.next = null;
if (JSR != null) {
if ((l.status & VISITED2) != 0) {
continue;
}
l.status |= VISITED2;
// adds JSR to the successors of l, if it is a RET block
if ((l.status & RET) != 0) {
if (!l.inSameSubroutine(JSR)) {
Edge e = new Edge();
e.info = l.inputStackTop;
e.successor = JSR.successors.successor;
e.next = l.successors;
l.successors = e;
}
final void put(
final ByteVector code, final int sourceInsnBytecodeOffset, final boolean wideReference) {
if ((flags & FLAG_RESOLVED) == 0) {
if (wideReference) {
addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_WIDE, code.length);
code.putInt(-1);
} else {
addForwardReference(sourceInsnBytecodeOffset, FORWARD_REFERENCE_TYPE_SHORT, code.length);
code.putShort(-1);
}
} else {
// if the l block already belongs to subroutine 'id', continue
if (l.inSubroutine(id)) {
continue;
}
// marks the l block as belonging to subroutine 'id'
l.addToSubroutine(id, nbSubroutines);
}
// pushes each successor of l on the stack, except JSR targets
Edge e = l.successors;
while (e != null) {
// if the l block is a JSR block, then 'l.successors.next' leads
// to the JSR target (see {@link #visitJumpInsn}) and must
// therefore not be followed
if ((l.status & Label.JSR) == 0 || e != l.successors.next) {
// pushes e.successor on the stack if it not already added
if (e.successor.next == null) {
e.successor.next = stack;
stack = e.successor;
}
}
e = e.next;
if (wideReference) {
code.putInt(bytecodeOffset - sourceInsnBytecodeOffset);
} else {
code.putShort(bytecodeOffset - sourceInsnBytecodeOffset);
}
}
}
// ------------------------------------------------------------------------
// Overriden Object methods
// ------------------------------------------------------------------------
/**
* Adds a forward reference to this label. This method must be called only for a true forward
* reference, i.e. only if this label is not resolved yet. For backward references, the relative
* bytecode offset of the reference can be, and must be, computed and stored directly.
*
* @param sourceInsnBytecodeOffset the bytecode offset of the instruction that contains the
* reference stored at referenceHandle.
* @param referenceType either {@link #FORWARD_REFERENCE_TYPE_SHORT} or {@link
* #FORWARD_REFERENCE_TYPE_WIDE}.
* @param referenceHandle the offset in the bytecode where the forward reference value must be
* stored.
*/
private void addForwardReference(
final int sourceInsnBytecodeOffset, final int referenceType, final int referenceHandle) {
if (forwardReferences == null) {
forwardReferences = new int[FORWARD_REFERENCES_CAPACITY_INCREMENT];
}
int lastElementIndex = forwardReferences[0];
if (lastElementIndex + 2 >= forwardReferences.length) {
int[] newValues = new int[forwardReferences.length + FORWARD_REFERENCES_CAPACITY_INCREMENT];
System.arraycopy(forwardReferences, 0, newValues, 0, forwardReferences.length);
forwardReferences = newValues;
}
forwardReferences[++lastElementIndex] = sourceInsnBytecodeOffset;
forwardReferences[++lastElementIndex] = referenceType | referenceHandle;
forwardReferences[0] = lastElementIndex;
}
/**
* Sets the bytecode offset of this label to the given value and resolves the forward references
* to this label, if any. This method must be called when this label is added to the bytecode of
* the method, i.e. when its bytecode offset becomes known. This method fills in the blanks that
* where left in the bytecode by each forward reference previously added to this label.
*
* @param code the bytecode of the method.
* @param bytecodeOffset the bytecode offset of this label.
* @return {@literal true} if a blank that was left for this label was too small to store the
* offset. In such a case the corresponding jump instruction is replaced with an equivalent
* ASM specific instruction using an unsigned two bytes offset. These ASM specific
* instructions are later replaced with standard bytecode instructions with wider offsets (4
* bytes instead of 2), in ClassReader.
*/
final boolean resolve(final byte[] code, final int bytecodeOffset) {
this.flags |= FLAG_RESOLVED;
this.bytecodeOffset = bytecodeOffset;
if (forwardReferences == null) {
return false;
}
boolean hasAsmInstructions = false;
for (int i = forwardReferences[0]; i > 0; i -= 2) {
final int sourceInsnBytecodeOffset = forwardReferences[i - 1];
final int reference = forwardReferences[i];
final int relativeOffset = bytecodeOffset - sourceInsnBytecodeOffset;
int handle = reference & FORWARD_REFERENCE_HANDLE_MASK;
if ((reference & FORWARD_REFERENCE_TYPE_MASK) == FORWARD_REFERENCE_TYPE_SHORT) {
if (relativeOffset < Short.MIN_VALUE || relativeOffset > Short.MAX_VALUE) {
// Change the opcode of the jump instruction, in order to be able to find it later in
// ClassReader. These ASM specific opcodes are similar to jump instruction opcodes, except
// that the 2 bytes offset is unsigned (and can therefore represent values from 0 to
// 65535, which is sufficient since the size of a method is limited to 65535 bytes).
int opcode = code[sourceInsnBytecodeOffset] & 0xFF;
if (opcode < Opcodes.IFNULL) {
// Change IFEQ ... JSR to ASM_IFEQ ... ASM_JSR.
code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_OPCODE_DELTA);
} else {
// Change IFNULL and IFNONNULL to ASM_IFNULL and ASM_IFNONNULL.
code[sourceInsnBytecodeOffset] = (byte) (opcode + Constants.ASM_IFNULL_OPCODE_DELTA);
}
hasAsmInstructions = true;
}
code[handle++] = (byte) (relativeOffset >>> 8);
code[handle] = (byte) relativeOffset;
} else {
code[handle++] = (byte) (relativeOffset >>> 24);
code[handle++] = (byte) (relativeOffset >>> 16);
code[handle++] = (byte) (relativeOffset >>> 8);
code[handle] = (byte) relativeOffset;
}
}
return hasAsmInstructions;
}
// -----------------------------------------------------------------------------------------------
// Methods related to subroutines
// -----------------------------------------------------------------------------------------------
/**
* Finds the basic blocks that belong to the subroutine starting with the basic block
* corresponding to this label, and marks these blocks as belonging to this subroutine. This
* method follows the control flow graph to find all the blocks that are reachable from the
* current basic block WITHOUT following any jsr target.
*
* <p>Note: a precondition and postcondition of this method is that all labels must have a null
* {@link #nextListElement}.
*
* @param subroutineId the id of the subroutine starting with the basic block corresponding to
* this label.
*/
final void markSubroutine(final short subroutineId) {
// Data flow algorithm: put this basic block in a list of blocks to process (which are blocks
// belonging to subroutine subroutineId) and, while there are blocks to process, remove one from
// the list, mark it as belonging to the subroutine, and add its successor basic blocks in the
// control flow graph to the list of blocks to process (if not already done).
Label listOfBlocksToProcess = this;
listOfBlocksToProcess.nextListElement = EMPTY_LIST;
while (listOfBlocksToProcess != EMPTY_LIST) {
// Remove a basic block from the list of blocks to process.
Label basicBlock = listOfBlocksToProcess;
listOfBlocksToProcess = listOfBlocksToProcess.nextListElement;
basicBlock.nextListElement = null;
// If it is not already marked as belonging to a subroutine, mark it as belonging to
// subroutineId and add its successors to the list of blocks to process (unless already done).
if (basicBlock.subroutineId == 0) {
basicBlock.subroutineId = subroutineId;
listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
}
}
}
/**
* Finds the basic blocks that end a subroutine starting with the basic block corresponding to
* this label and, for each one of them, adds an outgoing edge to the basic block following the
* given subroutine call. In other words, completes the control flow graph by adding the edges
* corresponding to the return from this subroutine, when called from the given caller basic
* block.
*
* <p>Note: a precondition and postcondition of this method is that all labels must have a null
* {@link #nextListElement}.
*
* @param subroutineCaller a basic block that ends with a jsr to the basic block corresponding to
* this label. This label is supposed to correspond to the start of a subroutine.
*/
final void addSubroutineRetSuccessors(final Label subroutineCaller) {
// Data flow algorithm: put this basic block in a list blocks to process (which are blocks
// belonging to a subroutine starting with this label) and, while there are blocks to process,
// remove one from the list, put it in a list of blocks that have been processed, add a return
// edge to the successor of subroutineCaller if applicable, and add its successor basic blocks
// in the control flow graph to the list of blocks to process (if not already done).
Label listOfProcessedBlocks = EMPTY_LIST;
Label listOfBlocksToProcess = this;
listOfBlocksToProcess.nextListElement = EMPTY_LIST;
while (listOfBlocksToProcess != EMPTY_LIST) {
// Move a basic block from the list of blocks to process to the list of processed blocks.
Label basicBlock = listOfBlocksToProcess;
listOfBlocksToProcess = basicBlock.nextListElement;
basicBlock.nextListElement = listOfProcessedBlocks;
listOfProcessedBlocks = basicBlock;
// Add an edge from this block to the successor of the caller basic block, if this block is
// the end of a subroutine and if this block and subroutineCaller do not belong to the same
// subroutine.
if ((basicBlock.flags & FLAG_SUBROUTINE_END) != 0
&& basicBlock.subroutineId != subroutineCaller.subroutineId) {
basicBlock.outgoingEdges =
new Edge(
basicBlock.outputStackSize,
// By construction, the first outgoing edge of a basic block that ends with a jsr
// instruction leads to the jsr continuation block, i.e. where execution continues
// when ret is called (see {@link #FLAG_SUBROUTINE_CALLER}).
subroutineCaller.outgoingEdges.successor,
basicBlock.outgoingEdges);
}
// Add its successors to the list of blocks to process. Note that {@link #pushSuccessors} does
// not push basic blocks which are already in a list. Here this means either in the list of
// blocks to process, or in the list of already processed blocks. This second list is
// important to make sure we don't reprocess an already processed block.
listOfBlocksToProcess = basicBlock.pushSuccessors(listOfBlocksToProcess);
}
// Reset the {@link #nextListElement} of all the basic blocks that have been processed to null,
// so that this method can be called again with a different subroutine or subroutine caller.
while (listOfProcessedBlocks != EMPTY_LIST) {
Label newListOfProcessedBlocks = listOfProcessedBlocks.nextListElement;
listOfProcessedBlocks.nextListElement = null;
listOfProcessedBlocks = newListOfProcessedBlocks;
}
}
/**
* Adds the successors of this label in the method's control flow graph (except those
* corresponding to a jsr target, and those already in a list of labels) to the given list of
* blocks to process, and returns the new list.
*
* @param listOfLabelsToProcess a list of basic blocks to process, linked together with their
* {@link #nextListElement} field.
* @return the new list of blocks to process.
*/
private Label pushSuccessors(final Label listOfLabelsToProcess) {
Label newListOfLabelsToProcess = listOfLabelsToProcess;
Edge outgoingEdge = outgoingEdges;
while (outgoingEdge != null) {
// By construction, the second outgoing edge of a basic block that ends with a jsr instruction
// leads to the jsr target (see {@link #FLAG_SUBROUTINE_CALLER}).
boolean isJsrTarget =
(flags & Label.FLAG_SUBROUTINE_CALLER) != 0 && outgoingEdge == outgoingEdges.nextEdge;
if (!isJsrTarget && outgoingEdge.successor.nextListElement == null) {
// Add this successor to the list of blocks to process, if it does not already belong to a
// list of labels.
outgoingEdge.successor.nextListElement = newListOfLabelsToProcess;
newListOfLabelsToProcess = outgoingEdge.successor;
}
outgoingEdge = outgoingEdge.nextEdge;
}
return newListOfLabelsToProcess;
}
// -----------------------------------------------------------------------------------------------
// Overridden Object methods
// -----------------------------------------------------------------------------------------------
/**
* Returns a string representation of this label.

View file

@ -0,0 +1,130 @@
/*
* 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;
/**
* Exception thrown when the Code attribute of a method produced by a {@link ClassWriter} is too
* large.
*
* @author Jason Zaugg
*/
public final class MethodTooLargeException extends IndexOutOfBoundsException {
private static final long serialVersionUID = 6807380416709738314L;
private final String className;
private final String methodName;
private final String descriptor;
private final int codeSize;
/**
* Constructs a new {@link MethodTooLargeException}.
*
* @param className the internal name of the owner class.
* @param methodName the name of the method.
* @param descriptor the descriptor of the method.
* @param codeSize the size of the method's Code attribute, in bytes.
*/
public MethodTooLargeException(
final String className,
final String methodName,
final String descriptor,
final int codeSize) {
super("Method too large: " + className + "." + methodName + " " + descriptor);
this.className = className;
this.methodName = methodName;
this.descriptor = descriptor;
this.codeSize = codeSize;
}
/**
* Returns the internal name of the owner class.
*
* @return the internal name of the owner class.
*/
public String getClassName() {
return className;
}
/**
* Returns the name of the method.
*
* @return the name of the method.
*/
public String getMethodName() {
return methodName;
}
/**
* Returns the descriptor of the method.
*
* @return the descriptor of the method.
*/
public String getDescriptor() {
return descriptor;
}
/**
* Returns the size of the method's Code attribute, in bytes.
*
* @return the size of the method's Code attribute, in bytes.
*/
public int getCodeSize() {
return codeSize;
}
}

View file

@ -59,36 +59,28 @@
package jdk.internal.org.objectweb.asm;
/**
* A visitor to visit a Java module. The methods of this class must be called in
* the following order: <tt>visitMainClass</tt> | ( <tt>visitPackage</tt> |
* <tt>visitRequire</tt> | <tt>visitExport</tt> | <tt>visitOpen</tt> |
* <tt>visitUse</tt> | <tt>visitProvide</tt> )* <tt>visitEnd</tt>.
*
* The methods {@link #visitRequire(String, int, String)}, {@link #visitExport(String, int, String...)},
* {@link #visitOpen(String, int, String...)} and {@link #visitPackage(String)}
* take as parameter a package name or a module name. Unlike the other names which are internal names
* (names separated by slash), module and package names are qualified names (names separated by dot).
* A visitor to visit a Java module. The methods of this class must be called in the following
* order: ( {@code visitMainClass} | ( {@code visitPackage} | {@code visitRequire} | {@code
* visitExport} | {@code visitOpen} | {@code visitUse} | {@code visitProvide} )* ) {@code visitEnd}.
*
* @author Remi Forax
* @author Eric Bruneton
*/
public abstract class ModuleVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field
* must be {@link Opcodes#ASM6}.
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
* Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
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 null. */
protected ModuleVisitor mv;
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
* or {@link Opcodes#ASM7}.
*/
public ModuleVisitor(final int api) {
this(api, null);
@ -97,18 +89,17 @@ public abstract class ModuleVisitor {
/**
* Constructs a new {@link ModuleVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be {@link Opcodes#ASM6}.
* @param mv
* the module visitor to which this visitor must delegate method
* calls. May be null.
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM6}
* or {@link Opcodes#ASM7}.
* @param moduleVisitor the module visitor to which this visitor must delegate method calls. May
* be null.
*/
public ModuleVisitor(final int api, final ModuleVisitor mv) {
if (api != Opcodes.ASM6) {
public ModuleVisitor(final int api, final ModuleVisitor moduleVisitor) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
}
this.api = api;
this.mv = mv;
this.mv = moduleVisitor;
}
/**
@ -116,7 +107,7 @@ public abstract class ModuleVisitor {
*
* @param mainClass the internal name of the main class of the current module.
*/
public void visitMainClass(String mainClass) {
public void visitMainClass(final String mainClass) {
if (mv != null) {
mv.visitMainClass(mainClass);
}
@ -125,9 +116,9 @@ public abstract class ModuleVisitor {
/**
* Visit a package of the current module.
*
* @param packaze the qualified name of a package.
* @param packaze the internal name of a package.
*/
public void visitPackage(String packaze) {
public void visitPackage(final String packaze) {
if (mv != null) {
mv.visitPackage(packaze);
}
@ -136,13 +127,12 @@ public abstract class ModuleVisitor {
/**
* Visits a dependence of the current module.
*
* @param module the qualified name of the dependence.
* @param access the access flag of the dependence among
* ACC_TRANSITIVE, ACC_STATIC_PHASE, ACC_SYNTHETIC
* and ACC_MANDATED.
* @param version the module version at compile time or null.
* @param module the fully qualified name (using dots) of the dependence.
* @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
* ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param version the module version at compile time, or {@literal null}.
*/
public void visitRequire(String module, int access, String version) {
public void visitRequire(final String module, final int access, final String version) {
if (mv != null) {
mv.visitRequire(module, access, version);
}
@ -151,15 +141,13 @@ public abstract class ModuleVisitor {
/**
* Visit an exported package of the current module.
*
* @param packaze the qualified name of the exported package.
* @param access the access flag of the exported package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can access to
* the public classes of the exported package or
* <tt>null</tt>.
* @param packaze the internal name of the exported package.
* @param access the access flag of the exported package, valid values are among {@code
* ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param modules the fully qualified names (using dots) of the modules that can access the public
* classes of the exported package, or {@literal null}.
*/
public void visitExport(String packaze, int access, String... modules) {
public void visitExport(final String packaze, final int access, final String... modules) {
if (mv != null) {
mv.visitExport(packaze, access, modules);
}
@ -168,27 +156,25 @@ public abstract class ModuleVisitor {
/**
* Visit an open package of the current module.
*
* @param packaze the qualified name of the opened package.
* @param access the access flag of the opened package,
* valid values are among {@code ACC_SYNTHETIC} and
* {@code ACC_MANDATED}.
* @param modules the qualified names of the modules that can use deep
* reflection to the classes of the open package or
* <tt>null</tt>.
* @param packaze the internal name of the opened package.
* @param access the access flag of the opened package, valid values are among {@code
* ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param modules the fully qualified names (using dots) of the modules that can use deep
* reflection to the classes of the open package, or {@literal null}.
*/
public void visitOpen(String packaze, int access, String... modules) {
public void visitOpen(final String packaze, final int access, final String... modules) {
if (mv != null) {
mv.visitOpen(packaze, access, modules);
}
}
/**
* Visit a service used by the current module.
* The name must be the internal name of an interface or a class.
* Visit a service used by the current module. The name must be the internal name of an interface
* or a class.
*
* @param service the internal name of the service.
*/
public void visitUse(String service) {
public void visitUse(final String service) {
if (mv != null) {
mv.visitUse(service);
}
@ -197,19 +183,19 @@ public abstract class ModuleVisitor {
/**
* Visit an implementation of a service.
*
* @param service the internal name of the service
* @param providers the internal names of the implementations
* of the service (there is at least one provider).
* @param service the internal name of the service.
* @param providers the internal names of the implementations of the service (there is at least
* one provider).
*/
public void visitProvide(String service, String... providers) {
public void visitProvide(final String service, final String... providers) {
if (mv != null) {
mv.visitProvide(service, providers);
}
}
/**
* Visits the end of the module. This method, which is the last one to be
* called, is used to inform the visitor that everything have been visited.
* Visits the end of the module. 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 (mv != null) {

View file

@ -56,267 +56,229 @@
* 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 {@link ModuleVisitor} that generates the corresponding Module, ModulePackages and
* ModuleMainClass attributes, 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.25">JVMS
* 4.7.25</a>
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.26">JVMS
* 4.7.26</a>
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.27">JVMS
* 4.7.27</a>
* @author Remi Forax
* @author Eric Bruneton
*/
final class ModuleWriter extends ModuleVisitor {
/**
* The class writer to which this Module attribute must be added.
*/
private final ClassWriter cw;
/**
* size in byte of the Module attribute.
*/
int size;
/** Where the constants used in this AnnotationWriter must be stored. */
private final SymbolTable symbolTable;
/**
* Number of attributes associated with the current module
* (Version, ConcealPackages, etc)
*/
int attributeCount;
/** The module_name_index field of the JVMS Module attribute. */
private final int moduleNameIndex;
/**
* Size in bytes of the attributes associated with the current module
*/
int attributesSize;
/** The module_flags field of the JVMS Module attribute. */
private final int moduleFlags;
/**
* module name index in the constant pool
*/
private final int name;
/** The module_version_index field of the JVMS Module attribute. */
private final int moduleVersionIndex;
/**
* module access flags
*/
private final int access;
/** The requires_count field of the JVMS Module attribute. */
private int requiresCount;
/**
* module version index in the constant pool or 0
*/
private final int version;
/** The binary content of the 'requires' array of the JVMS Module attribute. */
private final ByteVector requires;
/**
* module main class index in the constant pool or 0
*/
private int mainClass;
/** The exports_count field of the JVMS Module attribute. */
private int exportsCount;
/**
* number of packages
*/
/** The binary content of the 'exports' array of the JVMS Module attribute. */
private final ByteVector exports;
/** The opens_count field of the JVMS Module attribute. */
private int opensCount;
/** The binary content of the 'opens' array of the JVMS Module attribute. */
private final ByteVector opens;
/** The uses_count field of the JVMS Module attribute. */
private int usesCount;
/** The binary content of the 'uses_index' array of the JVMS Module attribute. */
private final ByteVector usesIndex;
/** The provides_count field of the JVMS Module attribute. */
private int providesCount;
/** The binary content of the 'provides' array of the JVMS Module attribute. */
private final ByteVector provides;
/** The provides_count field of the JVMS ModulePackages attribute. */
private int packageCount;
/**
* The packages in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in packageCount
*/
private ByteVector packages;
/** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */
private final ByteVector packageIndex;
/**
* number of requires items
*/
private int requireCount;
/** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */
private int mainClassIndex;
/**
* The requires items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in requireCount
*/
private ByteVector requires;
/**
* number of exports items
*/
private int exportCount;
/**
* The exports items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in exportCount
*/
private ByteVector exports;
/**
* number of opens items
*/
private int openCount;
/**
* The opens items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in openCount
*/
private ByteVector opens;
/**
* number of uses items
*/
private int useCount;
/**
* The uses items in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in useCount
*/
private ByteVector uses;
/**
* number of provides items
*/
private int provideCount;
/**
* The uses provides in bytecode form. This byte vector only contains
* the items themselves, the number of items is store in provideCount
*/
private ByteVector provides;
ModuleWriter(final ClassWriter cw, final int name,
final int access, final int version) {
super(Opcodes.ASM6);
this.cw = cw;
this.size = 16; // name + access + version + 5 counts
this.name = name;
this.access = access;
this.version = version;
ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
super(Opcodes.ASM7);
this.symbolTable = symbolTable;
this.moduleNameIndex = name;
this.moduleFlags = access;
this.moduleVersionIndex = version;
this.requires = new ByteVector();
this.exports = new ByteVector();
this.opens = new ByteVector();
this.usesIndex = new ByteVector();
this.provides = new ByteVector();
this.packageIndex = new ByteVector();
}
@Override
public void visitMainClass(String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass
cw.newUTF8("ModuleMainClass");
attributeCount++;
attributesSize += 8;
}
this.mainClass = cw.newClass(mainClass);
public void visitMainClass(final String mainClass) {
this.mainClassIndex = symbolTable.addConstantClass(mainClass).index;
}
@Override
public void visitPackage(String packaze) {
if (packages == null) {
// protect against several calls to visitPackage
cw.newUTF8("ModulePackages");
packages = new ByteVector();
attributeCount++;
attributesSize += 8;
}
packages.putShort(cw.newPackage(packaze));
public void visitPackage(final String packaze) {
packageIndex.putShort(symbolTable.addConstantPackage(packaze).index);
packageCount++;
attributesSize += 2;
}
@Override
public void visitRequire(String module, int access, String version) {
if (requires == null) {
requires = new ByteVector();
}
requires.putShort(cw.newModule(module))
public void visitRequire(final String module, final int access, final String version) {
requires
.putShort(symbolTable.addConstantModule(module).index)
.putShort(access)
.putShort(version == null? 0: cw.newUTF8(version));
requireCount++;
size += 6;
.putShort(version == null ? 0 : symbolTable.addConstantUtf8(version));
requiresCount++;
}
@Override
public void visitExport(String packaze, int access, String... modules) {
if (exports == null) {
exports = new ByteVector();
}
exports.putShort(cw.newPackage(packaze)).putShort(access);
public void visitExport(final String packaze, final int access, final String... modules) {
exports.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
if (modules == null) {
exports.putShort(0);
size += 6;
} else {
exports.putShort(modules.length);
for(String module: modules) {
exports.putShort(cw.newModule(module));
for (String module : modules) {
exports.putShort(symbolTable.addConstantModule(module).index);
}
size += 6 + 2 * modules.length;
}
exportCount++;
exportsCount++;
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
if (opens == null) {
opens = new ByteVector();
}
opens.putShort(cw.newPackage(packaze)).putShort(access);
public void visitOpen(final String packaze, final int access, final String... modules) {
opens.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
if (modules == null) {
opens.putShort(0);
size += 6;
} else {
opens.putShort(modules.length);
for(String module: modules) {
opens.putShort(cw.newModule(module));
for (String module : modules) {
opens.putShort(symbolTable.addConstantModule(module).index);
}
size += 6 + 2 * modules.length;
}
openCount++;
opensCount++;
}
@Override
public void visitUse(String service) {
if (uses == null) {
uses = new ByteVector();
}
uses.putShort(cw.newClass(service));
useCount++;
size += 2;
public void visitUse(final String service) {
usesIndex.putShort(symbolTable.addConstantClass(service).index);
usesCount++;
}
@Override
public void visitProvide(String service, String... providers) {
if (provides == null) {
provides = new ByteVector();
}
provides.putShort(cw.newClass(service));
public void visitProvide(final String service, final String... providers) {
provides.putShort(symbolTable.addConstantClass(service).index);
provides.putShort(providers.length);
for(String provider: providers) {
provides.putShort(cw.newClass(provider));
for (String provider : providers) {
provides.putShort(symbolTable.addConstantClass(provider).index);
}
provideCount++;
size += 4 + 2 * providers.length;
providesCount++;
}
@Override
public void visitEnd() {
// empty
// Nothing to do.
}
void putAttributes(ByteVector out) {
if (mainClass != 0) {
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass);
/**
* Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this
* ModuleWriter.
*
* @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3).
*/
int getAttributeCount() {
return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0);
}
if (packages != null) {
out.putShort(cw.newUTF8("ModulePackages"))
.putInt(2 + 2 * packageCount)
/**
* Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this
* ModuleWriter. Also add the names of these attributes in the constant pool.
*
* @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes.
*/
int computeAttributesSize() {
symbolTable.addConstantUtf8(Constants.MODULE);
// 6 attribute header bytes, 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
int size =
22 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
if (packageCount > 0) {
symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES);
// 6 attribute header bytes, and 2 bytes for package_count.
size += 8 + packageIndex.length;
}
if (mainClassIndex > 0) {
symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS);
// 6 attribute header bytes, and 2 bytes for main_class_index.
size += 8;
}
return size;
}
/**
* Puts the Module, ModulePackages and ModuleMainClass attributes generated by this ModuleWriter
* in the given ByteVector.
*
* @param output where the attributes must be put.
*/
void putAttributes(final ByteVector output) {
// 6 bytes for name, flags and version, and 5 * 2 bytes for counts.
int moduleAttributeLength =
16 + requires.length + exports.length + opens.length + usesIndex.length + provides.length;
output
.putShort(symbolTable.addConstantUtf8(Constants.MODULE))
.putInt(moduleAttributeLength)
.putShort(moduleNameIndex)
.putShort(moduleFlags)
.putShort(moduleVersionIndex)
.putShort(requiresCount)
.putByteArray(requires.data, 0, requires.length)
.putShort(exportsCount)
.putByteArray(exports.data, 0, exports.length)
.putShort(opensCount)
.putByteArray(opens.data, 0, opens.length)
.putShort(usesCount)
.putByteArray(usesIndex.data, 0, usesIndex.length)
.putShort(providesCount)
.putByteArray(provides.data, 0, provides.length);
if (packageCount > 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.MODULE_PACKAGES))
.putInt(2 + packageIndex.length)
.putShort(packageCount)
.putByteArray(packages.data, 0, packages.length);
.putByteArray(packageIndex.data, 0, packageIndex.length);
}
}
void put(ByteVector out) {
out.putInt(size);
out.putShort(name).putShort(access).putShort(version);
out.putShort(requireCount);
if (requires != null) {
out.putByteArray(requires.data, 0, requires.length);
}
out.putShort(exportCount);
if (exports != null) {
out.putByteArray(exports.data, 0, exports.length);
}
out.putShort(openCount);
if (opens != null) {
out.putByteArray(opens.data, 0, opens.length);
}
out.putShort(useCount);
if (uses != null) {
out.putByteArray(uses.data, 0, uses.length);
}
out.putShort(provideCount);
if (provides != null) {
out.putByteArray(provides.data, 0, provides.length);
if (mainClassIndex > 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS))
.putInt(2)
.putShort(mainClassIndex);
}
}
}

View file

@ -59,26 +59,29 @@
package jdk.internal.org.objectweb.asm;
/**
* Defines the JVM opcodes, access flags and array type codes. This interface
* does not define all the JVM opcodes because some opcodes are automatically
* handled. For example, the xLOAD and xSTORE opcodes are automatically replaced
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n
* opcodes are therefore not defined in this interface. Likewise for LDC,
* automatically replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and
* JSR_W.
* The JVM opcodes, access flags and array type codes. This interface does not define all the JVM
* opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes
* are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and
* xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically
* replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
* @author Eric Bruneton
* @author Eugene Kuleshov
*/
// DontCheck(InterfaceIsType): can't be fixed (for backward binary compatibility).
public interface Opcodes {
// ASM API versions
// ASM API versions.
int ASM4 = 4 << 16 | 0 << 8 | 0;
int ASM5 = 5 << 16 | 0 << 8 | 0;
int ASM6 = 6 << 16 | 0 << 8 | 0;
int ASM4 = 4 << 16 | 0 << 8;
int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8;
int ASM7 = 7 << 16 | 0 << 8;
// versions
// 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;
int V1_2 = 0 << 16 | 46;
@ -93,7 +96,19 @@ public interface Opcodes {
int V11 = 0 << 16 | 55;
int V12 = 0 << 16 | 56;
// access flags
/**
* Version flag indicating that the class is using 'preview' features.
*
* <p>{@code version & V_PREVIEW == V_PREVIEW} tests if a version is flagged with {@code
* V_PREVIEW}.
*/
int V_PREVIEW = 0xFFFF0000;
// Access flags values, defined in
// - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.1-200-E.1
// - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.5-200-A.1
// - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.6-200-A.1
// - https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.25
int ACC_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // class, field, method
@ -119,12 +134,15 @@ public interface Opcodes {
int ACC_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class
// ASM specific pseudo access flags
// ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
// 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_DEPRECATED = 0x20000; // class, field, method
// types for NEWARRAY
// Possible values for the type operand of the NEWARRAY instruction.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html#jvms-6.5.newarray.
int T_BOOLEAN = 4;
int T_CHAR = 5;
@ -135,7 +153,8 @@ public interface Opcodes {
int T_INT = 10;
int T_LONG = 11;
// tags for Handle
// Possible values for the reference_kind field of CONSTANT_MethodHandle_info structures.
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.4.8.
int H_GETFIELD = 1;
int H_GETSTATIC = 2;
@ -147,57 +166,50 @@ public interface Opcodes {
int H_NEWINVOKESPECIAL = 8;
int H_INVOKEINTERFACE = 9;
// stack map frame types
// ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
/**
* Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
*/
/** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
int F_NEW = -1;
/**
* Represents a compressed frame with complete frame data.
*/
/** A compressed frame with complete frame data. */
int F_FULL = 0;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that additional 1-3 locals are defined, and
* with an empty stack.
* A compressed frame where locals are the same as the locals in the previous frame, except that
* additional 1-3 locals are defined, and with an empty stack.
*/
int F_APPEND = 1;
/**
* Represents a compressed frame where locals are the same as the locals in
* the previous frame, except that the last 1-3 locals are absent and with
* an empty stack.
* A compressed frame where locals are the same as the locals in the previous frame, except that
* the last 1-3 locals are absent and with an empty stack.
*/
int F_CHOP = 2;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with an empty stack.
* A compressed frame with exactly the same locals as the previous frame and with an empty stack.
*/
int F_SAME = 3;
/**
* Represents a compressed frame with exactly the same locals as the
* previous frame and with a single value on the stack.
* A compressed frame with exactly the same locals as the previous frame and with a single value
* on the stack.
*/
int F_SAME1 = 4;
// Do not try to change the following code to use auto-boxing,
// these values are compared by reference and not by value
// The constructor of Integer was deprecated in 9
// but we are stuck with it by backward compatibility
@SuppressWarnings("deprecation") Integer TOP = new Integer(0);
@SuppressWarnings("deprecation") Integer INTEGER = new Integer(1);
@SuppressWarnings("deprecation") Integer FLOAT = new Integer(2);
@SuppressWarnings("deprecation") Integer DOUBLE = new Integer(3);
@SuppressWarnings("deprecation") Integer LONG = new Integer(4);
@SuppressWarnings("deprecation") Integer NULL = new Integer(5);
@SuppressWarnings("deprecation") Integer UNINITIALIZED_THIS = new Integer(6);
// Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}.
// opcodes // visit method (- = idem)
Integer TOP = Frame.ITEM_TOP;
Integer INTEGER = Frame.ITEM_INTEGER;
Integer FLOAT = Frame.ITEM_FLOAT;
Integer DOUBLE = Frame.ITEM_DOUBLE;
Integer LONG = Frame.ITEM_LONG;
Integer NULL = Frame.ITEM_NULL;
Integer UNINITIALIZED_THIS = Frame.ITEM_UNINITIALIZED_THIS;
// The JVM opcode values (with the MethodVisitor method name used to visit them in comment, and
// where '-' means 'same method name as on the previous line').
// See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-6.html.
int NOP = 0; // visitInsn
int ACONST_NULL = 1; // -
@ -218,33 +230,11 @@ public interface Opcodes {
int BIPUSH = 16; // visitIntInsn
int SIPUSH = 17; // -
int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // -
int FLOAD = 23; // -
int DLOAD = 24; // -
int ALOAD = 25; // -
// int ILOAD_0 = 26; // -
// int ILOAD_1 = 27; // -
// int ILOAD_2 = 28; // -
// int ILOAD_3 = 29; // -
// int LLOAD_0 = 30; // -
// int LLOAD_1 = 31; // -
// int LLOAD_2 = 32; // -
// int LLOAD_3 = 33; // -
// int FLOAD_0 = 34; // -
// int FLOAD_1 = 35; // -
// int FLOAD_2 = 36; // -
// int FLOAD_3 = 37; // -
// int DLOAD_0 = 38; // -
// int DLOAD_1 = 39; // -
// int DLOAD_2 = 40; // -
// int DLOAD_3 = 41; // -
// int ALOAD_0 = 42; // -
// int ALOAD_1 = 43; // -
// int ALOAD_2 = 44; // -
// int ALOAD_3 = 45; // -
int IALOAD = 46; // visitInsn
int LALOAD = 47; // -
int FALOAD = 48; // -
@ -258,26 +248,6 @@ public interface Opcodes {
int FSTORE = 56; // -
int DSTORE = 57; // -
int ASTORE = 58; // -
// int ISTORE_0 = 59; // -
// int ISTORE_1 = 60; // -
// int ISTORE_2 = 61; // -
// int ISTORE_3 = 62; // -
// int LSTORE_0 = 63; // -
// int LSTORE_1 = 64; // -
// int LSTORE_2 = 65; // -
// int LSTORE_3 = 66; // -
// int FSTORE_0 = 67; // -
// int FSTORE_1 = 68; // -
// int FSTORE_2 = 69; // -
// int FSTORE_3 = 70; // -
// int DSTORE_0 = 71; // -
// int DSTORE_1 = 72; // -
// int DSTORE_2 = 73; // -
// int DSTORE_3 = 74; // -
// int ASTORE_0 = 75; // -
// int ASTORE_1 = 76; // -
// int ASTORE_2 = 77; // -
// int ASTORE_3 = 78; // -
int IASTORE = 79; // visitInsn
int LASTORE = 80; // -
int FASTORE = 81; // -
@ -395,10 +365,7 @@ public interface Opcodes {
int INSTANCEOF = 193; // -
int MONITORENTER = 194; // visitInsn
int MONITOREXIT = 195; // -
// int WIDE = 196; // NOT VISITED
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // -
// int GOTO_W = 200; // -
// int JSR_W = 201; // -
}

View file

@ -0,0 +1,274 @@
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This file is available under and governed by the GNU General Public
* License version 2 only, as published by the Free Software Foundation.
* However, the following notice accompanied the original version of this
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package jdk.internal.org.objectweb.asm;
/**
* An entry of the constant pool, of the BootstrapMethods attribute, or of the (ASM specific) type
* table of a class.
*
* @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
*/
abstract class Symbol {
// Tag values for the constant pool entries (using the same order as in the JVMS).
/** The tag value of CONSTANT_Class_info JVMS structures. */
static final int CONSTANT_CLASS_TAG = 7;
/** The tag value of CONSTANT_Fieldref_info JVMS structures. */
static final int CONSTANT_FIELDREF_TAG = 9;
/** The tag value of CONSTANT_Methodref_info JVMS structures. */
static final int CONSTANT_METHODREF_TAG = 10;
/** The tag value of CONSTANT_InterfaceMethodref_info JVMS structures. */
static final int CONSTANT_INTERFACE_METHODREF_TAG = 11;
/** The tag value of CONSTANT_String_info JVMS structures. */
static final int CONSTANT_STRING_TAG = 8;
/** The tag value of CONSTANT_Integer_info JVMS structures. */
static final int CONSTANT_INTEGER_TAG = 3;
/** The tag value of CONSTANT_Float_info JVMS structures. */
static final int CONSTANT_FLOAT_TAG = 4;
/** The tag value of CONSTANT_Long_info JVMS structures. */
static final int CONSTANT_LONG_TAG = 5;
/** The tag value of CONSTANT_Double_info JVMS structures. */
static final int CONSTANT_DOUBLE_TAG = 6;
/** The tag value of CONSTANT_NameAndType_info JVMS structures. */
static final int CONSTANT_NAME_AND_TYPE_TAG = 12;
/** The tag value of CONSTANT_Utf8_info JVMS structures. */
static final int CONSTANT_UTF8_TAG = 1;
/** The tag value of CONSTANT_MethodHandle_info JVMS structures. */
static final int CONSTANT_METHOD_HANDLE_TAG = 15;
/** The tag value of CONSTANT_MethodType_info JVMS structures. */
static final int CONSTANT_METHOD_TYPE_TAG = 16;
/** The tag value of CONSTANT_Dynamic_info JVMS structures. */
static final int CONSTANT_DYNAMIC_TAG = 17;
/** The tag value of CONSTANT_InvokeDynamic_info JVMS structures. */
static final int CONSTANT_INVOKE_DYNAMIC_TAG = 18;
/** The tag value of CONSTANT_Module_info JVMS structures. */
static final int CONSTANT_MODULE_TAG = 19;
/** The tag value of CONSTANT_Package_info JVMS structures. */
static final int CONSTANT_PACKAGE_TAG = 20;
// Tag values for the BootstrapMethods attribute entries (ASM specific tag).
/** The tag value of the BootstrapMethods attribute entries. */
static final int BOOTSTRAP_METHOD_TAG = 64;
// Tag values for the type table entries (ASM specific tags).
/** The tag value of a normal type entry in the (ASM specific) type table of a class. */
static final int TYPE_TAG = 128;
/**
* The tag value of an {@link Frame#ITEM_UNINITIALIZED} type entry in the type table of a class.
*/
static final int UNINITIALIZED_TYPE_TAG = 129;
/** The tag value of a merged type entry in the (ASM specific) type table of a class. */
static final int MERGED_TYPE_TAG = 130;
// Instance fields.
/**
* The index of this symbol in the constant pool, in the BootstrapMethods attribute, or in the
* (ASM specific) type table of a class (depending on the {@link #tag} value).
*/
final int index;
/**
* A tag indicating the type of this symbol. Must be one of the static tag values defined in this
* class.
*/
final int tag;
/**
* The internal name of the owner class of this symbol. Only used for {@link
* #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
* #CONSTANT_INTERFACE_METHODREF_TAG}, and {@link #CONSTANT_METHOD_HANDLE_TAG} symbols.
*/
final String owner;
/**
* The name of the class field or method corresponding to this symbol. Only used for {@link
* #CONSTANT_FIELDREF_TAG}, {@link #CONSTANT_METHODREF_TAG}, {@link
* #CONSTANT_INTERFACE_METHODREF_TAG}, {@link #CONSTANT_NAME_AND_TYPE_TAG}, {@link
* #CONSTANT_METHOD_HANDLE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
*/
final String name;
/**
* The string value of this symbol. This is:
*
* <ul>
* <li>a field or method descriptor for {@link #CONSTANT_FIELDREF_TAG}, {@link
* #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG}, {@link
* #CONSTANT_NAME_AND_TYPE_TAG}, {@link #CONSTANT_METHOD_HANDLE_TAG}, {@link
* #CONSTANT_METHOD_TYPE_TAG}, {@link #CONSTANT_DYNAMIC_TAG} and {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
* <li>an arbitrary string for {@link #CONSTANT_UTF8_TAG} and {@link #CONSTANT_STRING_TAG}
* symbols,
* <li>an internal class name for {@link #CONSTANT_CLASS_TAG}, {@link #TYPE_TAG} and {@link
* #UNINITIALIZED_TYPE_TAG} symbols,
* <li>{@literal null} for the other types of symbol.
* </ul>
*/
final String value;
/**
* The numeric value of this symbol. This is:
*
* <ul>
* <li>the symbol's value for {@link #CONSTANT_INTEGER_TAG},{@link #CONSTANT_FLOAT_TAG}, {@link
* #CONSTANT_LONG_TAG}, {@link #CONSTANT_DOUBLE_TAG},
* <li>the CONSTANT_MethodHandle_info reference_kind field value for {@link
* #CONSTANT_METHOD_HANDLE_TAG} symbols,
* <li>the CONSTANT_InvokeDynamic_info bootstrap_method_attr_index field value for {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
* <li>the offset of a bootstrap method in the BootstrapMethods boostrap_methods array, for
* {@link #CONSTANT_DYNAMIC_TAG} or {@link #BOOTSTRAP_METHOD_TAG} symbols,
* <li>the bytecode offset of the NEW instruction that created an {@link
* Frame#ITEM_UNINITIALIZED} type for {@link #UNINITIALIZED_TYPE_TAG} symbols,
* <li>the indices (in the class' type table) of two {@link #TYPE_TAG} source types for {@link
* #MERGED_TYPE_TAG} symbols,
* <li>0 for the other types of symbol.
* </ul>
*/
final long data;
/**
* Additional information about this symbol, generally computed lazily. <i>Warning: the value of
* this field is ignored when comparing Symbol instances</i> (to avoid duplicate entries in a
* SymbolTable). Therefore, this field should only contain data that can be computed from the
* other fields of this class. It contains:
*
* <ul>
* <li>the {@link Type#getArgumentsAndReturnSizes} of the symbol's method descriptor for {@link
* #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols,
* <li>the index in the InnerClasses_attribute 'classes' array (plus one) corresponding to this
* class, for {@link #CONSTANT_CLASS_TAG} symbols,
* <li>the index (in the class' type table) of the merged type of the two source types for
* {@link #MERGED_TYPE_TAG} symbols,
* <li>0 for the other types of symbol, or if this field has not been computed yet.
* </ul>
*/
int info;
/**
* Constructs a new Symbol. This constructor can't be used directly because the Symbol class is
* abstract. Instead, use the factory methods of the {@link SymbolTable} class.
*
* @param index the symbol index in the constant pool, in the BootstrapMethods attribute, or in
* the (ASM specific) type table of a class (depending on 'tag').
* @param tag the symbol type. Must be one of the static tag values defined in this class.
* @param owner The internal name of the symbol's owner class. Maybe {@literal null}.
* @param name The name of the symbol's corresponding class field or method. Maybe {@literal
* null}.
* @param value The string value of this symbol. Maybe {@literal null}.
* @param data The numeric value of this symbol.
*/
Symbol(
final int index,
final int tag,
final String owner,
final String name,
final String value,
final long data) {
this.index = index;
this.tag = tag;
this.owner = owner;
this.name = name;
this.value = value;
this.data = data;
}
/**
* Returns the result {@link Type#getArgumentsAndReturnSizes} on {@link #value}.
*
* @return the result {@link Type#getArgumentsAndReturnSizes} on {@link #value} (memoized in
* {@link #info} for efficiency). This should only be used for {@link
* #CONSTANT_METHODREF_TAG}, {@link #CONSTANT_INTERFACE_METHODREF_TAG} and {@link
* #CONSTANT_INVOKE_DYNAMIC_TAG} symbols.
*/
int getArgumentsAndReturnSizes() {
if (info == 0) {
info = Type.getArgumentsAndReturnSizes(value);
}
return info;
}
}

File diff suppressed because it is too large Load diff

View file

@ -29,7 +29,7 @@
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 INRIA, France Telecom
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -56,147 +56,137 @@
* 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;
/**
* The path to a type argument, wildcard bound, array element type, or static
* inner type within an enclosing type.
* The path to a type argument, wildcard bound, array element type, or static inner type within an
* enclosing type.
*
* @author Eric Bruneton
*/
public class TypePath {
public final class TypePath {
/** A type path step that steps into the element type of an array type. See {@link #getStep}. */
public static final int ARRAY_ELEMENT = 0;
/** A type path step that steps into the nested type of a class type. See {@link #getStep}. */
public static final int INNER_TYPE = 1;
/** A type path step that steps into the bound of a wildcard type. See {@link #getStep}. */
public static final int WILDCARD_BOUND = 2;
/** A type path step that steps into a type argument of a generic type. See {@link #getStep}. */
public static final int TYPE_ARGUMENT = 3;
/**
* A type path step that steps into the element type of an array type. See
* {@link #getStep getStep}.
*/
public final static int ARRAY_ELEMENT = 0;
/**
* A type path step that steps into the nested type of a class type. See
* {@link #getStep getStep}.
*/
public final static int INNER_TYPE = 1;
/**
* A type path step that steps into the bound of a wildcard type. See
* {@link #getStep getStep}.
*/
public final static int WILDCARD_BOUND = 2;
/**
* A type path step that steps into a type argument of a generic type. See
* {@link #getStep getStep}.
*/
public final static int TYPE_ARGUMENT = 3;
/**
* The byte array where the path is stored, in Java class file format.
*/
byte[] b;
/**
* The offset of the first byte of the type path in 'b'.
*/
int offset;
/**
* Creates a new type path.
* The byte array where the 'type_path' structure - as defined in the Java Virtual Machine
* Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the
* structure in this array is given by {@link #typePathOffset}.
*
* @param b
* the byte array containing the type path in Java class file
* format.
* @param offset
* the offset of the first byte of the type path in 'b'.
* @see <a
* href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.2">JVMS
* 4.7.20.2</a>
*/
TypePath(byte[] b, int offset) {
this.b = b;
this.offset = offset;
private final byte[] typePathContainer;
/** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */
private final int typePathOffset;
/**
* Constructs a new TypePath.
*
* @param typePathContainer a byte array containing a type_path JVMS structure.
* @param typePathOffset the offset of the first byte of the type_path structure in
* typePathContainer.
*/
TypePath(final byte[] typePathContainer, final int typePathOffset) {
this.typePathContainer = typePathContainer;
this.typePathOffset = typePathOffset;
}
/**
* Returns the length of this path.
* Returns the length of this path, i.e. its number of steps.
*
* @return the length of this path.
*/
public int getLength() {
return b[offset];
// path_length is stored in the first byte of a type_path.
return typePathContainer[typePathOffset];
}
/**
* Returns the value of the given step of this path.
*
* @param index
* an index between 0 and {@link #getLength()}, exclusive.
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE
* INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
* @param index an index between 0 and {@link #getLength()}, exclusive.
* @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link
* #TYPE_ARGUMENT}.
*/
public int getStep(int index) {
return b[offset + 2 * index + 1];
public int getStep(final int index) {
// Returns the type_path_kind of the path element of the given index.
return typePathContainer[typePathOffset + 2 * index + 1];
}
/**
* Returns the index of the type argument that the given step is stepping
* into. This method should only be used for steps whose value is
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}.
* Returns the index of the type argument that the given step is stepping into. This method should
* only be used for steps whose value is {@link #TYPE_ARGUMENT}.
*
* @param index
* an index between 0 and {@link #getLength()}, exclusive.
* @return the index of the type argument that the given step is stepping
* into.
* @param index an index between 0 and {@link #getLength()}, exclusive.
* @return the index of the type argument that the given step is stepping into.
*/
public int getStepArgument(int index) {
return b[offset + 2 * index + 2];
public int getStepArgument(final int index) {
// Returns the type_argument_index of the path element of the given index.
return typePathContainer[typePathOffset + 2 * index + 2];
}
/**
* Converts a type path in string form, in the format used by
* {@link #toString()}, into a TypePath object.
* Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath
* object.
*
* @param typePath
* a type path in string form, in the format used by
* {@link #toString()}. May be null or empty.
* @return the corresponding TypePath object, or null if the path is empty.
* @param typePath a type path in string form, in the format used by {@link #toString()}. May be
* {@literal null} or empty.
* @return the corresponding TypePath object, or {@literal null} if the path is empty.
*/
public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.length() == 0) {
return null;
}
int n = typePath.length();
ByteVector out = new ByteVector(n);
out.putByte(0);
for (int i = 0; i < n;) {
char c = typePath.charAt(i++);
int typePathLength = typePath.length();
ByteVector output = new ByteVector(typePathLength);
output.putByte(0);
int typePathIndex = 0;
while (typePathIndex < typePathLength) {
char c = typePath.charAt(typePathIndex++);
if (c == '[') {
out.put11(ARRAY_ELEMENT, 0);
output.put11(ARRAY_ELEMENT, 0);
} else if (c == '.') {
out.put11(INNER_TYPE, 0);
output.put11(INNER_TYPE, 0);
} else if (c == '*') {
out.put11(WILDCARD_BOUND, 0);
output.put11(WILDCARD_BOUND, 0);
} else if (c >= '0' && c <= '9') {
int typeArg = c - '0';
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') {
while (typePathIndex < typePathLength) {
c = typePath.charAt(typePathIndex++);
if (c >= '0' && c <= '9') {
typeArg = typeArg * 10 + c - '0';
i += 1;
}
if (i < n && typePath.charAt(i) == ';') {
i += 1;
}
out.put11(TYPE_ARGUMENT, typeArg);
} else if (c == ';') {
break;
} else {
throw new IllegalArgumentException();
}
}
out.data[0] = (byte) (out.length / 2);
return new TypePath(out.data, 0);
output.put11(TYPE_ARGUMENT, typeArg);
} else {
throw new IllegalArgumentException();
}
}
output.data[0] = (byte) (output.length / 2);
return new TypePath(output.data, 0);
}
/**
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT
* ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE
* INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps
* with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type
* argument index in decimal form followed by ';'.
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented
* with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link
* #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
*/
@Override
public String toString() {
@ -217,9 +207,25 @@ public class TypePath {
result.append(getStepArgument(i)).append(';');
break;
default:
result.append('_');
throw new AssertionError();
}
}
return result.toString();
}
/**
* Puts the type_path JVMS structure corresponding to the given TypePath into the given
* ByteVector.
*
* @param typePath a TypePath instance, or {@literal null} for empty paths.
* @param output where the type path must be put.
*/
static void put(final TypePath typePath, final ByteVector output) {
if (typePath == null) {
output.putByte(0);
} else {
int length = typePath.typePathContainer[typePath.typePathOffset] * 2 + 1;
output.putByteArray(typePath.typePathContainer, typePath.typePathOffset, length);
}
}
}

View file

@ -29,7 +29,7 @@
* file:
*
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2013 INRIA, France Telecom
* Copyright (c) 2000-2011 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -56,426 +56,411 @@
* 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 reference to a type appearing in a class, field or method declaration, or
* on an instruction. Such a reference designates the part of the class where
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws'
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable
* declaration, etc).
* A reference to a type appearing in a class, field or method declaration, or on an instruction.
* Such a reference designates the part of the class where the referenced type is appearing (e.g. an
* 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a
* local variable declaration, etc).
*
* @author Eric Bruneton
*/
public class TypeReference {
/**
* The sort of type references that target a type parameter of a generic
* class. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic class. See {@link
* #getSort}.
*/
public final static int CLASS_TYPE_PARAMETER = 0x00;
public static final int CLASS_TYPE_PARAMETER = 0x00;
/**
* The sort of type references that target a type parameter of a generic
* method. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic method. See {@link
* #getSort}.
*/
public final static int METHOD_TYPE_PARAMETER = 0x01;
public static final int METHOD_TYPE_PARAMETER = 0x01;
/**
* The sort of type references that target the super class of a class or one
* of the interfaces it implements. See {@link #getSort getSort}.
* The sort of type references that target the super class of a class or one of the interfaces it
* implements. See {@link #getSort}.
*/
public final static int CLASS_EXTENDS = 0x10;
public static final int CLASS_EXTENDS = 0x10;
/**
* The sort of type references that target a bound of a type parameter of a
* generic class. See {@link #getSort getSort}.
* The sort of type references that target a bound of a type parameter of a generic class. See
* {@link #getSort}.
*/
public final static int CLASS_TYPE_PARAMETER_BOUND = 0x11;
public static final int CLASS_TYPE_PARAMETER_BOUND = 0x11;
/**
* The sort of type references that target a bound of a type parameter of a
* generic method. See {@link #getSort getSort}.
* The sort of type references that target a bound of a type parameter of a generic method. See
* {@link #getSort}.
*/
public final static int METHOD_TYPE_PARAMETER_BOUND = 0x12;
public static final int METHOD_TYPE_PARAMETER_BOUND = 0x12;
/** The sort of type references that target the type of a field. See {@link #getSort}. */
public static final int FIELD = 0x13;
/** The sort of type references that target the return type of a method. See {@link #getSort}. */
public static final int METHOD_RETURN = 0x14;
/**
* The sort of type references that target the type of a field. See
* {@link #getSort getSort}.
* The sort of type references that target the receiver type of a method. See {@link #getSort}.
*/
public final static int FIELD = 0x13;
public static final int METHOD_RECEIVER = 0x15;
/**
* The sort of type references that target the return type of a method. See
* {@link #getSort getSort}.
* The sort of type references that target the type of a formal parameter of a method. See {@link
* #getSort}.
*/
public final static int METHOD_RETURN = 0x14;
public static final int METHOD_FORMAL_PARAMETER = 0x16;
/**
* The sort of type references that target the receiver type of a method.
* See {@link #getSort getSort}.
* The sort of type references that target the type of an exception declared in the throws clause
* of a method. See {@link #getSort}.
*/
public final static int METHOD_RECEIVER = 0x15;
public static final int THROWS = 0x17;
/**
* The sort of type references that target the type of a formal parameter of
* a method. See {@link #getSort getSort}.
* The sort of type references that target the type of a local variable in a method. See {@link
* #getSort}.
*/
public final static int METHOD_FORMAL_PARAMETER = 0x16;
public static final int LOCAL_VARIABLE = 0x40;
/**
* The sort of type references that target the type of an exception declared
* in the throws clause of a method. See {@link #getSort getSort}.
* The sort of type references that target the type of a resource variable in a method. See {@link
* #getSort}.
*/
public final static int THROWS = 0x17;
public static final int RESOURCE_VARIABLE = 0x41;
/**
* The sort of type references that target the type of a local variable in a
* method. See {@link #getSort getSort}.
* The sort of type references that target the type of the exception of a 'catch' clause in a
* method. See {@link #getSort}.
*/
public final static int LOCAL_VARIABLE = 0x40;
public static final int EXCEPTION_PARAMETER = 0x42;
/**
* The sort of type references that target the type of a resource variable
* in a method. See {@link #getSort getSort}.
* The sort of type references that target the type declared in an 'instanceof' instruction. See
* {@link #getSort}.
*/
public final static int RESOURCE_VARIABLE = 0x41;
public static final int INSTANCEOF = 0x43;
/**
* The sort of type references that target the type of the exception of a
* 'catch' clause in a method. See {@link #getSort getSort}.
* The sort of type references that target the type of the object created by a 'new' instruction.
* See {@link #getSort}.
*/
public final static int EXCEPTION_PARAMETER = 0x42;
public static final int NEW = 0x44;
/**
* The sort of type references that target the type declared in an
* 'instanceof' instruction. See {@link #getSort getSort}.
* The sort of type references that target the receiver type of a constructor reference. See
* {@link #getSort}.
*/
public final static int INSTANCEOF = 0x43;
public static final int CONSTRUCTOR_REFERENCE = 0x45;
/**
* The sort of type references that target the type of the object created by
* a 'new' instruction. See {@link #getSort getSort}.
* The sort of type references that target the receiver type of a method reference. See {@link
* #getSort}.
*/
public final static int NEW = 0x44;
public static final int METHOD_REFERENCE = 0x46;
/**
* The sort of type references that target the receiver type of a
* constructor reference. See {@link #getSort getSort}.
* The sort of type references that target the type declared in an explicit or implicit cast
* instruction. See {@link #getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE = 0x45;
public static final int CAST = 0x47;
/**
* The sort of type references that target the receiver type of a method
* reference. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic constructor in a
* constructor call. See {@link #getSort}.
*/
public final static int METHOD_REFERENCE = 0x46;
public static final int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
/**
* The sort of type references that target the type declared in an explicit
* or implicit cast instruction. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic method in a method call.
* See {@link #getSort}.
*/
public final static int CAST = 0x47;
public static final int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor call. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic constructor in a
* constructor reference. See {@link #getSort}.
*/
public final static int CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48;
public static final int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/**
* The sort of type references that target a type parameter of a generic
* method in a method call. See {@link #getSort getSort}.
* The sort of type references that target a type parameter of a generic method in a method
* reference. See {@link #getSort}.
*/
public final static int METHOD_INVOCATION_TYPE_ARGUMENT = 0x49;
public static final int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/**
* The sort of type references that target a type parameter of a generic
* constructor in a constructor reference. See {@link #getSort getSort}.
*/
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A;
/**
* The sort of type references that target a type parameter of a generic
* method in a method reference. See {@link #getSort getSort}.
*/
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B;
/**
* The type reference value in Java class file format.
*/
private int value;
/**
* Creates a new TypeReference.
* The target_type and target_info structures - as defined in the Java Virtual Machine
* Specification (JVMS) - corresponding to this type reference. target_type uses one byte, and all
* the target_info union fields use up to 3 bytes (except localvar_target, handled with the
* specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can
* be stored in an int.
*
* @param typeRef
* the int encoded value of the type reference, as received in a
* visit method related to type annotations, like
* visitTypeAnnotation.
* <p>This int field stores target_type (called the TypeReference 'sort' in the public API of this
* class) in its most significant byte, followed by the target_info fields. Depending on
* target_type, 1, 2 or even 3 least significant bytes of this field are unused. target_info
* fields which reference bytecode offsets are set to 0 (these offsets are ignored in ClassReader,
* and recomputed in MethodWriter).
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20">JVMS
* 4.7.20</a>
* @see <a
* href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.1">JVMS
* 4.7.20.1</a>
*/
public TypeReference(int typeRef) {
this.value = typeRef;
private final int targetTypeAndInfo;
/**
* Constructs a new TypeReference.
*
* @param typeRef the int encoded value of the type reference, as received in a visit method
* related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}.
*/
public TypeReference(final int typeRef) {
this.targetTypeAndInfo = typeRef;
}
/**
* Returns a type reference of the given sort.
*
* @param sort
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
* #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link
* #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}.
* @return a type reference of the given sort.
*/
public static TypeReference newTypeReference(int sort) {
public static TypeReference newTypeReference(final int sort) {
return new TypeReference(sort << 24);
}
/**
* Returns a reference to a type parameter of a generic class or method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
* @param paramIndex the type parameter index.
* @return a reference to the given generic class or method type parameter.
*/
public static TypeReference newTypeParameterReference(int sort,
int paramIndex) {
public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16));
}
/**
* Returns a reference to a type parameter bound of a generic class or
* method.
* Returns a reference to a type parameter bound of a generic class or method.
*
* @param sort
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}.
* @param paramIndex
* the type parameter index.
* @param boundIndex
* the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter
* bound.
* @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
* @param paramIndex the type parameter index.
* @param boundIndex the type bound index within the above type parameters.
* @return a reference to the given generic class or method type parameter bound.
*/
public static TypeReference newTypeParameterBoundReference(int sort,
int paramIndex, int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)
| (boundIndex << 8));
public static TypeReference newTypeParameterBoundReference(
final int sort, final int paramIndex, final int boundIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
}
/**
* Returns a reference to the super class or to an interface of the
* 'implements' clause of a class.
* Returns a reference to the super class or to an interface of the 'implements' clause of a
* class.
*
* @param itfIndex
* the index of an interface in the 'implements' clause of a
* class, or -1 to reference the super class of the class.
* @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to
* reference the super class of the class.
* @return a reference to the given super type of a class.
*/
public static TypeReference newSuperTypeReference(int itfIndex) {
itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
public static TypeReference newSuperTypeReference(final int itfIndex) {
return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8));
}
/**
* Returns a reference to the type of a formal parameter of a method.
*
* @param paramIndex
* the formal parameter index.
*
* @param paramIndex the formal parameter index.
* @return a reference to the type of the given method formal parameter.
*/
public static TypeReference newFormalParameterReference(int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24)
| (paramIndex << 16));
public static TypeReference newFormalParameterReference(final int paramIndex) {
return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
}
/**
* Returns a reference to the type of an exception, in a 'throws' clause of
* a method.
*
* @param exceptionIndex
* the index of an exception in a 'throws' clause of a method.
* Returns a reference to the type of an exception, in a 'throws' clause of a method.
*
* @param exceptionIndex the index of an exception in a 'throws' clause of a method.
* @return a reference to the type of the given exception.
*/
public static TypeReference newExceptionReference(int exceptionIndex) {
public static TypeReference newExceptionReference(final int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
}
/**
* Returns a reference to the type of the exception declared in a 'catch'
* clause of a method.
*
* @param tryCatchBlockIndex
* the index of a try catch block (using the order in which they
* are visited with visitTryCatchBlock).
* Returns a reference to the type of the exception declared in a 'catch' clause of a method.
*
* @param tryCatchBlockIndex the index of a try catch block (using the order in which they are
* visited with visitTryCatchBlock).
* @return a reference to the type of the given exception.
*/
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24)
| (tryCatchBlockIndex << 8));
public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
}
/**
* Returns a reference to the type of a type argument in a constructor or
* method call or reference.
*
* @param sort
* {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex
* the type argument index.
* Returns a reference to the type of a type argument in a constructor or method call or
* reference.
*
* @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
* #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
* #METHOD_REFERENCE_TYPE_ARGUMENT}.
* @param argIndex the type argument index.
* @return a reference to the type of the given type argument.
*/
public static TypeReference newTypeArgumentReference(int sort, int argIndex) {
public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) {
return new TypeReference((sort << 24) | argIndex);
}
/**
* Returns the sort of this type reference.
*
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_EXTENDS CLASS_EXTENDS},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND},
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND},
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN},
* {@link #METHOD_RECEIVER METHOD_RECEIVER},
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER},
* {@link #THROWS THROWS}, {@link #LOCAL_VARIABLE LOCAL_VARIABLE},
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE},
* {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER},
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW},
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE},
* {@link #METHOD_REFERENCE METHOD_REFERENCE}, {@link #CAST CAST},
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT
* METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* METHOD_REFERENCE_TYPE_ARGUMENT}.
* @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link
* #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND},
* {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
* #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link
* #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW},
* {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link
* #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
* #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
*/
public int getSort() {
return value >>> 24;
return targetTypeAndInfo >>> 24;
}
/**
* Returns the index of the type parameter referenced by this type
* reference. This method must only be used for type references whose sort
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER},
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER},
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
* Returns the index of the type parameter referenced by this type reference. This method must
* only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link
* #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
* #METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter index.
*/
public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16;
return (targetTypeAndInfo & 0x00FF0000) >> 16;
}
/**
* Returns the index of the type parameter bound, within the type parameter
* {@link #getTypeParameterIndex}, referenced by this type reference. This
* method must only be used for type references whose sort is
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}.
* Returns the index of the type parameter bound, within the type parameter {@link
* #getTypeParameterIndex}, referenced by this type reference. This method must only be used for
* type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
* #METHOD_TYPE_PARAMETER_BOUND}.
*
* @return a type parameter bound index.
*/
public int getTypeParameterBoundIndex() {
return (value & 0x0000FF00) >> 8;
return (targetTypeAndInfo & 0x0000FF00) >> 8;
}
/**
* Returns the index of the "super type" of a class that is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}.
* Returns the index of the "super type" of a class that is referenced by this type reference.
* This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}.
*
* @return the index of an interface in the 'implements' clause of a class,
* or -1 if this type reference references the type of the super
* class.
* @return the index of an interface in the 'implements' clause of a class, or -1 if this type
* reference references the type of the super class.
*/
public int getSuperTypeIndex() {
return (short) ((value & 0x00FFFF00) >> 8);
return (short) ((targetTypeAndInfo & 0x00FFFF00) >> 8);
}
/**
* Returns the index of the formal parameter whose type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}.
* Returns the index of the formal parameter whose type is referenced by this type reference. This
* method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}.
*
* @return a formal parameter index.
*/
public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16;
return (targetTypeAndInfo & 0x00FF0000) >> 16;
}
/**
* Returns the index of the exception, in a 'throws' clause of a method,
* whose type is referenced by this type reference. This method must only be
* used for type references whose sort is {@link #THROWS THROWS}.
* Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced
* by this type reference. This method must only be used for type references whose sort is {@link
* #THROWS}.
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getExceptionIndex() {
return (value & 0x00FFFF00) >> 8;
return (targetTypeAndInfo & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the try catch block (using the order in which they
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by
* this type reference. This method must only be used for type references
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} .
* Returns the index of the try catch block (using the order in which they are visited with
* visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must
* only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} .
*
* @return the index of an exception in the 'throws' clause of a method.
*/
public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8;
return (targetTypeAndInfo & 0x00FFFF00) >> 8;
}
/**
* Returns the index of the type argument referenced by this type reference.
* This method must only be used for type references whose sort is
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT},
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT},
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
* Returns the index of the type argument referenced by this type reference. This method must only
* be used for type references whose sort is {@link #CAST}, {@link
* #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
* #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
*
* @return a type parameter index.
*/
public int getTypeArgumentIndex() {
return value & 0xFF;
return targetTypeAndInfo & 0xFF;
}
/**
* Returns the int encoded value of this type reference, suitable for use in
* visit methods related to type annotations, like visitTypeAnnotation.
* Returns the int encoded value of this type reference, suitable for use in visit methods related
* to type annotations, like visitTypeAnnotation.
*
* @return the int encoded value of this type reference.
*/
public int getValue() {
return value;
return targetTypeAndInfo;
}
/**
* Puts the given target_type and target_info JVMS structures into the given ByteVector.
*
* @param targetTypeAndInfo a target_type and a target_info structures encoded as in {@link
* #targetTypeAndInfo}. LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
* @param output where the type reference must be put.
*/
static void putTarget(final int targetTypeAndInfo, final ByteVector output) {
switch (targetTypeAndInfo >>> 24) {
case CLASS_TYPE_PARAMETER:
case METHOD_TYPE_PARAMETER:
case METHOD_FORMAL_PARAMETER:
output.putShort(targetTypeAndInfo >>> 16);
break;
case FIELD:
case METHOD_RETURN:
case METHOD_RECEIVER:
output.putByte(targetTypeAndInfo >>> 24);
break;
case CAST:
case CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
case METHOD_INVOCATION_TYPE_ARGUMENT:
case CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
case METHOD_REFERENCE_TYPE_ARGUMENT:
output.putInt(targetTypeAndInfo);
break;
case CLASS_EXTENDS:
case CLASS_TYPE_PARAMETER_BOUND:
case METHOD_TYPE_PARAMETER_BOUND:
case THROWS:
case EXCEPTION_PARAMETER:
case INSTANCEOF:
case NEW:
case CONSTRUCTOR_REFERENCE:
case METHOD_REFERENCE:
output.put12(targetTypeAndInfo >>> 24, (targetTypeAndInfo & 0xFFFF00) >> 8);
break;
default:
throw new IllegalArgumentException();
}
}
}

View file

@ -62,7 +62,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.ConstantDynamic;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -70,111 +70,126 @@ import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
/**
* A {@link jdk.internal.org.objectweb.asm.MethodVisitor} to insert before, after and around
* advices in methods and constructors.
* <p>
* The behavior for constructors is like this:
* <ol>
*
* <li>as long as the INVOKESPECIAL for the object initialization has not been
* reached, every bytecode instruction is dispatched in the ctor code visitor</li>
*
* <li>when this one is reached, it is only added in the ctor code visitor and a
* JP invoke is added</li>
*
* <li>after that, only the other code visitor receives the instructions</li>
*
* </ol>
* A {@link MethodVisitor} to insert before, after and around advices in methods and constructors.
* For constructors, the code keeps track of the elements on the stack in order to detect when the
* super class constructor is called (note that there can be multiple such calls in different
* branches). {@code onMethodEnter} is called after each super class constructor call, because the
* object cannot be used before it is properly initialized.
*
* @author Eugene Kuleshov
* @author Eric Bruneton
*/
public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes {
private static final Object THIS = new Object();
/** The "uninitialized this" value. */
private static final Object UNINITIALIZED_THIS = new Object();
/** Any value other than "uninitialized this". */
private static final Object OTHER = new Object();
/** Prefix of the error message when invalid opcodes are found. */
private static final String INVALID_OPCODE = "Invalid opcode ";
/** The access flags of the visited method. */
protected int methodAccess;
/** The descriptor of the visited method. */
protected String methodDesc;
private boolean constructor;
private boolean superInitialized;
private List<Object> stackFrame;
private Map<Label, List<Object>> branches;
/** Whether the visited method is a constructor. */
private final boolean isConstructor;
/**
* Creates a new {@link AdviceAdapter}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param mv
* 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.
* @param desc
* the method's descriptor (see {@link Type Type}).
* Whether the super class constructor has been called (if the visited method is a constructor),
* at the current instruction. There can be multiple call sites to the super constructor (e.g. for
* Java code such as {@code super(expr ? value1 : value2);}), in different branches. When scanning
* the bytecode linearly, we can move from one branch where the super constructor has been called
* to another where it has not been called yet. Therefore, this value can change from false to
* true, and vice-versa.
*/
protected AdviceAdapter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc) {
super(api, mv, access, name, desc);
private boolean superClassConstructorCalled;
/**
* The values on the current execution stack frame (long and double are represented by two
* elements). Each value is either {@link #UNINITIALIZED_THIS} (for the uninitialized this value),
* or {@link #OTHER} (for any other value). This field is only maintained for constructors, in
* branches where the super class constructor has not been called yet.
*/
private List<Object> stackFrame;
/**
* The stack map frames corresponding to the labels of the forward jumps made *before* the super
* class constructor has been called (note that the Java Virtual Machine forbids backward jumps
* before the super class constructor is called). Note that by definition (cf. the 'before'), when
* we reach a label from this map, {@link #superClassConstructorCalled} must be reset to false.
* This field is only maintained for constructors.
*/
private Map<Label, List<Object>> forwardJumpStackFrames;
/**
* Constructs a new {@link AdviceAdapter}.
*
* @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 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.
* @param descriptor the method's descriptor (see {@link Type Type}).
*/
protected AdviceAdapter(
final int api,
final MethodVisitor methodVisitor,
final int access,
final String name,
final String descriptor) {
super(api, methodVisitor, access, name, descriptor);
methodAccess = access;
methodDesc = desc;
constructor = "<init>".equals(name);
methodDesc = descriptor;
isConstructor = "<init>".equals(name);
}
@Override
public void visitCode() {
mv.visitCode();
if (constructor) {
super.visitCode();
if (isConstructor) {
stackFrame = new ArrayList<Object>();
branches = new HashMap<Label, List<Object>>();
forwardJumpStackFrames = new HashMap<Label, List<Object>>();
} else {
superInitialized = true;
onMethodEnter();
}
}
@Override
public void visitLabel(final Label label) {
mv.visitLabel(label);
if (constructor && branches != null) {
List<Object> frame = branches.get(label);
if (frame != null) {
stackFrame = frame;
branches.remove(label);
super.visitLabel(label);
if (isConstructor && forwardJumpStackFrames != null) {
List<Object> labelStackFrame = forwardJumpStackFrames.get(label);
if (labelStackFrame != null) {
stackFrame = labelStackFrame;
superClassConstructorCalled = false;
forwardJumpStackFrames.remove(label);
}
}
}
@Override
public void visitInsn(final int opcode) {
if (constructor) {
int s;
if (isConstructor && !superClassConstructorCalled) {
int stackSize;
switch (opcode) {
case IRETURN:
case FRETURN:
case ARETURN:
case LRETURN:
case DRETURN:
throw new IllegalArgumentException("Invalid return in constructor");
case RETURN: // empty stack
onMethodExit(opcode);
break;
case IRETURN: // 1 before n/a after
case FRETURN: // 1 before n/a after
case ARETURN: // 1 before n/a after
case ATHROW: // 1 before n/a after
popValue();
onMethodExit(opcode);
break;
case LRETURN: // 2 before n/a after
case DRETURN: // 2 before n/a after
popValue();
popValue();
onMethodExit(opcode);
break;
case NOP:
case LALOAD: // remove 2 add 2
case DALOAD: // remove 2 add 2
@ -292,33 +307,35 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
pushValue(peekValue());
break;
case DUP_X1:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackSize = stackFrame.size();
stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
break;
case DUP_X2:
s = stackFrame.size();
stackFrame.add(s - 3, stackFrame.get(s - 1));
stackSize = stackFrame.size();
stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
break;
case DUP2:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackSize = stackFrame.size();
stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
break;
case DUP2_X1:
s = stackFrame.size();
stackFrame.add(s - 3, stackFrame.get(s - 1));
stackFrame.add(s - 3, stackFrame.get(s - 1));
stackSize = stackFrame.size();
stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
stackFrame.add(stackSize - 3, stackFrame.get(stackSize - 1));
break;
case DUP2_X2:
s = stackFrame.size();
stackFrame.add(s - 4, stackFrame.get(s - 1));
stackFrame.add(s - 4, stackFrame.get(s - 1));
stackSize = stackFrame.size();
stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1));
stackFrame.add(stackSize - 4, stackFrame.get(stackSize - 1));
break;
case SWAP:
s = stackFrame.size();
stackFrame.add(s - 2, stackFrame.get(s - 1));
stackFrame.remove(s);
stackSize = stackFrame.size();
stackFrame.add(stackSize - 2, stackFrame.get(stackSize - 1));
stackFrame.remove(stackSize);
break;
default:
throw new IllegalArgumentException(INVALID_OPCODE + opcode);
}
} else {
switch (opcode) {
@ -331,15 +348,17 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
case ATHROW:
onMethodExit(opcode);
break;
default:
break;
}
}
mv.visitInsn(opcode);
super.visitInsn(opcode);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
super.visitVarInsn(opcode, var);
if (constructor) {
if (isConstructor && !superClassConstructorCalled) {
switch (opcode) {
case ILOAD:
case FLOAD:
@ -351,7 +370,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
pushValue(OTHER);
break;
case ALOAD:
pushValue(var == 0 ? THIS : OTHER);
pushValue(var == 0 ? UNINITIALIZED_THIS : OTHER);
break;
case ASTORE:
case ISTORE:
@ -363,17 +382,19 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
popValue();
popValue();
break;
default:
throw new IllegalArgumentException(INVALID_OPCODE + opcode);
}
}
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
mv.visitFieldInsn(opcode, owner, name, desc);
if (constructor) {
char c = desc.charAt(0);
boolean longOrDouble = c == 'J' || c == 'D';
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
super.visitFieldInsn(opcode, owner, name, descriptor);
if (isConstructor && !superClassConstructorCalled) {
char firstDescriptorChar = descriptor.charAt(0);
boolean longOrDouble = firstDescriptorChar == 'J' || firstDescriptorChar == 'D';
switch (opcode) {
case GETSTATIC:
pushValue(OTHER);
@ -394,39 +415,43 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
popValue();
}
break;
// case GETFIELD:
default:
case GETFIELD:
if (longOrDouble) {
pushValue(OTHER);
}
break;
default:
throw new IllegalArgumentException(INVALID_OPCODE + opcode);
}
}
}
@Override
public void visitIntInsn(final int opcode, final int operand) {
mv.visitIntInsn(opcode, operand);
if (constructor && opcode != NEWARRAY) {
super.visitIntInsn(opcode, operand);
if (isConstructor && !superClassConstructorCalled && opcode != NEWARRAY) {
pushValue(OTHER);
}
}
@Override
public void visitLdcInsn(final Object cst) {
mv.visitLdcInsn(cst);
if (constructor) {
public void visitLdcInsn(final Object value) {
super.visitLdcInsn(value);
if (isConstructor && !superClassConstructorCalled) {
pushValue(OTHER);
if (cst instanceof Double || cst instanceof Long) {
if (value instanceof Double
|| value instanceof Long
|| (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
pushValue(OTHER);
}
}
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
mv.visitMultiANewArrayInsn(desc, dims);
if (constructor) {
for (int i = 0; i < dims; i++) {
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
super.visitMultiANewArrayInsn(descriptor, numDimensions);
if (isConstructor && !superClassConstructorCalled) {
for (int i = 0; i < numDimensions; i++) {
popValue();
}
pushValue(OTHER);
@ -435,66 +460,70 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitTypeInsn(final int opcode, final String type) {
mv.visitTypeInsn(opcode, type);
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
if (constructor && opcode == NEW) {
super.visitTypeInsn(opcode, type);
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack.
if (isConstructor && !superClassConstructorCalled && opcode == NEW) {
pushValue(OTHER);
}
}
/**
* 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 desc) {
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
mv.visitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, descriptor);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
doVisitMethodInsn(opcode, descriptor);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
if (constructor) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
private void doVisitMethodInsn(final int opcode, final String descriptor) {
if (isConstructor && !superClassConstructorCalled) {
for (Type argumentType : Type.getArgumentTypes(descriptor)) {
popValue();
if (types[i].getSize() == 2) {
if (argumentType.getSize() == 2) {
popValue();
}
}
switch (opcode) {
// case INVOKESTATIC:
// break;
case INVOKEINTERFACE:
case INVOKEVIRTUAL:
popValue(); // objectref
popValue();
break;
case INVOKESPECIAL:
Object type = popValue(); // objectref
if (type == THIS && !superInitialized) {
Object value = popValue();
if (value == UNINITIALIZED_THIS && !superClassConstructorCalled) {
superClassConstructorCalled = true;
onMethodEnter();
superInitialized = true;
// once super has been initialized it is no longer
// necessary to keep track of stack state
constructor = false;
}
break;
default:
break;
}
Type returnType = Type.getReturnType(desc);
Type returnType = Type.getReturnType(descriptor);
if (returnType != Type.VOID_TYPE) {
pushValue(OTHER);
if (returnType.getSize() == 2) {
@ -505,32 +534,19 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
if (constructor) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
popValue();
if (types[i].getSize() == 2) {
popValue();
}
}
Type returnType = Type.getReturnType(desc);
if (returnType != Type.VOID_TYPE) {
pushValue(OTHER);
if (returnType.getSize() == 2) {
pushValue(OTHER);
}
}
}
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
doVisitMethodInsn(Opcodes.INVOKEDYNAMIC, descriptor);
}
@Override
public void visitJumpInsn(final int opcode, final Label label) {
mv.visitJumpInsn(opcode, label);
if (constructor) {
super.visitJumpInsn(opcode, label);
if (isConstructor && !superClassConstructorCalled) {
switch (opcode) {
case IFEQ:
case IFNE:
@ -556,54 +572,63 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
case JSR:
pushValue(OTHER);
break;
default:
break;
}
addBranch(label);
addForwardJump(label);
}
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
if (constructor) {
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
super.visitLookupSwitchInsn(dflt, keys, labels);
if (isConstructor && !superClassConstructorCalled) {
popValue();
addBranches(dflt, labels);
addForwardJumps(dflt, labels);
}
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
if (constructor) {
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
super.visitTableSwitchInsn(min, max, dflt, labels);
if (isConstructor && !superClassConstructorCalled) {
popValue();
addBranches(dflt, labels);
addForwardJumps(dflt, labels);
}
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type);
if (constructor && !branches.containsKey(handler)) {
List<Object> stackFrame = new ArrayList<Object>();
stackFrame.add(OTHER);
branches.put(handler, stackFrame);
// By definition of 'forwardJumpStackFrames', 'handler' should be pushed only if there is an
// instruction between 'start' and 'end' at which the super class constructor is not yet
// called. Unfortunately, try catch blocks must be visited before their labels, so we have no
// way to know this at this point. Instead, we suppose that the super class constructor has not
// been called at the start of *any* exception handler. If this is wrong, normally there should
// not be a second super class constructor call in the exception handler (an object can't be
// 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>();
handlerStackFrame.add(OTHER);
forwardJumpStackFrames.put(handler, handlerStackFrame);
}
}
private void addBranches(final Label dflt, final Label[] labels) {
addBranch(dflt);
for (int i = 0; i < labels.length; i++) {
addBranch(labels[i]);
private void addForwardJumps(final Label dflt, final Label[] labels) {
addForwardJump(dflt);
for (Label label : labels) {
addForwardJump(label);
}
}
private void addBranch(final Label label) {
if (branches.containsKey(label)) {
private void addForwardJump(final Label label) {
if (forwardJumpStackFrames.containsKey(label)) {
return;
}
branches.put(label, new ArrayList<Object>(stackFrame));
forwardJumpStackFrames.put(label, new ArrayList<Object>(stackFrame));
}
private Object popValue() {
@ -614,34 +639,33 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
return stackFrame.get(stackFrame.size() - 1);
}
private void pushValue(final Object o) {
stackFrame.add(o);
private void pushValue(final Object value) {
stackFrame.add(value);
}
/**
* Called at the beginning of the method or after super class call in
* the constructor. <br>
* <br>
*
* <i>Custom code can use or change all the local variables, but should not
* change state of the stack.</i>
* Generates the "before" advice for the visited method. The default implementation of this method
* does nothing. Subclasses can use or change all the local variables, but should not change state
* of the stack. This method is called at the beginning of the method or after super class
* constructor has been called (in constructors).
*/
protected void onMethodEnter() {
}
protected void onMethodEnter() {}
/**
* Called before explicit exit from the method using either return or throw.
* Top element on the stack contains the return value or exception instance.
* Generates the "after" advice for the visited method. The default implementation of this method
* does nothing. Subclasses can use or change all the local variables, but should not change state
* of the stack. This method is called at the end of the method, just before return and athrow
* instructions. The top element on the stack contains the return value or the exception instance.
* For example:
*
* <pre>
* public void onMethodExit(int opcode) {
* if(opcode==RETURN) {
* public void onMethodExit(final int opcode) {
* if (opcode == RETURN) {
* visitInsn(ACONST_NULL);
* } else if(opcode==ARETURN || opcode==ATHROW) {
* } else if (opcode == ARETURN || opcode == ATHROW) {
* dup();
* } else {
* if(opcode==LRETURN || opcode==DRETURN) {
* if (opcode == LRETURN || opcode == DRETURN) {
* dup2();
* } else {
* dup();
@ -652,24 +676,15 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
* visitMethodInsn(INVOKESTATIC, owner, "onExit", "(Ljava/lang/Object;I)V");
* }
*
* // an actual call back method
* public static void onExit(Object param, int opcode) {
* // An actual call back method.
* public static void onExit(final Object exitValue, final int opcode) {
* ...
* }
* </pre>
*
* <br>
* <br>
*
* <i>Custom code can use or change all the local variables, but should not
* change state of the stack.</i>
*
* @param opcode
* one of the RETURN, IRETURN, FRETURN, ARETURN, LRETURN, DRETURN
* or ATHROW
*
* @param opcode one of {@link Opcodes#RETURN}, {@link Opcodes#IRETURN}, {@link Opcodes#FRETURN},
* {@link Opcodes#ARETURN}, {@link Opcodes#LRETURN}, {@link Opcodes#DRETURN} or {@link
* Opcodes#ATHROW}.
*/
protected void onMethodExit(int opcode) {
}
// TODO onException, onMethodCall
protected void onMethodExit(final int opcode) {}
}

View file

@ -56,53 +56,78 @@
* 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;
/**
* An {@link AnnotationVisitor} adapter for type remapping.
* An {@link AnnotationVisitor} that remaps types with a {@link Remapper}.
*
* @author Eugene Kuleshov
*/
public class AnnotationRemapper extends AnnotationVisitor {
/** The remapper used to remap the types in the visited annotation. */
protected final Remapper remapper;
public AnnotationRemapper(final AnnotationVisitor av,
final Remapper remapper) {
this(Opcodes.ASM6, av, remapper);
/**
* Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #AnnotationRemapper(int,AnnotationVisitor,Remapper)} version.
*
* @param annotationVisitor the annotation visitor this remapper must deleted to.
* @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);
}
protected AnnotationRemapper(final int api, final AnnotationVisitor av,
final Remapper remapper) {
super(api, av);
/**
* 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}.
* @param annotationVisitor the annotation visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited annotation.
*/
protected AnnotationRemapper(
final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) {
super(api, annotationVisitor);
this.remapper = remapper;
}
@Override
public void visit(String name, Object value) {
av.visit(name, remapper.mapValue(value));
public void visit(final String name, final Object value) {
super.visit(name, remapper.mapValue(value));
}
@Override
public void visitEnum(String name, String desc, String value) {
av.visitEnum(name, remapper.mapDesc(desc), value);
public void visitEnum(final String name, final String descriptor, final String value) {
super.visitEnum(name, remapper.mapDesc(descriptor), value);
}
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
remapper));
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
AnnotationVisitor annotationVisitor = super.visitAnnotation(name, remapper.mapDesc(descriptor));
if (annotationVisitor == null) {
return null;
} else {
return annotationVisitor == av
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
}
@Override
public AnnotationVisitor visitArray(String name) {
AnnotationVisitor v = av.visitArray(name);
return v == null ? null : (v == av ? this : new AnnotationRemapper(v,
remapper));
public AnnotationVisitor visitArray(final String name) {
AnnotationVisitor annotationVisitor = super.visitArray(name);
if (annotationVisitor == null) {
return null;
} else {
return annotationVisitor == av
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
}
}

View file

@ -56,11 +56,9 @@
* 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 java.util.List;
import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassVisitor;
@ -71,117 +69,198 @@ import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link ClassVisitor} for type remapping.
* A {@link ClassVisitor} that remaps types with a {@link Remapper}.
*
* @author Eugene Kuleshov
*/
public class ClassRemapper extends ClassVisitor {
/** The remapper used to remap the types in the visited class. */
protected final Remapper remapper;
/** The internal name of the visited class. */
protected String className;
public ClassRemapper(final ClassVisitor cv, final Remapper remapper) {
this(Opcodes.ASM6, cv, remapper);
/**
* Constructs a new {@link ClassRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #ClassRemapper(int,ClassVisitor,Remapper)} version.
*
* @param classVisitor the class visitor this remapper must deleted to.
* @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);
}
protected ClassRemapper(final int api, final ClassVisitor cv,
final Remapper remapper) {
super(api, cv);
/**
* Constructs a new {@link ClassRemapper}.
*
* @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}.
* @param classVisitor the class visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited class.
*/
protected ClassRemapper(final int api, final ClassVisitor classVisitor, final Remapper remapper) {
super(api, classVisitor);
this.remapper = remapper;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name;
super.visit(version, access, remapper.mapType(name), remapper
.mapSignature(signature, false), remapper.mapType(superName),
super.visit(
version,
access,
remapper.mapType(name),
remapper.mapSignature(signature, false),
remapper.mapType(superName),
interfaces == null ? null : remapper.mapTypes(interfaces));
}
@Override
public ModuleVisitor visitModule(String name, int flags, String version) {
ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version);
return mv == null ? null : createModuleRemapper(mv);
public ModuleVisitor visitModule(final String name, final int flags, final String version) {
ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version);
return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? null : createAnnotationRemapper(av);
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(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? null : createAnnotationRemapper(av);
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);
}
@Override
public void visitAttribute(Attribute attr) {
if (attr instanceof ModuleHashesAttribute) {
ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute();
List<String> modules = hashesAttr.modules;
for(int i = 0; i < modules.size(); i++) {
public void visitAttribute(final Attribute attribute) {
if (attribute instanceof ModuleHashesAttribute) {
ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute;
List<String> modules = moduleHashesAttribute.modules;
for (int i = 0; i < modules.size(); ++i) {
modules.set(i, remapper.mapModuleName(modules.get(i)));
}
}
super.visitAttribute(attr);
super.visitAttribute(attribute);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
FieldVisitor fv = super.visitField(access,
remapper.mapFieldName(className, name, desc),
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
remapper.mapValue(value));
return fv == null ? null : createFieldRemapper(fv);
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
FieldVisitor fieldVisitor =
super.visitField(
access,
remapper.mapFieldName(className, name, descriptor),
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
(value == null) ? null : remapper.mapValue(value));
return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
String newDesc = remapper.mapMethodDesc(desc);
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
className, name, desc), newDesc, remapper.mapSignature(
signature, false),
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
String remappedDescriptor = remapper.mapMethodDesc(descriptor);
MethodVisitor methodVisitor =
super.visitMethod(
access,
remapper.mapMethodName(className, name, descriptor),
remappedDescriptor,
remapper.mapSignature(signature, false),
exceptions == null ? null : remapper.mapTypes(exceptions));
return mv == null ? null : createMethodRemapper(mv);
return methodVisitor == null ? null : createMethodRemapper(methodVisitor);
}
@Override
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
// TODO should innerName be changed?
super.visitInnerClass(remapper.mapType(name), outerName == null ? null
: remapper.mapType(outerName), innerName, access);
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
super.visitInnerClass(
remapper.mapType(name),
outerName == null ? null : remapper.mapType(outerName),
innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName),
access);
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
super.visitOuterClass(remapper.mapType(owner), name == null ? null
: remapper.mapMethodName(owner, name, desc),
desc == null ? null : remapper.mapMethodDesc(desc));
public void visitOuterClass(final String owner, final String name, final String descriptor) {
super.visitOuterClass(
remapper.mapType(owner),
name == null ? null : remapper.mapMethodName(owner, name, descriptor),
descriptor == null ? null : remapper.mapMethodDesc(descriptor));
}
protected FieldVisitor createFieldRemapper(FieldVisitor fv) {
return new FieldRemapper(fv, remapper);
@Override
public void visitNestHost(final String nestHost) {
super.visitNestHost(remapper.mapType(nestHost));
}
protected MethodVisitor createMethodRemapper(MethodVisitor mv) {
return new MethodRemapper(mv, remapper);
@Override
public void visitNestMember(final String nestMember) {
super.visitNestMember(remapper.mapType(nestMember));
}
protected AnnotationVisitor createAnnotationRemapper(AnnotationVisitor av) {
return new AnnotationRemapper(av, remapper);
/**
* Constructs a new remapper for fields. The default implementation of this method returns a new
* {@link FieldRemapper}.
*
* @param fieldVisitor the FieldVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected FieldVisitor createFieldRemapper(final FieldVisitor fieldVisitor) {
return new FieldRemapper(api, fieldVisitor, remapper);
}
protected ModuleVisitor createModuleRemapper(ModuleVisitor mv) {
return new ModuleRemapper(mv, remapper);
/**
* Constructs a new remapper for methods. The default implementation of this method returns a new
* {@link MethodRemapper}.
*
* @param methodVisitor the MethodVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected MethodVisitor createMethodRemapper(final MethodVisitor methodVisitor) {
return new MethodRemapper(api, methodVisitor, remapper);
}
/**
* Constructs a new remapper for annotations. The default implementation of this method returns a
* new {@link AnnotationRemapper}.
*
* @param annotationVisitor the AnnotationVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected AnnotationVisitor createAnnotationRemapper(final AnnotationVisitor annotationVisitor) {
return new AnnotationRemapper(api, annotationVisitor, remapper);
}
/**
* Constructs a new remapper for modules. The default implementation of this method returns a new
* {@link ModuleRemapper}.
*
* @param moduleVisitor the ModuleVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
protected ModuleVisitor createModuleRemapper(final ModuleVisitor moduleVisitor) {
return new ModuleRemapper(api, moduleVisitor, remapper);
}
}

View file

@ -58,28 +58,31 @@
*/
package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.ConstantDynamic;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A {@link MethodVisitor} that can be used to approximate method size.
* A {@link MethodVisitor} that approximates the size of the methods it visits.
*
* @author Eugene Kuleshov
*/
public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
/** The minimum size in bytes of the visited method. */
private int minSize;
/** The maximum size in bytes of the visited method. */
private int maxSize;
public CodeSizeEvaluator(final MethodVisitor mv) {
this(Opcodes.ASM6, mv);
public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, methodVisitor);
}
protected CodeSizeEvaluator(final int api, final MethodVisitor mv) {
super(api, mv);
protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
public int getMinSize() {
@ -94,9 +97,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
public void visitInsn(final int opcode) {
minSize += 1;
maxSize += 1;
if (mv != null) {
mv.visitInsn(opcode);
}
super.visitInsn(opcode);
}
@Override
@ -108,9 +109,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
super.visitIntInsn(opcode, operand);
}
@Override
@ -125,54 +124,60 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
super.visitVarInsn(opcode, var);
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
super.visitTypeInsn(opcode, type);
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
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 desc) {
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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;
@ -181,18 +186,19 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
maxSize += 3;
}
if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
minSize += 5;
maxSize += 5;
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
}
@Override
@ -203,23 +209,21 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
} else {
maxSize += 8;
}
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
super.visitJumpInsn(opcode, label);
}
@Override
public void visitLdcInsn(final Object cst) {
if (cst instanceof Long || cst instanceof Double) {
public void visitLdcInsn(final Object value) {
if (value instanceof Long
|| value instanceof Double
|| (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
minSize += 3;
maxSize += 3;
} else {
minSize += 2;
maxSize += 3;
}
if (mv != null) {
mv.visitLdcInsn(cst);
}
super.visitLdcInsn(value);
}
@Override
@ -231,37 +235,28 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 3;
maxSize += 3;
}
if (mv != null) {
mv.visitIincInsn(var, increment);
}
super.visitIincInsn(var, increment);
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
minSize += 13 + labels.length * 4;
maxSize += 16 + labels.length * 4;
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
super.visitTableSwitchInsn(min, max, dflt, labels);
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
minSize += 9 + keys.length * 8;
maxSize += 12 + keys.length * 8;
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
super.visitLookupSwitchInsn(dflt, keys, labels);
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
minSize += 4;
maxSize += 4;
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
super.visitMultiANewArrayInsn(descriptor, numDimensions);
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -65,36 +64,56 @@ import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link FieldVisitor} adapter for type remapping.
* A {@link FieldVisitor} that remaps types with a {@link Remapper}.
*
* @author Eugene Kuleshov
*/
public class FieldRemapper extends FieldVisitor {
private final Remapper remapper;
/** The remapper used to remap the types in the visited field. */
protected final Remapper remapper;
public FieldRemapper(final FieldVisitor fv, final Remapper remapper) {
this(Opcodes.ASM6, fv, remapper);
/**
* Constructs a new {@link FieldRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #FieldRemapper(int,FieldVisitor,Remapper)} version.
*
* @param fieldVisitor the field visitor this remapper must deleted to.
* @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);
}
protected FieldRemapper(final int api, final FieldVisitor fv,
final Remapper remapper) {
super(api, fv);
/**
* 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}.
* @param fieldVisitor the field visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited field.
*/
protected FieldRemapper(final int api, final FieldVisitor fieldVisitor, final Remapper remapper) {
super(api, fieldVisitor);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? null : new AnnotationRemapper(av, remapper);
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);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? null : new AnnotationRemapper(av, remapper);
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
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

View file

@ -56,9 +56,9 @@
* 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.ConstantDynamic;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
@ -66,43 +66,38 @@ import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
/**
* A {@link MethodVisitor} providing a more detailed API to generate and
* transform instructions.
* A {@link MethodVisitor} providing a more detailed API to generate and transform instructions.
*
* @author Eric Bruneton
*/
public class InstructionAdapter extends MethodVisitor {
public final static Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
/** The type of the java.lang.Object class. */
public static final Type OBJECT_TYPE = Type.getType("Ljava/lang/Object;");
/**
* Creates a new {@link InstructionAdapter}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #InstructionAdapter(int, MethodVisitor)} version.
* Constructs a new {@link InstructionAdapter}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #InstructionAdapter(int, MethodVisitor)} version.
*
* @param mv
* the method visitor to which this adapter delegates calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @param methodVisitor the method visitor to which this adapter delegates calls.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public InstructionAdapter(final MethodVisitor mv) {
this(Opcodes.ASM6, mv);
public InstructionAdapter(final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, methodVisitor);
if (getClass() != InstructionAdapter.class) {
throw new IllegalStateException();
}
}
/**
* Creates a new {@link InstructionAdapter}.
* 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} or {@link Opcodes#ASM6}.
* @param mv
* the method visitor to which this adapter delegates calls.
* @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 methodVisitor the method visitor to which this adapter delegates calls.
*/
protected InstructionAdapter(final int api, final MethodVisitor mv) {
super(api, mv);
protected InstructionAdapter(final int api, final MethodVisitor methodVisitor) {
super(api, methodVisitor);
}
@Override
@ -125,16 +120,16 @@ public class InstructionAdapter extends MethodVisitor {
break;
case Opcodes.LCONST_0:
case Opcodes.LCONST_1:
lconst(opcode - Opcodes.LCONST_0);
lconst((long) (opcode - Opcodes.LCONST_0));
break;
case Opcodes.FCONST_0:
case Opcodes.FCONST_1:
case Opcodes.FCONST_2:
fconst(opcode - Opcodes.FCONST_0);
fconst((float) (opcode - Opcodes.FCONST_0));
break;
case Opcodes.DCONST_0:
case Opcodes.DCONST_1:
dconst(opcode - Opcodes.DCONST_0);
dconst((double) (opcode - Opcodes.DCONST_0));
break;
case Opcodes.IALOAD:
aload(Type.INT_TYPE);
@ -501,19 +496,19 @@ public class InstructionAdapter extends MethodVisitor {
@Override
public void visitTypeInsn(final int opcode, final String type) {
Type t = Type.getObjectType(type);
Type objectType = Type.getObjectType(type);
switch (opcode) {
case Opcodes.NEW:
anew(t);
anew(objectType);
break;
case Opcodes.ANEWARRAY:
newarray(t);
newarray(objectType);
break;
case Opcodes.CHECKCAST:
checkcast(t);
checkcast(objectType);
break;
case Opcodes.INSTANCEOF:
instanceOf(t);
instanceOf(objectType);
break;
default:
throw new IllegalArgumentException();
@ -521,62 +516,74 @@ public class InstructionAdapter extends MethodVisitor {
}
@Override
public void visitFieldInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
switch (opcode) {
case Opcodes.GETSTATIC:
getstatic(owner, name, desc);
getstatic(owner, name, descriptor);
break;
case Opcodes.PUTSTATIC:
putstatic(owner, name, desc);
putstatic(owner, name, descriptor);
break;
case Opcodes.GETFIELD:
getfield(owner, name, desc);
getfield(owner, name, descriptor);
break;
case Opcodes.PUTFIELD:
putfield(owner, name, desc);
putfield(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
}
}
/**
* 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 desc) {
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
invokespecial(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEVIRTUAL:
invokevirtual(owner, name, desc, itf);
invokevirtual(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKESTATIC:
invokestatic(owner, name, desc, itf);
invokestatic(owner, name, descriptor, isInterface);
break;
case Opcodes.INVOKEINTERFACE:
invokeinterface(owner, name, desc);
invokeinterface(owner, name, descriptor);
break;
default:
throw new IllegalArgumentException();
@ -584,9 +591,12 @@ public class InstructionAdapter extends MethodVisitor {
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
invokedynamic(name, desc, bsm, bsmArgs);
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
invokedynamic(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
}
@Override
@ -657,37 +667,39 @@ public class InstructionAdapter extends MethodVisitor {
}
@Override
public void visitLdcInsn(final Object cst) {
if (cst instanceof Integer) {
int val = ((Integer) cst).intValue();
iconst(val);
} else if (cst instanceof Byte) {
int val = ((Byte) cst).intValue();
iconst(val);
} else if (cst instanceof Character) {
int val = ((Character) cst).charValue();
iconst(val);
} else if (cst instanceof Short) {
int val = ((Short) cst).intValue();
iconst(val);
} else if (cst instanceof Boolean) {
int val = ((Boolean) cst).booleanValue() ? 1 : 0;
iconst(val);
} else if (cst instanceof Float) {
float val = ((Float) cst).floatValue();
fconst(val);
} else if (cst instanceof Long) {
long val = ((Long) cst).longValue();
lconst(val);
} else if (cst instanceof Double) {
double val = ((Double) cst).doubleValue();
dconst(val);
} else if (cst instanceof String) {
aconst(cst);
} else if (cst instanceof Type) {
tconst((Type) cst);
} else if (cst instanceof Handle) {
hconst((Handle) cst);
public void visitLdcInsn(final Object value) {
if (api < Opcodes.ASM5
&& (value instanceof Handle
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException("This feature requires ASM5");
}
if (api != Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (value instanceof Integer) {
iconst((Integer) value);
} else if (value instanceof Byte) {
iconst(((Byte) value).intValue());
} else if (value instanceof Character) {
iconst(((Character) value).charValue());
} else if (value instanceof Short) {
iconst(((Short) value).intValue());
} else if (value instanceof Boolean) {
iconst(((Boolean) value).booleanValue() ? 1 : 0);
} else if (value instanceof Float) {
fconst((Float) value);
} else if (value instanceof Long) {
lconst((Long) value);
} else if (value instanceof Double) {
dconst((Double) value);
} else if (value instanceof String) {
aconst(value);
} else if (value instanceof Type) {
tconst((Type) value);
} else if (value instanceof Handle) {
hconst((Handle) value);
} else if (value instanceof ConstantDynamic) {
cconst((ConstantDynamic) value);
} else {
throw new IllegalArgumentException();
}
@ -699,82 +711,131 @@ public class InstructionAdapter extends MethodVisitor {
}
@Override
public void visitTableSwitchInsn(final int min, final int max,
final Label dflt, final Label... labels) {
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
tableswitch(min, max, dflt, labels);
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys,
final Label[] labels) {
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
lookupswitch(dflt, keys, labels);
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
multianewarray(desc, dims);
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
multianewarray(descriptor, numDimensions);
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/** Generates a nop instruction. */
public void nop() {
mv.visitInsn(Opcodes.NOP);
}
public void aconst(final Object cst) {
if (cst == null) {
/**
* Generates the instruction to push the given value on the stack.
*
* @param value the constant to be pushed on the stack. This parameter must be an {@link Integer},
* a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link Type} of
* OBJECT or ARRAY sort for {@code .class} constants, for classes whose version is 49, a
* {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle constants,
* for classes whose version is 51 or a {@link ConstantDynamic} for a constant dynamic for
* classes whose version is 55.
*/
public void aconst(final Object value) {
if (value == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
mv.visitLdcInsn(cst);
mv.visitLdcInsn(value);
}
}
public void iconst(final int cst) {
if (cst >= -1 && cst <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + cst);
} else if (cst >= Byte.MIN_VALUE && cst <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, cst);
} else if (cst >= Short.MIN_VALUE && cst <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, cst);
/**
* Generates the instruction to push the given value on the stack.
*
* @param intValue the constant to be pushed on the stack.
*/
public void iconst(final int intValue) {
if (intValue >= -1 && intValue <= 5) {
mv.visitInsn(Opcodes.ICONST_0 + intValue);
} else if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) {
mv.visitIntInsn(Opcodes.BIPUSH, intValue);
} else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) {
mv.visitIntInsn(Opcodes.SIPUSH, intValue);
} else {
mv.visitLdcInsn(cst);
mv.visitLdcInsn(intValue);
}
}
public void lconst(final long cst) {
if (cst == 0L || cst == 1L) {
mv.visitInsn(Opcodes.LCONST_0 + (int) cst);
/**
* Generates the instruction to push the given value on the stack.
*
* @param longValue the constant to be pushed on the stack.
*/
public void lconst(final long longValue) {
if (longValue == 0L || longValue == 1L) {
mv.visitInsn(Opcodes.LCONST_0 + (int) longValue);
} else {
mv.visitLdcInsn(cst);
mv.visitLdcInsn(longValue);
}
}
public void fconst(final float cst) {
int bits = Float.floatToIntBits(cst);
if (bits == 0L || bits == 0x3f800000 || bits == 0x40000000) { // 0..2
mv.visitInsn(Opcodes.FCONST_0 + (int) cst);
/**
* Generates the instruction to push the given value on the stack.
*
* @param floatValue the constant to be pushed on the stack.
*/
public void fconst(final float floatValue) {
int bits = Float.floatToIntBits(floatValue);
if (bits == 0L || bits == 0x3F800000 || bits == 0x40000000) { // 0..2
mv.visitInsn(Opcodes.FCONST_0 + (int) floatValue);
} else {
mv.visitLdcInsn(cst);
mv.visitLdcInsn(floatValue);
}
}
public void dconst(final double cst) {
long bits = Double.doubleToLongBits(cst);
if (bits == 0L || bits == 0x3ff0000000000000L) { // +0.0d and 1.0d
mv.visitInsn(Opcodes.DCONST_0 + (int) cst);
/**
* Generates the instruction to push the given value on the stack.
*
* @param doubleValue the constant to be pushed on the stack.
*/
public void dconst(final double doubleValue) {
long bits = Double.doubleToLongBits(doubleValue);
if (bits == 0L || bits == 0x3FF0000000000000L) { // +0.0d and 1.0d
mv.visitInsn(Opcodes.DCONST_0 + (int) doubleValue);
} else {
mv.visitLdcInsn(cst);
mv.visitLdcInsn(doubleValue);
}
}
/**
* Generates the instruction to push the given type on the stack.
*
* @param type the type to be pushed on the stack.
*/
public void tconst(final Type type) {
mv.visitLdcInsn(type);
}
/**
* Generates the instruction to push the given handle on the stack.
*
* @param handle the handle to be pushed on the stack.
*/
public void hconst(final Handle handle) {
mv.visitLdcInsn(handle);
}
/**
* Generates the instruction to push the given constant dynamic on the stack.
*
* @param constantDynamic the constant dynamic to be pushed on the stack.
*/
public void cconst(final ConstantDynamic constantDynamic) {
mv.visitLdcInsn(constantDynamic);
}
public void load(final int var, final Type type) {
mv.visitVarInsn(type.getOpcode(Opcodes.ILOAD), var);
}
@ -879,6 +940,12 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitIincInsn(var, increment);
}
/**
* Generates the instruction to cast from the first given type to the other.
*
* @param from a Type.
* @param to a Type.
*/
public void cast(final Type from, final Type to) {
if (from != to) {
if (from == Type.DOUBLE_TYPE) {
@ -1006,155 +1073,220 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitVarInsn(Opcodes.RET, var);
}
public void tableswitch(final int min, final int max, final Label dflt,
final Label... labels) {
public void tableswitch(final int min, final int max, final Label dflt, final Label... labels) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
public void lookupswitch(final Label dflt, final int[] keys,
final Label[] labels) {
public void lookupswitch(final Label dflt, final int[] keys, final Label[] labels) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
public void areturn(final Type t) {
mv.visitInsn(t.getOpcode(Opcodes.IRETURN));
public void areturn(final Type type) {
mv.visitInsn(type.getOpcode(Opcodes.IRETURN));
}
public void getstatic(final String owner, final String name,
final String desc) {
mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, desc);
public void getstatic(final String owner, final String name, final String descriptor) {
mv.visitFieldInsn(Opcodes.GETSTATIC, owner, name, descriptor);
}
public void putstatic(final String owner, final String name,
final String desc) {
mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, desc);
public void putstatic(final String owner, final String name, final String descriptor) {
mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, name, descriptor);
}
public void getfield(final String owner, final String name,
final String desc) {
mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, desc);
public void getfield(final String owner, final String name, final String descriptor) {
mv.visitFieldInsn(Opcodes.GETFIELD, owner, name, descriptor);
}
public void putfield(final String owner, final String name,
final String desc) {
mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, desc);
public void putfield(final String owner, final String name, final String descriptor) {
mv.visitFieldInsn(Opcodes.PUTFIELD, owner, name, descriptor);
}
/**
* Deprecated.
*
* @param owner the internal name of the method's owner class.
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @deprecated use {@link #invokevirtual(String, String, String, boolean)} instead.
*/
@Deprecated
public void invokevirtual(final String owner, final String name,
final String desc) {
public void invokevirtual(final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
invokevirtual(owner, name, desc, false);
invokevirtual(owner, name, descriptor, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor);
}
public void invokevirtual(final String owner, final String name,
final String desc, final boolean itf) {
/**
* Generates the instruction to call the given virtual method.
*
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param isInterface if the method's owner class is an interface.
*/
public void invokevirtual(
final String owner, final String name, final String descriptor, final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKEVIRTUAL on interfaces require ASM 5");
if (isInterface) {
throw new IllegalArgumentException("INVOKEVIRTUAL on interfaces require ASM 5");
}
invokevirtual(owner, name, desc);
invokevirtual(owner, name, descriptor);
return;
}
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, desc, itf);
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, owner, name, descriptor, isInterface);
}
/**
* Deprecated.
*
* @param owner the internal name of the method's owner class.
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @deprecated use {@link #invokespecial(String, String, String, boolean)} instead.
*/
@Deprecated
public void invokespecial(final String owner, final String name,
final String desc) {
public void invokespecial(final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
invokespecial(owner, name, desc, false);
invokespecial(owner, name, descriptor, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, false);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, false);
}
public void invokespecial(final String owner, final String name,
final String desc, final boolean itf) {
/**
* Generates the instruction to call the given special method.
*
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param isInterface if the method's owner class is an interface.
*/
public void invokespecial(
final String owner, final String name, final String descriptor, final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKESPECIAL on interfaces require ASM 5");
if (isInterface) {
throw new IllegalArgumentException("INVOKESPECIAL on interfaces require ASM 5");
}
invokespecial(owner, name, desc);
invokespecial(owner, name, descriptor);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, desc, itf);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, owner, name, descriptor, isInterface);
}
/**
* Deprecated.
*
* @param owner the internal name of the method's owner class.
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @deprecated use {@link #invokestatic(String, String, String, boolean)} instead.
*/
@Deprecated
public void invokestatic(final String owner, final String name,
final String desc) {
public void invokestatic(final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
invokestatic(owner, name, desc, false);
invokestatic(owner, name, descriptor, false);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, false);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, false);
}
public void invokestatic(final String owner, final String name,
final String desc, final boolean itf) {
/**
* Generates the instruction to call the given static method.
*
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param isInterface if the method's owner class is an interface.
*/
public void invokestatic(
final String owner, final String name, final String descriptor, final boolean isInterface) {
if (api < Opcodes.ASM5) {
if (itf) {
throw new IllegalArgumentException(
"INVOKESTATIC on interfaces require ASM 5");
if (isInterface) {
throw new IllegalArgumentException("INVOKESTATIC on interfaces require ASM 5");
}
invokestatic(owner, name, desc);
invokestatic(owner, name, descriptor);
return;
}
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, desc, itf);
mv.visitMethodInsn(Opcodes.INVOKESTATIC, owner, name, descriptor, isInterface);
}
public void invokeinterface(final String owner, final String name,
final String desc) {
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, desc, true);
/**
* Generates the instruction to call the given interface method.
*
* @param owner the internal name of the method's owner class (see {@link
* Type#getInternalName()}).
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
*/
public void invokeinterface(final String owner, final String name, final String descriptor) {
mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, owner, name, descriptor, true);
}
public void invokedynamic(String name, String desc, Handle bsm,
Object[] bsmArgs) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
/**
* Generates the instruction to call the given dynamic method.
*
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link Type}).
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
* the content of the array so a caller should expect that this array may change.
*/
public void invokedynamic(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object[] bootstrapMethodArguments) {
mv.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
}
public void anew(final Type type) {
mv.visitTypeInsn(Opcodes.NEW, type.getInternalName());
}
/**
* Generates the instruction to create and push on the stack an array of the given type.
*
* @param type an array Type.
*/
public void newarray(final Type type) {
int typ;
int arrayType;
switch (type.getSort()) {
case Type.BOOLEAN:
typ = Opcodes.T_BOOLEAN;
arrayType = Opcodes.T_BOOLEAN;
break;
case Type.CHAR:
typ = Opcodes.T_CHAR;
arrayType = Opcodes.T_CHAR;
break;
case Type.BYTE:
typ = Opcodes.T_BYTE;
arrayType = Opcodes.T_BYTE;
break;
case Type.SHORT:
typ = Opcodes.T_SHORT;
arrayType = Opcodes.T_SHORT;
break;
case Type.INT:
typ = Opcodes.T_INT;
arrayType = Opcodes.T_INT;
break;
case Type.FLOAT:
typ = Opcodes.T_FLOAT;
arrayType = Opcodes.T_FLOAT;
break;
case Type.LONG:
typ = Opcodes.T_LONG;
arrayType = Opcodes.T_LONG;
break;
case Type.DOUBLE:
typ = Opcodes.T_DOUBLE;
arrayType = Opcodes.T_DOUBLE;
break;
default:
mv.visitTypeInsn(Opcodes.ANEWARRAY, type.getInternalName());
return;
}
mv.visitIntInsn(Opcodes.NEWARRAY, typ);
mv.visitIntInsn(Opcodes.NEWARRAY, arrayType);
}
public void arraylength() {
@ -1181,8 +1313,8 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitInsn(Opcodes.MONITOREXIT);
}
public void multianewarray(final String desc, final int dims) {
mv.visitMultiANewArrayInsn(desc, dims);
public void multianewarray(final String descriptor, final int numDimensions) {
mv.visitMultiANewArrayInsn(descriptor, numDimensions);
}
public void ifnull(final Label label) {

View file

@ -66,12 +66,11 @@ import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link MethodVisitor} that renumbers local variables in their order of
* appearance. This adapter allows one to easily add new local variables to a
* method. It may be used by inheriting from this class, but the preferred way
* of using it is via delegation: the next visitor in the chain can indeed add
* new locals when needed by calling {@link #newLocal} on this adapter (this
* requires a reference back to this {@link LocalVariablesSorter}).
* A {@link MethodVisitor} that renumbers local variables in their order of appearance. This adapter
* allows one to easily add new local variables to a method. It may be used by inheriting from this
* class, but the preferred way of using it is via delegation: the next visitor in the chain can
* indeed add new locals when needed by calling {@link #newLocal} on this adapter (this requires a
* reference back to this {@link LocalVariablesSorter}).
*
* @author Chris Nokleberg
* @author Eugene Kuleshov
@ -79,291 +78,278 @@ import jdk.internal.org.objectweb.asm.TypePath;
*/
public class LocalVariablesSorter extends MethodVisitor {
private static final Type OBJECT_TYPE = Type
.getObjectType("java/lang/Object");
/** The type of the java.lang.Object class. */
private static final Type OBJECT_TYPE = Type.getObjectType("java/lang/Object");
/**
* Mapping from old to new local variable indexes. A local variable at index
* i of size 1 is remapped to 'mapping[2*i]', while a local variable at
* index i of size 2 is remapped to 'mapping[2*i+1]'.
* The mapping from old to new local variable indices. A local variable at index i of size 1 is
* remapped to 'mapping[2*i]', while a local variable at index i of size 2 is remapped to
* 'mapping[2*i+1]'.
*/
private int[] mapping = new int[40];
private int[] remappedVariableIndices = new int[40];
/**
* Array used to store stack map local variable types after remapping.
* The local variable types after remapping. The format of this array is the same as in {@link
* MethodVisitor#visitFrame}, except that long and double types use two slots.
*/
private Object[] newLocals = new Object[20];
private Object[] remappedLocalTypes = new Object[20];
/**
* Index of the first local variable, after formal parameters.
*/
/** The index of the first local variable, after formal parameters. */
protected final int firstLocal;
/**
* Index of the next local variable to be created by {@link #newLocal}.
*/
/** The index of the next local variable to be created by {@link #newLocal}. */
protected int nextLocal;
/**
* Creates a new {@link LocalVariablesSorter}. <i>Subclasses must not use
* this constructor</i>. Instead, they must use the
* {@link #LocalVariablesSorter(int, int, String, MethodVisitor)} version.
* Constructs a new {@link LocalVariablesSorter}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #LocalVariablesSorter(int, int, String, MethodVisitor)}
* version.
*
* @param access
* access flags of the adapted method.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @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.
* @throws IllegalStateException if a subclass calls this constructor.
*/
public LocalVariablesSorter(final int access, final String desc,
final MethodVisitor mv) {
this(Opcodes.ASM6, access, desc, mv);
public LocalVariablesSorter(
final int access, final String descriptor, final MethodVisitor methodVisitor) {
this(Opcodes.ASM7, access, descriptor, methodVisitor);
if (getClass() != LocalVariablesSorter.class) {
throw new IllegalStateException();
}
}
/**
* Creates a new {@link LocalVariablesSorter}.
* 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} or {@link Opcodes#ASM6}.
* @param access
* access flags of the adapted method.
* @param desc
* the method's descriptor (see {@link Type Type}).
* @param mv
* the method visitor to which this adapter delegates calls.
* @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 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.
*/
protected LocalVariablesSorter(final int api, final int access,
final String desc, final MethodVisitor mv) {
super(api, mv);
Type[] args = Type.getArgumentTypes(desc);
protected LocalVariablesSorter(
final int api, final int access, final String descriptor, final MethodVisitor methodVisitor) {
super(api, methodVisitor);
nextLocal = (Opcodes.ACC_STATIC & access) == 0 ? 1 : 0;
for (int i = 0; i < args.length; i++) {
nextLocal += args[i].getSize();
for (Type argumentType : Type.getArgumentTypes(descriptor)) {
nextLocal += argumentType.getSize();
}
firstLocal = nextLocal;
}
@Override
public void visitVarInsn(final int opcode, final int var) {
Type type;
Type varType;
switch (opcode) {
case Opcodes.LLOAD:
case Opcodes.LSTORE:
type = Type.LONG_TYPE;
varType = Type.LONG_TYPE;
break;
case Opcodes.DLOAD:
case Opcodes.DSTORE:
type = Type.DOUBLE_TYPE;
varType = Type.DOUBLE_TYPE;
break;
case Opcodes.FLOAD:
case Opcodes.FSTORE:
type = Type.FLOAT_TYPE;
varType = Type.FLOAT_TYPE;
break;
case Opcodes.ILOAD:
case Opcodes.ISTORE:
type = Type.INT_TYPE;
varType = Type.INT_TYPE;
break;
case Opcodes.ALOAD:
case Opcodes.ASTORE:
case Opcodes.RET:
varType = OBJECT_TYPE;
break;
default:
// case Opcodes.ALOAD:
// case Opcodes.ASTORE:
// case RET:
type = OBJECT_TYPE;
break;
throw new IllegalArgumentException("Invalid opcode " + opcode);
}
mv.visitVarInsn(opcode, remap(var, type));
super.visitVarInsn(opcode, remap(var, varType));
}
@Override
public void visitIincInsn(final int var, final int increment) {
mv.visitIincInsn(remap(var, Type.INT_TYPE), increment);
super.visitIincInsn(remap(var, Type.INT_TYPE), increment);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
mv.visitMaxs(maxStack, nextLocal);
super.visitMaxs(maxStack, nextLocal);
}
@Override
public void visitLocalVariable(final String name, final String desc,
final String signature, final Label start, final Label end,
public void visitLocalVariable(
final String name,
final String descriptor,
final String signature,
final Label start,
final Label end,
final int index) {
int newIndex = remap(index, Type.getType(desc));
mv.visitLocalVariable(name, desc, signature, start, end, newIndex);
int remappedIndex = remap(index, Type.getType(descriptor));
super.visitLocalVariable(name, descriptor, signature, start, end, remappedIndex);
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
Type t = Type.getType(desc);
int[] newIndex = new int[index.length];
for (int i = 0; i < newIndex.length; ++i) {
newIndex[i] = remap(index[i], t);
public AnnotationVisitor visitLocalVariableAnnotation(
final int typeRef,
final TypePath typePath,
final Label[] start,
final Label[] end,
final int[] index,
final String descriptor,
final boolean visible) {
Type type = Type.getType(descriptor);
int[] remappedIndex = new int[index.length];
for (int i = 0; i < remappedIndex.length; ++i) {
remappedIndex[i] = remap(index[i], type);
}
return mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
newIndex, desc, visible);
return super.visitLocalVariableAnnotation(
typeRef, typePath, start, end, remappedIndex, descriptor, visible);
}
@Override
public void visitFrame(final int type, final int nLocal,
final Object[] local, final int nStack, final Object[] stack) {
if (type != Opcodes.F_NEW) { // uncompressed frame
throw new IllegalStateException(
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
public void visitFrame(
final int type,
final int numLocal,
final Object[] local,
final int numStack,
final Object[] stack) {
if (type != Opcodes.F_NEW) { // Uncompressed frame.
throw new IllegalArgumentException(
"LocalVariablesSorter only accepts expanded frames (see ClassReader.EXPAND_FRAMES)");
}
// creates a copy of newLocals
Object[] oldLocals = new Object[newLocals.length];
System.arraycopy(newLocals, 0, oldLocals, 0, oldLocals.length);
// Create a copy of remappedLocals.
Object[] oldRemappedLocals = new Object[remappedLocalTypes.length];
System.arraycopy(remappedLocalTypes, 0, oldRemappedLocals, 0, oldRemappedLocals.length);
updateNewLocals(newLocals);
updateNewLocals(remappedLocalTypes);
// copies types from 'local' to 'newLocals'
// 'newLocals' already contains the variables added with 'newLocal'
int index = 0; // old local variable index
int number = 0; // old local variable number
for (; number < nLocal; ++number) {
Object t = local[number];
int size = t == Opcodes.LONG || t == Opcodes.DOUBLE ? 2 : 1;
if (t != Opcodes.TOP) {
Type typ = OBJECT_TYPE;
if (t == Opcodes.INTEGER) {
typ = Type.INT_TYPE;
} else if (t == Opcodes.FLOAT) {
typ = Type.FLOAT_TYPE;
} else if (t == Opcodes.LONG) {
typ = Type.LONG_TYPE;
} else if (t == Opcodes.DOUBLE) {
typ = Type.DOUBLE_TYPE;
} else if (t instanceof String) {
typ = Type.getObjectType((String) t);
// Copy the types from 'local' to 'remappedLocals'. 'remappedLocals' already contains the
// variables added with 'newLocal'.
int oldVar = 0; // Old local variable index.
for (int i = 0; i < numLocal; ++i) {
Object localType = local[i];
if (localType != Opcodes.TOP) {
Type varType = OBJECT_TYPE;
if (localType == Opcodes.INTEGER) {
varType = Type.INT_TYPE;
} else if (localType == Opcodes.FLOAT) {
varType = Type.FLOAT_TYPE;
} else if (localType == Opcodes.LONG) {
varType = Type.LONG_TYPE;
} else if (localType == Opcodes.DOUBLE) {
varType = Type.DOUBLE_TYPE;
} else if (localType instanceof String) {
varType = Type.getObjectType((String) localType);
}
setFrameLocal(remap(index, typ), t);
setFrameLocal(remap(oldVar, varType), localType);
}
index += size;
oldVar += localType == Opcodes.LONG || localType == Opcodes.DOUBLE ? 2 : 1;
}
// removes TOP after long and double types as well as trailing TOPs
index = 0;
number = 0;
for (int i = 0; index < newLocals.length; ++i) {
Object t = newLocals[index++];
if (t != null && t != Opcodes.TOP) {
newLocals[i] = t;
number = i + 1;
if (t == Opcodes.LONG || t == Opcodes.DOUBLE) {
index += 1;
}
// Remove TOP after long and double types as well as trailing TOPs.
oldVar = 0;
int newVar = 0;
int remappedNumLocal = 0;
while (oldVar < remappedLocalTypes.length) {
Object localType = remappedLocalTypes[oldVar];
oldVar += localType == Opcodes.LONG || localType == Opcodes.DOUBLE ? 2 : 1;
if (localType != null && localType != Opcodes.TOP) {
remappedLocalTypes[newVar++] = localType;
remappedNumLocal = newVar;
} else {
newLocals[i] = Opcodes.TOP;
remappedLocalTypes[newVar++] = Opcodes.TOP;
}
}
// visits remapped frame
mv.visitFrame(type, number, newLocals, nStack, stack);
// Visit the remapped frame.
super.visitFrame(type, remappedNumLocal, remappedLocalTypes, numStack, stack);
// restores original value of 'newLocals'
newLocals = oldLocals;
// Restore the original value of 'remappedLocals'.
remappedLocalTypes = oldRemappedLocals;
}
// -------------
// -----------------------------------------------------------------------------------------------
/**
* Creates a new local variable of the given type.
* Constructs a new local variable of the given type.
*
* @param type
* the type of the local variable to be created.
* @param type the type of the local variable to be created.
* @return the identifier of the newly created local variable.
*/
public int newLocal(final Type type) {
Object t;
Object localType;
switch (type.getSort()) {
case Type.BOOLEAN:
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
t = Opcodes.INTEGER;
localType = Opcodes.INTEGER;
break;
case Type.FLOAT:
t = Opcodes.FLOAT;
localType = Opcodes.FLOAT;
break;
case Type.LONG:
t = Opcodes.LONG;
localType = Opcodes.LONG;
break;
case Type.DOUBLE:
t = Opcodes.DOUBLE;
localType = Opcodes.DOUBLE;
break;
case Type.ARRAY:
t = type.getDescriptor();
localType = type.getDescriptor();
break;
case Type.OBJECT:
localType = type.getInternalName();
break;
// case Type.OBJECT:
default:
t = type.getInternalName();
break;
throw new AssertionError();
}
int local = newLocalMapping(type);
setLocalType(local, type);
setFrameLocal(local, t);
setFrameLocal(local, localType);
return local;
}
/**
* Notifies subclasses that a new stack map frame is being visited. The
* array argument contains the stack map frame types corresponding to the
* local variables added with {@link #newLocal}. This method can update
* these types in place for the stack map frame being visited. The default
* implementation of this method does nothing, i.e. a local variable added
* with {@link #newLocal} will have the same type in all stack map frames.
* But this behavior is not always the desired one, for instance if a local
* variable is added in the middle of a try/catch block: the frame for the
* exception handler should have a TOP type for this new local.
* Notifies subclasses that a new stack map frame is being visited. The array argument contains
* the stack map frame types corresponding to the local variables added with {@link #newLocal}.
* This method can update these types in place for the stack map frame being visited. The default
* implementation of this method does nothing, i.e. a local variable added with {@link #newLocal}
* will have the same type in all stack map frames. But this behavior is not always the desired
* one, for instance if a local variable is added in the middle of a try/catch block: the frame
* for the exception handler should have a TOP type for this new local.
*
* @param newLocals
* the stack map frame types corresponding to the local variables
* added with {@link #newLocal} (and null for the others). The
* format of this array is the same as in
* {@link MethodVisitor#visitFrame}, except that long and double
* types use two slots. The types for the current stack map frame
* must be updated in place in this array.
* @param newLocals the stack map frame types corresponding to the local variables added with
* {@link #newLocal} (and null for the others). The format of this array is the same as in
* {@link MethodVisitor#visitFrame}, except that long and double types use two slots. The
* types for the current stack map frame must be updated in place in this array.
*/
protected void updateNewLocals(Object[] newLocals) {
protected void updateNewLocals(final Object[] newLocals) {
// The default implementation does nothing.
}
/**
* Notifies subclasses that a local variable has been added or remapped. The
* default implementation of this method does nothing.
* Notifies subclasses that a local variable has been added or remapped. The default
* implementation of this method does nothing.
*
* @param local
* a local variable identifier, as returned by {@link #newLocal
* newLocal()}.
* @param type
* the type of the value being stored in the local variable.
* @param local a local variable identifier, as returned by {@link #newLocal}.
* @param type the type of the value being stored in the local variable.
*/
protected void setLocalType(final int local, final Type type) {
// The default implementation does nothing.
}
private void setFrameLocal(final int local, final Object type) {
int l = newLocals.length;
if (local >= l) {
Object[] a = new Object[Math.max(2 * l, local + 1)];
System.arraycopy(newLocals, 0, a, 0, l);
newLocals = a;
int numLocals = remappedLocalTypes.length;
if (local >= numLocals) {
Object[] newRemappedLocalTypes = new Object[Math.max(2 * numLocals, local + 1)];
System.arraycopy(remappedLocalTypes, 0, newRemappedLocalTypes, 0, numLocals);
remappedLocalTypes = newRemappedLocalTypes;
}
newLocals[local] = type;
remappedLocalTypes[local] = type;
}
private int remap(final int var, final Type type) {
@ -371,17 +357,17 @@ public class LocalVariablesSorter extends MethodVisitor {
return var;
}
int key = 2 * var + type.getSize() - 1;
int size = mapping.length;
int size = remappedVariableIndices.length;
if (key >= size) {
int[] newMapping = new int[Math.max(2 * size, key + 1)];
System.arraycopy(mapping, 0, newMapping, 0, size);
mapping = newMapping;
int[] newRemappedVariableIndices = new int[Math.max(2 * size, key + 1)];
System.arraycopy(remappedVariableIndices, 0, newRemappedVariableIndices, 0, size);
remappedVariableIndices = newRemappedVariableIndices;
}
int value = mapping[key];
int value = remappedVariableIndices[key];
if (value == 0) {
value = newLocalMapping(type);
setLocalType(value, type);
mapping[key] = value + 1;
remappedVariableIndices[key] = value + 1;
} else {
value--;
}

View file

@ -60,7 +60,6 @@ package jdk.internal.org.objectweb.asm.commons;
import java.util.HashMap;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Type;
/**
@ -72,186 +71,169 @@ import jdk.internal.org.objectweb.asm.Type;
*/
public class Method {
/**
* The method name.
*/
/** The method name. */
private final String name;
/**
* The method descriptor.
*/
private final String desc;
/** The method descriptor. */
private final String descriptor;
/**
* Maps primitive Java type names to their descriptors.
*/
private static final Map<String, String> DESCRIPTORS;
/** The descriptors of the primitive Java types (plus void). */
private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
static {
DESCRIPTORS = new HashMap<String, String>();
DESCRIPTORS.put("void", "V");
DESCRIPTORS.put("byte", "B");
DESCRIPTORS.put("char", "C");
DESCRIPTORS.put("double", "D");
DESCRIPTORS.put("float", "F");
DESCRIPTORS.put("int", "I");
DESCRIPTORS.put("long", "J");
DESCRIPTORS.put("short", "S");
DESCRIPTORS.put("boolean", "Z");
HashMap<String, String> descriptors = new HashMap<String, String>();
descriptors.put("void", "V");
descriptors.put("byte", "B");
descriptors.put("char", "C");
descriptors.put("double", "D");
descriptors.put("float", "F");
descriptors.put("int", "I");
descriptors.put("long", "J");
descriptors.put("short", "S");
descriptors.put("boolean", "Z");
PRIMITIVE_TYPE_DESCRIPTORS = descriptors;
}
/**
* Creates a new {@link Method}.
* Constructs a new {@link Method}.
*
* @param name
* the method's name.
* @param desc
* the method's descriptor.
* @param name the method's name.
* @param descriptor the method's descriptor.
*/
public Method(final String name, final String desc) {
public Method(final String name, final String descriptor) {
this.name = name;
this.desc = desc;
this.descriptor = descriptor;
}
/**
* Creates a new {@link Method}.
* Constructs a new {@link Method}.
*
* @param name
* the method's name.
* @param returnType
* the method's return type.
* @param argumentTypes
* the method's argument types.
* @param name the method's name.
* @param returnType the method's return type.
* @param argumentTypes the method's argument types.
*/
public Method(final String name, final Type returnType,
final Type[] argumentTypes) {
public Method(final String name, final Type returnType, final Type[] argumentTypes) {
this(name, Type.getMethodDescriptor(returnType, argumentTypes));
}
/**
* Creates a new {@link Method}.
*
* @param m
* a java.lang.reflect method descriptor
* @return a {@link Method} corresponding to the given Java method
* declaration.
* @param method a java.lang.reflect method descriptor
* @return a {@link Method} corresponding to the given Java method declaration.
*/
public static Method getMethod(java.lang.reflect.Method m) {
return new Method(m.getName(), Type.getMethodDescriptor(m));
public static Method getMethod(final java.lang.reflect.Method method) {
return new Method(method.getName(), Type.getMethodDescriptor(method));
}
/**
* Creates a new {@link Method}.
*
* @param c
* a java.lang.reflect constructor descriptor
* @return a {@link Method} corresponding to the given Java constructor
* declaration.
* @param constructor a java.lang.reflect constructor descriptor
* @return a {@link Method} corresponding to the given Java constructor declaration.
*/
public static Method getMethod(java.lang.reflect.Constructor<?> c) {
return new Method("<init>", Type.getConstructorDescriptor(c));
public static Method getMethod(final java.lang.reflect.Constructor<?> constructor) {
return new Method("<init>", Type.getConstructorDescriptor(constructor));
}
/**
* Returns a {@link Method} corresponding to the given Java method
* declaration.
* Returns a {@link Method} corresponding to the given Java method declaration.
*
* @param method
* a Java method declaration, without argument names, of the form
* "returnType name (argumentType1, ... argumentTypeN)", where
* the types are in plain Java (e.g. "int", "float",
* "java.util.List", ...). Classes of the java.lang package can
* be specified by their unqualified name; all other classes
* names must be fully qualified.
* @return a {@link Method} corresponding to the given Java method
* declaration.
* @throws IllegalArgumentException
* if <code>method</code> could not get parsed.
* @param method a Java method declaration, without argument names, of the form "returnType name
* (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
* "float", "java.util.List", ...). Classes of the java.lang package can be specified by their
* unqualified name; all other classes names must be fully qualified.
* @return a {@link Method} corresponding to the given Java method declaration.
* @throws IllegalArgumentException if <code>method</code> could not get parsed.
*/
public static Method getMethod(final String method)
throws IllegalArgumentException {
public static Method getMethod(final String method) {
return getMethod(method, false);
}
/**
* Returns a {@link Method} corresponding to the given Java method
* declaration.
* Returns a {@link Method} corresponding to the given Java method declaration.
*
* @param method
* a Java method declaration, without argument names, of the form
* "returnType name (argumentType1, ... argumentTypeN)", where
* the types are in plain Java (e.g. "int", "float",
* "java.util.List", ...). Classes of the java.lang package may
* be specified by their unqualified name, depending on the
* defaultPackage argument; all other classes names must be fully
* qualified.
* @param defaultPackage
* true if unqualified class names belong to the default package,
* or false if they correspond to java.lang classes. For instance
* "Object" means "Object" if this option is true, or
* "java.lang.Object" otherwise.
* @return a {@link Method} corresponding to the given Java method
* declaration.
* @throws IllegalArgumentException
* if <code>method</code> could not get parsed.
* @param method a Java method declaration, without argument names, of the form "returnType name
* (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
* "float", "java.util.List", ...). Classes of the java.lang package may be specified by their
* unqualified name, depending on the defaultPackage argument; all other classes names must be
* fully qualified.
* @param defaultPackage true if unqualified class names belong to the default package, or false
* if they correspond to java.lang classes. For instance "Object" means "Object" if this
* option is true, or "java.lang.Object" otherwise.
* @return a {@link Method} corresponding to the given Java method declaration.
* @throws IllegalArgumentException if <code>method</code> could not get parsed.
*/
public static Method getMethod(final String method,
final boolean defaultPackage) throws IllegalArgumentException {
int space = method.indexOf(' ');
int start = method.indexOf('(', space) + 1;
int end = method.indexOf(')', start);
if (space == -1 || start == -1 || end == -1) {
public static Method getMethod(final String method, final boolean defaultPackage) {
final int spaceIndex = method.indexOf(' ');
int currentArgumentStartIndex = method.indexOf('(', spaceIndex) + 1;
final int endIndex = method.indexOf(')', currentArgumentStartIndex);
if (spaceIndex == -1 || currentArgumentStartIndex == 0 || endIndex == -1) {
throw new IllegalArgumentException();
}
String returnType = method.substring(0, space);
String methodName = method.substring(space + 1, start - 1).trim();
StringBuilder sb = new StringBuilder();
sb.append('(');
int p;
final String returnType = method.substring(0, spaceIndex);
final String methodName =
method.substring(spaceIndex + 1, currentArgumentStartIndex - 1).trim();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('(');
int currentArgumentEndIndex;
do {
String s;
p = method.indexOf(',', start);
if (p == -1) {
s = map(method.substring(start, end).trim(), defaultPackage);
String argumentDescriptor;
currentArgumentEndIndex = method.indexOf(',', currentArgumentStartIndex);
if (currentArgumentEndIndex == -1) {
argumentDescriptor =
getDescriptorInternal(
method.substring(currentArgumentStartIndex, endIndex).trim(), defaultPackage);
} else {
s = map(method.substring(start, p).trim(), defaultPackage);
start = p + 1;
argumentDescriptor =
getDescriptorInternal(
method.substring(currentArgumentStartIndex, currentArgumentEndIndex).trim(),
defaultPackage);
currentArgumentStartIndex = currentArgumentEndIndex + 1;
}
sb.append(s);
} while (p != -1);
sb.append(')');
sb.append(map(returnType, defaultPackage));
return new Method(methodName, sb.toString());
stringBuilder.append(argumentDescriptor);
} while (currentArgumentEndIndex != -1);
stringBuilder.append(')').append(getDescriptorInternal(returnType, defaultPackage));
return new Method(methodName, stringBuilder.toString());
}
private static String map(final String type, final boolean defaultPackage) {
/**
* Returns the descriptor corresponding to the given type name.
*
* @param type a Java type name.
* @param defaultPackage true if unqualified class names belong to the default package, or false
* if they correspond to java.lang classes. For instance "Object" means "Object" if this
* option is true, or "java.lang.Object" otherwise.
* @return the descriptor corresponding to the given type name.
*/
private static String getDescriptorInternal(final String type, final boolean defaultPackage) {
if ("".equals(type)) {
return type;
}
StringBuilder sb = new StringBuilder();
int index = 0;
while ((index = type.indexOf("[]", index) + 1) > 0) {
sb.append('[');
StringBuilder stringBuilder = new StringBuilder();
int arrayBracketsIndex = 0;
while ((arrayBracketsIndex = type.indexOf("[]", arrayBracketsIndex) + 1) > 0) {
stringBuilder.append('[');
}
String t = type.substring(0, type.length() - sb.length() * 2);
String desc = DESCRIPTORS.get(t);
if (desc != null) {
sb.append(desc);
String elementType = type.substring(0, type.length() - stringBuilder.length() * 2);
String descriptor = PRIMITIVE_TYPE_DESCRIPTORS.get(elementType);
if (descriptor != null) {
stringBuilder.append(descriptor);
} else {
sb.append('L');
if (t.indexOf('.') < 0) {
stringBuilder.append('L');
if (elementType.indexOf('.') < 0) {
if (!defaultPackage) {
sb.append("java/lang/");
stringBuilder.append("java/lang/");
}
sb.append(t);
stringBuilder.append(elementType);
} else {
sb.append(t.replace('.', '/'));
stringBuilder.append(elementType.replace('.', '/'));
}
sb.append(';');
stringBuilder.append(';');
}
return sb.toString();
return stringBuilder.toString();
}
/**
@ -269,7 +251,7 @@ public class Method {
* @return the descriptor of the method described by this object.
*/
public String getDescriptor() {
return desc;
return descriptor;
}
/**
@ -278,7 +260,7 @@ public class Method {
* @return the return type of the method described by this object.
*/
public Type getReturnType() {
return Type.getReturnType(desc);
return Type.getReturnType(descriptor);
}
/**
@ -287,25 +269,25 @@ public class Method {
* @return the argument types of the method described by this object.
*/
public Type[] getArgumentTypes() {
return Type.getArgumentTypes(desc);
return Type.getArgumentTypes(descriptor);
}
@Override
public String toString() {
return name + desc;
return name + descriptor;
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof Method)) {
public boolean equals(final Object other) {
if (!(other instanceof Method)) {
return false;
}
Method other = (Method) o;
return name.equals(other.name) && desc.equals(other.desc);
Method otherMethod = (Method) other;
return name.equals(otherMethod.name) && descriptor.equals(otherMethod.descriptor);
}
@Override
public int hashCode() {
return name.hashCode() ^ desc.hashCode();
return name.hashCode() ^ descriptor.hashCode();
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -67,188 +66,258 @@ import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath;
/**
* A {@link LocalVariablesSorter} for type mapping.
* A {@link MethodVisitor} that remaps types with a {@link Remapper}.
*
* @author Eugene Kuleshov
*/
public class MethodRemapper extends MethodVisitor {
/** The remapper used to remap the types in the visited field. */
protected final Remapper remapper;
public MethodRemapper(final MethodVisitor mv, final Remapper remapper) {
this(Opcodes.ASM6, mv, remapper);
/**
* Constructs a new {@link MethodRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #MethodRemapper(int,MethodVisitor,Remapper)} version.
*
* @param methodVisitor the method visitor this remapper must deleted to.
* @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);
}
protected MethodRemapper(final int api, final MethodVisitor mv,
final Remapper remapper) {
super(api, mv);
/**
* Constructs a new {@link MethodRemapper}.
*
* @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}.
* @param methodVisitor the method visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited method.
*/
protected MethodRemapper(
final int api, final MethodVisitor methodVisitor, final Remapper remapper) {
super(api, methodVisitor);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor av = super.visitAnnotationDefault();
return av == null ? av : new AnnotationRemapper(av, remapper);
AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
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
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
AnnotationVisitor av = super.visitParameterAnnotation(parameter,
remapper.mapDesc(desc), visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
public AnnotationVisitor visitParameterAnnotation(
final int parameter, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
remapEntries(nStack, stack));
public void visitFrame(
final int type,
final int numLocal,
final Object[] local,
final int numStack,
final Object[] stack) {
super.visitFrame(
type,
numLocal,
remapFrameTypes(numLocal, local),
numStack,
remapFrameTypes(numStack, stack));
}
private Object[] remapEntries(int n, Object[] entries) {
if (entries != null) {
for (int i = 0; i < n; i++) {
if (entries[i] instanceof String) {
Object[] newEntries = new Object[n];
if (i > 0) {
System.arraycopy(entries, 0, newEntries, 0, i);
private Object[] remapFrameTypes(final int numTypes, final Object[] frameTypes) {
if (frameTypes == null) {
return frameTypes;
}
do {
Object t = entries[i];
newEntries[i++] = t instanceof String ? remapper
.mapType((String) t) : t;
} while (i < n);
return newEntries;
Object[] remappedFrameTypes = null;
for (int i = 0; i < numTypes; ++i) {
if (frameTypes[i] instanceof String) {
if (remappedFrameTypes == null) {
remappedFrameTypes = new Object[numTypes];
System.arraycopy(frameTypes, 0, remappedFrameTypes, 0, numTypes);
}
remappedFrameTypes[i] = remapper.mapType((String) frameTypes[i]);
}
}
}
return entries;
return remappedFrameTypes == null ? frameTypes : remappedFrameTypes;
}
@Override
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
super.visitFieldInsn(opcode, remapper.mapType(owner),
remapper.mapFieldName(owner, name, desc),
remapper.mapDesc(desc));
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
super.visitFieldInsn(
opcode,
remapper.mapType(owner),
remapper.mapFieldName(owner, name, descriptor),
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 desc) {
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
// 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.
// IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
// LocalVariableSorter.
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, desc),
remapper.mapMethodDesc(desc), itf);
mv.visitMethodInsn(
opcode,
remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
for (int i = 0; i < bsmArgs.length; i++) {
bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArguments.length];
for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
remappedBootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]);
}
super.visitInvokeDynamicInsn(
remapper.mapInvokeDynamicMethodName(name, desc),
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
bsmArgs);
remapper.mapInvokeDynamicMethodName(name, descriptor),
remapper.mapMethodDesc(descriptor),
(Handle) remapper.mapValue(bootstrapMethodHandle),
remappedBootstrapMethodArguments);
}
@Override
public void visitTypeInsn(int opcode, String type) {
public void visitTypeInsn(final int opcode, final String type) {
super.visitTypeInsn(opcode, remapper.mapType(type));
}
@Override
public void visitLdcInsn(Object cst) {
super.visitLdcInsn(remapper.mapValue(cst));
public void visitLdcInsn(final Object value) {
super.visitLdcInsn(remapper.mapValue(value));
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
}
@Override
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
public AnnotationVisitor visitInsnAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null
: remapper.mapType(type));
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
public AnnotationVisitor visitTryCatchAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
super.visitLocalVariable(name, remapper.mapDesc(desc),
remapper.mapSignature(signature, true), start, end, index);
public void visitLocalVariable(
final String name,
final String descriptor,
final String signature,
final Label start,
final Label end,
final int index) {
super.visitLocalVariable(
name,
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
start,
end,
index);
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
typePath, start, end, index, remapper.mapDesc(desc), visible);
return av == null ? av : new AnnotationRemapper(av, remapper);
public AnnotationVisitor visitLocalVariableAnnotation(
final int typeRef,
final TypePath typePath,
final Label[] start,
final Label[] end,
final int[] index,
final String descriptor,
final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitLocalVariableAnnotation(
typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
}

View file

@ -56,12 +56,10 @@
* 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 java.util.ArrayList;
import java.util.List;
import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ByteVector;
import jdk.internal.org.objectweb.asm.ClassReader;
@ -69,25 +67,30 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
/**
* ModuleHashes attribute.
* This attribute is specific to the OpenJDK and may change in the future.
* A ModuleHashes attribute. This attribute is specific to the OpenJDK and may change in the future.
*
* @author Remi Forax
*/
public final class ModuleHashesAttribute extends Attribute {
/** The name of the hashing algorithm. */
public String algorithm;
/** A list of module names. */
public List<String> modules;
/** The hash of the modules in {@link #modules}. The two lists must have the same size. */
public List<byte[]> hashes;
/**
* Creates an attribute with a hashing algorithm, a list of module names,
* and a list of the same length of hashes.
* @param algorithm the hashing algorithm name.
* @param modules a list of module name
* @param hashes a list of hash, one for each module name.
* Constructs a new {@link ModuleHashesAttribute}.
*
* @param algorithm the name of the hashing algorithm.
* @param modules a list of module names.
* @param hashes the hash of the modules in 'modules'. The two lists must have the same size.
*/
public ModuleHashesAttribute(final String algorithm,
final List<String> modules, final List<byte[]> hashes) {
public ModuleHashesAttribute(
final String algorithm, final List<String> modules, final List<byte[]> hashes) {
super("ModuleHashes");
this.algorithm = algorithm;
this.modules = modules;
@ -95,61 +98,72 @@ public final class ModuleHashesAttribute extends Attribute {
}
/**
* Creates an empty attribute that can be used as prototype
* to be passed as argument of the method
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
* Constructs an empty {@link ModuleHashesAttribute}. This object can be passed as a prototype to
* the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
*/
public ModuleHashesAttribute() {
this(null, null, null);
}
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf,
int codeOff, Label[] labels) {
String hashAlgorithm = cr.readUTF8(off, buf);
protected Attribute read(
final ClassReader classReader,
final int offset,
final int length,
final char[] charBuffer,
final int codeAttributeOffset,
final Label[] labels) {
int currentOffset = offset;
int count = cr.readUnsignedShort(off + 2);
ArrayList<String> modules = new ArrayList<String>(count);
ArrayList<byte[]> hashes = new ArrayList<byte[]>(count);
off += 4;
String hashAlgorithm = classReader.readUTF8(currentOffset, charBuffer);
currentOffset += 2;
for (int i = 0; i < count; i++) {
String module = cr.readModule(off, buf);
int hashLength = cr.readUnsignedShort(off + 2);
off += 4;
int numModules = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
ArrayList<String> moduleList = new ArrayList<String>(numModules);
ArrayList<byte[]> hashList = new ArrayList<byte[]>(numModules);
for (int i = 0; i < numModules; ++i) {
String module = classReader.readModule(currentOffset, charBuffer);
currentOffset += 2;
moduleList.add(module);
int hashLength = classReader.readUnsignedShort(currentOffset);
currentOffset += 2;
byte[] hash = new byte[hashLength];
for (int j = 0; j < hashLength; j++) {
hash[j] = (byte) (cr.readByte(off + j) & 0xff);
for (int j = 0; j < hashLength; ++j) {
hash[j] = (byte) (classReader.readByte(currentOffset) & 0xFF);
currentOffset += 1;
}
off += hashLength;
modules.add(module);
hashes.add(hash);
hashList.add(hash);
}
return new ModuleHashesAttribute(hashAlgorithm, modules, hashes);
return new ModuleHashesAttribute(hashAlgorithm, moduleList, hashList);
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len,
int maxStack, int maxLocals) {
ByteVector v = new ByteVector();
int index = cw.newUTF8(algorithm);
v.putShort(index);
int count = (modules == null)? 0: modules.size();
v.putShort(count);
for(int i = 0; i < count; i++) {
protected ByteVector write(
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
ByteVector byteVector = new ByteVector();
byteVector.putShort(classWriter.newUTF8(algorithm));
if (modules == null) {
byteVector.putShort(0);
} else {
int numModules = modules.size();
byteVector.putShort(numModules);
for (int i = 0; i < numModules; ++i) {
String module = modules.get(i);
v.putShort(cw.newModule(module));
byte[] hash = hashes.get(i);
v.putShort(hash.length);
for(byte b: hash) {
v.putByte(b);
byteVector
.putShort(classWriter.newModule(module))
.putShort(hash.length)
.putByteArray(hash, 0, hash.length);
}
}
return v;
return byteVector;
}
}

View file

@ -56,80 +56,97 @@
* 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.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A {@link ModuleVisitor} adapter for type remapping.
* A {@link ModuleVisitor} that remaps types with a {@link Remapper}.
*
* @author Remi Forax
*/
public class ModuleRemapper extends ModuleVisitor {
private final Remapper remapper;
public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) {
this(Opcodes.ASM6, mv, remapper);
/** The remapper used to remap the types in the visited module. */
protected final Remapper remapper;
/**
* Constructs a new {@link ModuleRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #ModuleRemapper(int,ModuleVisitor,Remapper)} version.
*
* @param moduleVisitor the module visitor this remapper must deleted to.
* @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);
}
protected ModuleRemapper(final int api, final ModuleVisitor mv,
final Remapper remapper) {
super(api, mv);
/**
* 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}.
* @param moduleVisitor the module visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited module.
*/
protected ModuleRemapper(
final int api, final ModuleVisitor moduleVisitor, final Remapper remapper) {
super(api, moduleVisitor);
this.remapper = remapper;
}
@Override
public void visitMainClass(String mainClass) {
public void visitMainClass(final String mainClass) {
super.visitMainClass(remapper.mapType(mainClass));
}
@Override
public void visitPackage(String packaze) {
public void visitPackage(final String packaze) {
super.visitPackage(remapper.mapPackageName(packaze));
}
@Override
public void visitRequire(String module, int access, String version) {
public void visitRequire(final String module, final int access, final String version) {
super.visitRequire(remapper.mapModuleName(module), access, version);
}
@Override
public void visitExport(String packaze, int access, String... modules) {
String[] newModules = null;
public void visitExport(final String packaze, final int access, final String... modules) {
String[] remappedModules = null;
if (modules != null) {
newModules = new String[modules.length];
for (int i = 0 ; i < modules.length; i++) {
newModules[i] = remapper.mapModuleName(modules[i]);
remappedModules = new String[modules.length];
for (int i = 0; i < modules.length; ++i) {
remappedModules[i] = remapper.mapModuleName(modules[i]);
}
}
super.visitExport(remapper.mapPackageName(packaze), access, newModules);
super.visitExport(remapper.mapPackageName(packaze), access, remappedModules);
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
String[] newModules = null;
public void visitOpen(final String packaze, final int access, final String... modules) {
String[] remappedModules = null;
if (modules != null) {
newModules = new String[modules.length];
for (int i = 0 ; i < modules.length; i++) {
newModules[i] = remapper.mapModuleName(modules[i]);
remappedModules = new String[modules.length];
for (int i = 0; i < modules.length; ++i) {
remappedModules[i] = remapper.mapModuleName(modules[i]);
}
}
super.visitOpen(remapper.mapPackageName(packaze), access, newModules);
super.visitOpen(remapper.mapPackageName(packaze), access, remappedModules);
}
@Override
public void visitUse(String service) {
public void visitUse(final String service) {
super.visitUse(remapper.mapType(service));
}
@Override
public void visitProvide(String service, String... providers) {
String[] newProviders = new String[providers.length];
for (int i = 0 ; i < providers.length; i++) {
newProviders[i] = remapper.mapType(providers[i]);
public void visitProvide(final String service, final String... providers) {
String[] remappedProviders = new String[providers.length];
for (int i = 0; i < providers.length; ++i) {
remappedProviders[i] = remapper.mapType(providers[i]);
}
super.visitProvide(remapper.mapType(service), newProviders);
super.visitProvide(remapper.mapType(service), remappedProviders);
}
}

View file

@ -56,7 +56,6 @@
* 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.Attribute;
@ -66,43 +65,45 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
/**
* ModuleResolution_attribute.
* This attribute is specific to the OpenJDK and may change in the future.
* A ModuleResolution attribute. This attribute is specific to the OpenJDK and may change in the
* future.
*
* @author Remi Forax
*/
public final class ModuleResolutionAttribute extends Attribute {
/**
* Resolution state of a module meaning that the module is not available
* from the class-path by default.
* The resolution state of a module meaning that the module is not available from the class-path
* by default.
*/
public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1;
/**
* Resolution state of a module meaning the module is marked as deprecated.
*/
/** The resolution state of a module meaning the module is marked as deprecated. */
public static final int RESOLUTION_WARN_DEPRECATED = 2;
/**
* Resolution state of a module meaning the module is marked as deprecated
* and will be removed in a future release.
* The resolution state of a module meaning the module is marked as deprecated and will be removed
* in a future release.
*/
public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4;
/**
* Resolution state of a module meaning the module is not yet standardized,
* so in incubating mode.
* The resolution state of a module meaning the module is not yet standardized, so in incubating
* mode.
*/
public static final int RESOLUTION_WARN_INCUBATING = 8;
/**
* The resolution state of the module. Must be one of {@link #RESOLUTION_WARN_DEPRECATED}, {@link
* #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link #RESOLUTION_WARN_INCUBATING}.
*/
public int resolution;
/**
* Creates an attribute with a resolution state value.
* @param resolution the resolution state among
* {@link #RESOLUTION_WARN_DEPRECATED},
* {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and
* {@link #RESOLUTION_WARN_INCUBATING}.
* Constructs a new {@link ModuleResolutionAttribute}.
*
* @param resolution the resolution state of the module. Must be one of {@link
* #RESOLUTION_WARN_DEPRECATED}, {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link
* #RESOLUTION_WARN_INCUBATING}.
*/
public ModuleResolutionAttribute(final int resolution) {
super("ModuleResolution");
@ -110,26 +111,33 @@ public final class ModuleResolutionAttribute extends Attribute {
}
/**
* Creates an empty attribute that can be used as prototype
* to be passed as argument of the method
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
* Constructs an empty {@link ModuleResolutionAttribute}. This object can be passed as a prototype
* to the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
*/
public ModuleResolutionAttribute() {
this(0);
}
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf,
int codeOff, Label[] labels) {
int resolution = cr.readUnsignedShort(off);
return new ModuleResolutionAttribute(resolution);
protected Attribute read(
final ClassReader classReader,
final int offset,
final int length,
final char[] charBuffer,
final int codeOffset,
final Label[] labels) {
return new ModuleResolutionAttribute(classReader.readUnsignedShort(offset));
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len,
int maxStack, int maxLocals) {
ByteVector v = new ByteVector();
v.putShort(resolution);
return v;
protected ByteVector write(
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
ByteVector byteVector = new ByteVector();
byteVector.putShort(resolution);
return byteVector;
}
}

View file

@ -56,7 +56,6 @@
* 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.Attribute;
@ -66,17 +65,19 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label;
/**
* ModuleTarget attribute.
* This attribute is specific to the OpenJDK and may change in the future.
* A ModuleTarget attribute. This attribute is specific to the OpenJDK and may change in the future.
*
* @author Remi Forax
*/
public final class ModuleTargetAttribute extends Attribute {
/** The name of the platform on which the module can run. */
public String platform;
/**
* Creates an attribute with a platform name.
* @param platform the platform name on which the module can run.
* Constructs a new {@link ModuleTargetAttribute}.
*
* @param platform the name of the platform on which the module can run.
*/
public ModuleTargetAttribute(final String platform) {
super("ModuleTarget");
@ -84,27 +85,33 @@ public final class ModuleTargetAttribute extends Attribute {
}
/**
* Creates an empty attribute that can be used as prototype
* to be passed as argument of the method
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}.
* Constructs an empty {@link ModuleTargetAttribute}. This object can be passed as a prototype to
* the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
*/
public ModuleTargetAttribute() {
this(null);
}
@Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf,
int codeOff, Label[] labels) {
String platform = cr.readUTF8(off, buf);
return new ModuleTargetAttribute(platform);
protected Attribute read(
final ClassReader classReader,
final int offset,
final int length,
final char[] charBuffer,
final int codeOffset,
final Label[] labels) {
return new ModuleTargetAttribute(classReader.readUTF8(offset, charBuffer));
}
@Override
protected ByteVector write(ClassWriter cw, byte[] code, int len,
int maxStack, int maxLocals) {
ByteVector v = new ByteVector();
int index = (platform == null)? 0: cw.newUTF8(platform);
v.putShort(index);
return v;
protected ByteVector write(
final ClassWriter classWriter,
final byte[] code,
final int codeLength,
final int maxStack,
final int maxLocals) {
ByteVector byteVector = new ByteVector();
byteVector.putShort(platform == null ? 0 : classWriter.newUTF8(platform));
return byteVector;
}
}

View file

@ -56,234 +56,305 @@
* 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.ConstantDynamic;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.signature.SignatureReader;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
import jdk.internal.org.objectweb.asm.signature.SignatureWriter;
/**
* A class responsible for remapping types and names. Subclasses can override
* the following methods:
*
* <ul>
* <li>{@link #map(String)} - map type</li>
* <li>{@link #mapFieldName(String, String, String)} - map field name</li>
* <li>{@link #mapMethodName(String, String, String)} - map method name</li>
* </ul>
* A class responsible for remapping types and names.
*
* @author Eugene Kuleshov
*/
public abstract class Remapper {
public String mapDesc(String desc) {
Type t = Type.getType(desc);
switch (t.getSort()) {
case Type.ARRAY:
String s = mapDesc(t.getElementType().getDescriptor());
for (int i = 0; i < t.getDimensions(); ++i) {
s = '[' + s;
}
return s;
case Type.OBJECT:
String newType = map(t.getInternalName());
if (newType != null) {
return 'L' + newType + ';';
}
}
return desc;
/**
* Returns the given descriptor, remapped with {@link #map(String)}.
*
* @param descriptor a type descriptor.
* @return the given descriptor, with its [array element type] internal name remapped with {@link
* #map(String)} (if the descriptor corresponds to an array or object type, otherwise the
* descriptor is returned as is).
*/
public String mapDesc(final String descriptor) {
return mapType(Type.getType(descriptor)).getDescriptor();
}
private Type mapType(Type t) {
switch (t.getSort()) {
/**
* Returns the given {@link Type}, remapped with {@link #map(String)} or {@link
* #mapMethodDesc(String)}.
*
* @param type a type, which can be a method type.
* @return the given type, with its [array element type] internal name remapped with {@link
* #map(String)} (if the type is an array or object type, otherwise the type is returned as
* is) or, of the type is a method type, with its descriptor remapped with {@link
* #mapMethodDesc(String)}.
*/
private Type mapType(final Type type) {
switch (type.getSort()) {
case Type.ARRAY:
String s = mapDesc(t.getElementType().getDescriptor());
for (int i = 0; i < t.getDimensions(); ++i) {
s = '[' + s;
StringBuilder remappedDescriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
remappedDescriptor.append('[');
}
return Type.getType(s);
remappedDescriptor.append(mapType(type.getElementType()).getDescriptor());
return Type.getType(remappedDescriptor.toString());
case Type.OBJECT:
s = map(t.getInternalName());
return s != null ? Type.getObjectType(s) : t;
String remappedInternalName = map(type.getInternalName());
return remappedInternalName != null ? Type.getObjectType(remappedInternalName) : type;
case Type.METHOD:
return Type.getMethodType(mapMethodDesc(t.getDescriptor()));
return Type.getMethodType(mapMethodDesc(type.getDescriptor()));
default:
return type;
}
return t;
}
public String mapType(String type) {
if (type == null) {
/**
* Returns the given internal name, remapped with {@link #map(String)}.
*
* @param internalName the internal name (or array type descriptor) of some (array) class.
* @return the given internal name, remapped with {@link #map(String)}.
*/
public String mapType(final String internalName) {
if (internalName == null) {
return null;
}
return mapType(Type.getObjectType(type)).getInternalName();
return mapType(Type.getObjectType(internalName)).getInternalName();
}
public String[] mapTypes(String[] types) {
String[] newTypes = null;
boolean needMapping = false;
for (int i = 0; i < types.length; i++) {
String type = types[i];
String newType = map(type);
if (newType != null && newTypes == null) {
newTypes = new String[types.length];
if (i > 0) {
System.arraycopy(types, 0, newTypes, 0, i);
/**
* Returns the given internal names, remapped with {@link #map(String)}.
*
* @param internalNames the internal names (or array type descriptors) of some (array) classes.
* @return the given internal name, remapped with {@link #map(String)}.
*/
public String[] mapTypes(final String[] internalNames) {
String[] remappedInternalNames = null;
for (int i = 0; i < internalNames.length; ++i) {
String internalName = internalNames[i];
String remappedInternalName = mapType(internalName);
if (remappedInternalName != null) {
if (remappedInternalNames == null) {
remappedInternalNames = new String[internalNames.length];
System.arraycopy(internalNames, 0, remappedInternalNames, 0, internalNames.length);
}
needMapping = true;
}
if (needMapping) {
newTypes[i] = newType == null ? type : newType;
remappedInternalNames[i] = remappedInternalName;
}
}
return needMapping ? newTypes : types;
return remappedInternalNames != null ? remappedInternalNames : internalNames;
}
public String mapMethodDesc(String desc) {
if ("()V".equals(desc)) {
return desc;
/**
* Returns the given method descriptor, with its argument and return type descriptors remapped
* with {@link #mapDesc(String)}.
*
* @param methodDescriptor a method descriptor.
* @return the given method descriptor, with its argument and return type descriptors remapped
* with {@link #mapDesc(String)}.
*/
public String mapMethodDesc(final String methodDescriptor) {
if ("()V".equals(methodDescriptor)) {
return methodDescriptor;
}
Type[] args = Type.getArgumentTypes(desc);
StringBuilder sb = new StringBuilder("(");
for (int i = 0; i < args.length; i++) {
sb.append(mapDesc(args[i].getDescriptor()));
StringBuilder stringBuilder = new StringBuilder("(");
for (Type argumentType : Type.getArgumentTypes(methodDescriptor)) {
stringBuilder.append(mapType(argumentType).getDescriptor());
}
Type returnType = Type.getReturnType(desc);
Type returnType = Type.getReturnType(methodDescriptor);
if (returnType == Type.VOID_TYPE) {
sb.append(")V");
return sb.toString();
stringBuilder.append(")V");
} else {
stringBuilder.append(')').append(mapType(returnType).getDescriptor());
}
sb.append(')').append(mapDesc(returnType.getDescriptor()));
return sb.toString();
return stringBuilder.toString();
}
public Object mapValue(Object value) {
/**
* Returns the given value, remapped with this remapper. Possible values are {@link Boolean},
* {@link Byte}, {@link Short}, {@link Character}, {@link Integer}, {@link Long}, {@link Double},
* {@link Float}, {@link String}, {@link Type}, {@link Handle}, {@link ConstantDynamic} or arrays
* of primitive types .
*
* @param value an object. Only {@link Type}, {@link Handle} and {@link ConstantDynamic} values
* are remapped.
* @return the given value, remapped with this remapper.
*/
public Object mapValue(final Object value) {
if (value instanceof Type) {
return mapType((Type) value);
}
if (value instanceof Handle) {
Handle h = (Handle) value;
return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName(
h.getOwner(), h.getName(), h.getDesc()),
mapMethodDesc(h.getDesc()), h.isInterface());
Handle handle = (Handle) value;
return new Handle(
handle.getTag(),
mapType(handle.getOwner()),
mapMethodName(handle.getOwner(), handle.getName(), handle.getDesc()),
handle.getTag() <= Opcodes.H_PUTSTATIC
? mapDesc(handle.getDesc())
: mapMethodDesc(handle.getDesc()),
handle.isInterface());
}
if (value instanceof ConstantDynamic) {
ConstantDynamic constantDynamic = (ConstantDynamic) value;
int bootstrapMethodArgumentCount = constantDynamic.getBootstrapMethodArgumentCount();
Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArgumentCount];
for (int i = 0; i < bootstrapMethodArgumentCount; ++i) {
remappedBootstrapMethodArguments[i] =
mapValue(constantDynamic.getBootstrapMethodArgument(i));
}
String descriptor = constantDynamic.getDescriptor();
return new ConstantDynamic(
mapInvokeDynamicMethodName(constantDynamic.getName(), descriptor),
mapDesc(descriptor),
(Handle) mapValue(constantDynamic.getBootstrapMethod()),
remappedBootstrapMethodArguments);
}
return value;
}
/**
* @param signature
* signature for mapper
* @param typeSignature
* true if signature is a FieldTypeSignature, such as the
* signature parameter of the ClassVisitor.visitField or
* MethodVisitor.visitLocalVariable methods
* @return signature rewritten as a string
* Returns the given signature, remapped with the {@link SignatureVisitor} returned by {@link
* #createSignatureRemapper(SignatureVisitor)}.
*
* @param signature a <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
* @param typeSignature whether the given signature is a <i>JavaTypeSignature</i>.
* @return signature the given signature, remapped with the {@link SignatureVisitor} returned by
* {@link #createSignatureRemapper(SignatureVisitor)}.
*/
public String mapSignature(String signature, boolean typeSignature) {
public String mapSignature(final String signature, final boolean typeSignature) {
if (signature == null) {
return null;
}
SignatureReader r = new SignatureReader(signature);
SignatureWriter w = new SignatureWriter();
SignatureVisitor a = createSignatureRemapper(w);
SignatureReader signatureReader = new SignatureReader(signature);
SignatureWriter signatureWriter = new SignatureWriter();
SignatureVisitor signatureRemapper = createSignatureRemapper(signatureWriter);
if (typeSignature) {
r.acceptType(a);
signatureReader.acceptType(signatureRemapper);
} else {
r.accept(a);
signatureReader.accept(signatureRemapper);
}
return w.toString();
return signatureWriter.toString();
}
/**
* Constructs a new remapper for signatures. The default implementation of this method returns a
* new {@link SignatureRemapper}.
*
* @param signatureVisitor the SignatureVisitor the remapper must delegate to.
* @return the newly created remapper.
* @deprecated use {@link #createSignatureRemapper} instead.
*/
@Deprecated
protected SignatureVisitor createRemappingSignatureAdapter(
SignatureVisitor v) {
return new SignatureRemapper(v, this);
}
protected SignatureVisitor createSignatureRemapper(
SignatureVisitor v) {
return createRemappingSignatureAdapter(v);
final SignatureVisitor signatureVisitor) {
return createSignatureRemapper(signatureVisitor);
}
/**
* Map method name to the new name. Subclasses can override.
* Constructs a new remapper for signatures. The default implementation of this method returns a
* new {@link SignatureRemapper}.
*
* @param owner
* owner of the method.
* @param name
* name of the method.
* @param desc
* descriptor of the method.
* @return new name of the method
* @param signatureVisitor the SignatureVisitor the remapper must delegate to.
* @return the newly created remapper.
*/
public String mapMethodName(String owner, String name, String desc) {
protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signatureVisitor) {
return new SignatureRemapper(signatureVisitor, this);
}
/**
* Maps an inner class name to its new name. The default implementation of this method provides a
* strategy that will work for inner classes produced by Java, but not necessarily other
* languages. Subclasses can override.
*
* @param name the fully-qualified internal name of the inner class.
* @param ownerName the internal name of the owner class of the inner class.
* @param innerName the internal name of the inner class.
* @return the new inner name of the inner class.
*/
public String mapInnerClassName(
final String name, final String ownerName, final String innerName) {
final String remappedInnerName = this.mapType(name);
if (remappedInnerName.contains("$")) {
return remappedInnerName.substring(remappedInnerName.lastIndexOf('$') + 1);
} else {
return innerName;
}
}
/**
* Maps a method 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 method.
* @param name the name of the method.
* @param descriptor the descriptor of the method.
* @return the new name of the method.
*/
public String mapMethodName(final String owner, final String name, final String descriptor) {
return name;
}
/**
* Map invokedynamic method name to the new name. Subclasses can override.
* Maps an invokedynamic or a constant dynamic method name to its new name. The default
* implementation of this method returns the given name, unchanged. Subclasses can override.
*
* @param name
* name of the invokedynamic.
* @param desc
* descriptor of the invokedynamic.
* @return new invokdynamic name.
* @param name the name of the method.
* @param descriptor the descriptor of the method.
* @return the new name of the method.
*/
public String mapInvokeDynamicMethodName(String name, String desc) {
public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
return name;
}
/**
* Map field name to the new name. Subclasses can override.
* Maps a field name to its new name. The default implementation of this method returns the given
* name, unchanged. Subclasses can override.
*
* @param owner
* owner of the field.
* @param name
* name of the field
* @param desc
* descriptor of the field
* @return new name of the field.
* @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 mapFieldName(String owner, String name, String desc) {
public String mapFieldName(final String owner, final String name, final String descriptor) {
return name;
}
/**
* Map package name to the new name. Subclasses can override.
* Maps a package name to its new name. The default implementation of this method returns the
* given name, unchanged. Subclasses can override.
*
* @param name name of the package
* @return new name of the package
* @param name the fully qualified name of the package (using dots).
* @return the new name of the package.
*/
public String mapPackageName(String name) {
String fakeName = map(name + ".FakeClassName");
int index;
return fakeName == null || (index = fakeName.lastIndexOf('.')) == -1 ? name: fakeName.substring(0, index);
}
/**
* Map module name to the new name. Subclasses can override.
*
* @param name name of the module
* @return new name of the module
*/
public String mapModuleName(String name) {
public String mapPackageName(final String name) {
return name;
}
/**
* Map type name to the new name. Subclasses can override.
* Maps a module name to its new name. The default implementation of this method returns the given
* name, unchanged. Subclasses can override.
*
* @param typeName
* the type name
* @return new name, default implementation is the identity.
* @param name the fully qualified name (using dots) of a module.
* @return the new name of the module.
*/
public String map(String typeName) {
return typeName;
public String mapModuleName(final String name) {
return name;
}
/**
* Maps the internal name of a class to its new name. The default implementation of this method
* returns the given name, unchanged. Subclasses can override.
*
* @param internalName the internal name of a class.
* @return the new internal name.
*/
public String map(final String internalName) {
return internalName;
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -73,38 +72,44 @@ public class RemappingAnnotationAdapter extends AnnotationVisitor {
protected final Remapper remapper;
public RemappingAnnotationAdapter(final AnnotationVisitor av,
final Remapper remapper) {
this(Opcodes.ASM6, av, remapper);
public RemappingAnnotationAdapter(
final AnnotationVisitor annotationVisitor, final Remapper remapper) {
this(Opcodes.ASM6, annotationVisitor, remapper);
}
protected RemappingAnnotationAdapter(final int api,
final AnnotationVisitor av, final Remapper remapper) {
super(api, av);
protected RemappingAnnotationAdapter(
final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) {
super(api, annotationVisitor);
this.remapper = remapper;
}
@Override
public void visit(String name, Object value) {
public void visit(final String name, final Object value) {
av.visit(name, remapper.mapValue(value));
}
@Override
public void visitEnum(String name, String desc, String value) {
av.visitEnum(name, remapper.mapDesc(desc), value);
public void visitEnum(final String name, final String descriptor, final String value) {
av.visitEnum(name, remapper.mapDesc(descriptor), value);
}
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc));
return v == null ? null : (v == av ? this
: new RemappingAnnotationAdapter(v, remapper));
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
AnnotationVisitor annotationVisitor = av.visitAnnotation(name, remapper.mapDesc(descriptor));
return annotationVisitor == null
? null
: (annotationVisitor == av
? this
: new RemappingAnnotationAdapter(annotationVisitor, remapper));
}
@Override
public AnnotationVisitor visitArray(String name) {
AnnotationVisitor v = av.visitArray(name);
return v == null ? null : (v == av ? this
: new RemappingAnnotationAdapter(v, remapper));
public AnnotationVisitor visitArray(final String name) {
AnnotationVisitor annotationVisitor = av.visitArray(name);
return annotationVisitor == null
? null
: (annotationVisitor == av
? this
: new RemappingAnnotationAdapter(annotationVisitor, remapper));
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -80,93 +79,119 @@ public class RemappingClassAdapter extends ClassVisitor {
protected String className;
public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) {
this(Opcodes.ASM6, cv, remapper);
public RemappingClassAdapter(final ClassVisitor classVisitor, final Remapper remapper) {
this(Opcodes.ASM6, classVisitor, remapper);
}
protected RemappingClassAdapter(final int api, final ClassVisitor cv,
final Remapper remapper) {
super(api, cv);
protected RemappingClassAdapter(
final int api, final ClassVisitor classVisitor, final Remapper remapper) {
super(api, classVisitor);
this.remapper = remapper;
}
@Override
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name;
super.visit(version, access, remapper.mapType(name), remapper
.mapSignature(signature, false), remapper.mapType(superName),
super.visit(
version,
access,
remapper.mapType(name),
remapper.mapSignature(signature, false),
remapper.mapType(superName),
interfaces == null ? null : remapper.mapTypes(interfaces));
}
@Override
public ModuleVisitor visitModule(String name, int flags, String version) {
public ModuleVisitor visitModule(final String name, final int flags, final String version) {
throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? null : createRemappingAnnotationAdapter(av);
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null ? null : createRemappingAnnotationAdapter(annotationVisitor);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? null : createRemappingAnnotationAdapter(av);
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 : createRemappingAnnotationAdapter(annotationVisitor);
}
@Override
public FieldVisitor visitField(int access, String name, String desc,
String signature, Object value) {
FieldVisitor fv = super.visitField(access,
remapper.mapFieldName(className, name, desc),
remapper.mapDesc(desc), remapper.mapSignature(signature, true),
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
FieldVisitor fieldVisitor =
super.visitField(
access,
remapper.mapFieldName(className, name, descriptor),
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
remapper.mapValue(value));
return fv == null ? null : createRemappingFieldAdapter(fv);
return fieldVisitor == null ? null : createRemappingFieldAdapter(fieldVisitor);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
String newDesc = remapper.mapMethodDesc(desc);
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName(
className, name, desc), newDesc, remapper.mapSignature(
signature, false),
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
String newDescriptor = remapper.mapMethodDesc(descriptor);
MethodVisitor methodVisitor =
super.visitMethod(
access,
remapper.mapMethodName(className, name, descriptor),
newDescriptor,
remapper.mapSignature(signature, false),
exceptions == null ? null : remapper.mapTypes(exceptions));
return mv == null ? null : createRemappingMethodAdapter(access,
newDesc, mv);
return methodVisitor == null
? null
: createRemappingMethodAdapter(access, newDescriptor, methodVisitor);
}
@Override
public void visitInnerClass(String name, String outerName,
String innerName, int access) {
// TODO should innerName be changed?
super.visitInnerClass(remapper.mapType(name), outerName == null ? null
: remapper.mapType(outerName), innerName, access);
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
super.visitInnerClass(
remapper.mapType(name),
outerName == null ? null : remapper.mapType(outerName),
innerName,
access);
}
@Override
public void visitOuterClass(String owner, String name, String desc) {
super.visitOuterClass(remapper.mapType(owner), name == null ? null
: remapper.mapMethodName(owner, name, desc),
desc == null ? null : remapper.mapMethodDesc(desc));
public void visitOuterClass(final String owner, final String name, final String descriptor) {
super.visitOuterClass(
remapper.mapType(owner),
name == null ? null : remapper.mapMethodName(owner, name, descriptor),
descriptor == null ? null : remapper.mapMethodDesc(descriptor));
}
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) {
return new RemappingFieldAdapter(fv, remapper);
protected FieldVisitor createRemappingFieldAdapter(final FieldVisitor fieldVisitor) {
return new RemappingFieldAdapter(fieldVisitor, remapper);
}
protected MethodVisitor createRemappingMethodAdapter(int access,
String newDesc, MethodVisitor mv) {
return new RemappingMethodAdapter(access, newDesc, mv, remapper);
protected MethodVisitor createRemappingMethodAdapter(
final int access, final String newDescriptor, final MethodVisitor methodVisitior) {
return new RemappingMethodAdapter(access, newDescriptor, methodVisitior, remapper);
}
protected AnnotationVisitor createRemappingAnnotationAdapter(
AnnotationVisitor av) {
protected AnnotationVisitor createRemappingAnnotationAdapter(final AnnotationVisitor av) {
return new RemappingAnnotationAdapter(av, remapper);
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -75,28 +74,31 @@ public class RemappingFieldAdapter extends FieldVisitor {
private final Remapper remapper;
public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) {
this(Opcodes.ASM6, fv, remapper);
public RemappingFieldAdapter(final FieldVisitor fieldVisitor, final Remapper remapper) {
this(Opcodes.ASM6, fieldVisitor, remapper);
}
protected RemappingFieldAdapter(final int api, final FieldVisitor fv,
final Remapper remapper) {
super(api, fv);
protected RemappingFieldAdapter(
final int api, final FieldVisitor fieldVisitor, final Remapper remapper) {
super(api, fieldVisitor);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor = fv.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? null
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? null : new RemappingAnnotationAdapter(av, remapper);
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
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
}

View file

@ -56,7 +56,6 @@
* 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;
@ -77,105 +76,130 @@ public class RemappingMethodAdapter extends LocalVariablesSorter {
protected final Remapper remapper;
public RemappingMethodAdapter(final int access, final String desc,
final MethodVisitor mv, final Remapper remapper) {
this(Opcodes.ASM6, access, desc, mv, remapper);
public RemappingMethodAdapter(
final int access,
final String descriptor,
final MethodVisitor methodVisitor,
final Remapper remapper) {
this(Opcodes.ASM6, access, descriptor, methodVisitor, remapper);
}
protected RemappingMethodAdapter(final int api, final int access,
final String desc, final MethodVisitor mv, final Remapper remapper) {
super(api, access, desc, mv);
protected RemappingMethodAdapter(
final int api,
final int access,
final String descriptor,
final MethodVisitor methodVisitor,
final Remapper remapper) {
super(api, access, descriptor, methodVisitor);
this.remapper = remapper;
}
@Override
public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor av = super.visitAnnotationDefault();
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc),
visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
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
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public AnnotationVisitor visitParameterAnnotation(int parameter,
String desc, boolean visible) {
AnnotationVisitor av = super.visitParameterAnnotation(parameter,
remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitParameterAnnotation(
final int parameter, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack,
Object[] stack) {
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack,
remapEntries(nStack, stack));
public void visitFrame(
final int type,
final int numLocal,
final Object[] local,
final int numStack,
final Object[] stack) {
super.visitFrame(
type, numLocal, remapEntries(numLocal, local), numStack, remapEntries(numStack, stack));
}
private Object[] remapEntries(int n, Object[] entries) {
if (entries != null) {
for (int i = 0; i < n; i++) {
if (entries[i] instanceof String) {
Object[] newEntries = new Object[n];
if (i > 0) {
System.arraycopy(entries, 0, newEntries, 0, i);
}
do {
Object t = entries[i];
newEntries[i++] = t instanceof String ? remapper
.mapType((String) t) : t;
} while (i < n);
return newEntries;
}
}
}
private Object[] remapEntries(final int numTypes, final Object[] entries) {
if (entries == null) {
return entries;
}
Object[] remappedEntries = null;
for (int i = 0; i < numTypes; ++i) {
if (entries[i] instanceof String) {
if (remappedEntries == null) {
remappedEntries = new Object[numTypes];
System.arraycopy(entries, 0, remappedEntries, 0, numTypes);
}
remappedEntries[i] = remapper.mapType((String) entries[i]);
}
}
return remappedEntries == null ? entries : remappedEntries;
}
@Override
public void visitFieldInsn(int opcode, String owner, String name,
String desc) {
super.visitFieldInsn(opcode, remapper.mapType(owner),
remapper.mapFieldName(owner, name, desc),
remapper.mapDesc(desc));
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String descriptor) {
super.visitFieldInsn(
opcode,
remapper.mapType(owner),
remapper.mapFieldName(owner, name, descriptor),
remapper.mapDesc(descriptor));
}
@Deprecated
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc) {
public void visitMethodInsn(
final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc);
super.visitMethodInsn(opcode, owner, name, descriptor);
return;
}
doVisitMethodInsn(opcode, owner, name, desc,
opcode == Opcodes.INVOKEINTERFACE);
doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
@Override
public void visitMethodInsn(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
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, desc, itf);
super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return;
}
doVisitMethodInsn(opcode, owner, name, desc, itf);
doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
}
private void doVisitMethodInsn(int opcode, String owner, String name,
String desc, boolean itf) {
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
@ -183,75 +207,103 @@ public class RemappingMethodAdapter extends LocalVariablesSorter {
// IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
// LocalVariableSorter.
if (mv != null) {
mv.visitMethodInsn(opcode, remapper.mapType(owner),
remapper.mapMethodName(owner, name, desc),
remapper.mapMethodDesc(desc), itf);
mv.visitMethodInsn(
opcode,
remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
}
}
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
Object... bsmArgs) {
for (int i = 0; i < bsmArgs.length; i++) {
bsmArgs[i] = remapper.mapValue(bsmArgs[i]);
public void visitInvokeDynamicInsn(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
for (int i = 0; i < bootstrapMethodArguments.length; i++) {
bootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]);
}
super.visitInvokeDynamicInsn(
remapper.mapInvokeDynamicMethodName(name, desc),
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm),
bsmArgs);
remapper.mapInvokeDynamicMethodName(name, descriptor),
remapper.mapMethodDesc(descriptor),
(Handle) remapper.mapValue(bootstrapMethodHandle),
bootstrapMethodArguments);
}
@Override
public void visitTypeInsn(int opcode, String type) {
public void visitTypeInsn(final int opcode, final String type) {
super.visitTypeInsn(opcode, remapper.mapType(type));
}
@Override
public void visitLdcInsn(Object cst) {
super.visitLdcInsn(remapper.mapValue(cst));
public void visitLdcInsn(final Object value) {
super.visitLdcInsn(remapper.mapValue(value));
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims);
public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
}
@Override
public AnnotationVisitor visitInsnAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitInsnAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler,
String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null
: remapper.mapType(type));
public void visitTryCatchBlock(
final Label start, final Label end, final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
}
@Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath,
remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitTryCatchAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
@Override
public void visitLocalVariable(String name, String desc, String signature,
Label start, Label end, int index) {
super.visitLocalVariable(name, remapper.mapDesc(desc),
remapper.mapSignature(signature, true), start, end, index);
public void visitLocalVariable(
final String name,
final String descriptor,
final String signature,
final Label start,
final Label end,
final int index) {
super.visitLocalVariable(
name,
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
start,
end,
index);
}
@Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
TypePath typePath, Label[] start, Label[] end, int[] index,
String desc, boolean visible) {
AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef,
typePath, start, end, index, remapper.mapDesc(desc), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper);
public AnnotationVisitor visitLocalVariableAnnotation(
final int typeRef,
final TypePath typePath,
final Label[] start,
final Label[] end,
final int[] index,
final String descriptor,
final boolean visible) {
AnnotationVisitor annotationVisitor =
super.visitLocalVariableAnnotation(
typeRef, typePath, start, end, index, remapper.mapDesc(descriptor), visible);
return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
}
}

View file

@ -56,7 +56,6 @@
* 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.Opcodes;
@ -71,116 +70,118 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
@Deprecated
public class RemappingSignatureAdapter extends SignatureVisitor {
private final SignatureVisitor v;
private final SignatureVisitor signatureVisitor;
private final Remapper remapper;
private String className;
public RemappingSignatureAdapter(final SignatureVisitor v,
final Remapper remapper) {
this(Opcodes.ASM6, v, remapper);
public RemappingSignatureAdapter(
final SignatureVisitor signatureVisitor, final Remapper remapper) {
this(Opcodes.ASM6, signatureVisitor, remapper);
}
protected RemappingSignatureAdapter(final int api,
final SignatureVisitor v, final Remapper remapper) {
protected RemappingSignatureAdapter(
final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
super(api);
this.v = v;
this.signatureVisitor = signatureVisitor;
this.remapper = remapper;
}
@Override
public void visitClassType(String name) {
public void visitClassType(final String name) {
className = name;
v.visitClassType(remapper.mapType(name));
signatureVisitor.visitClassType(remapper.mapType(name));
}
@Override
public void visitInnerClassType(String name) {
public void visitInnerClassType(final String name) {
String remappedOuter = remapper.mapType(className) + '$';
className = className + '$' + name;
String remappedName = remapper.mapType(className);
int index = remappedName.startsWith(remappedOuter) ? remappedOuter
.length() : remappedName.lastIndexOf('$') + 1;
v.visitInnerClassType(remappedName.substring(index));
int index =
remappedName.startsWith(remappedOuter)
? remappedOuter.length()
: remappedName.lastIndexOf('$') + 1;
signatureVisitor.visitInnerClassType(remappedName.substring(index));
}
@Override
public void visitFormalTypeParameter(String name) {
v.visitFormalTypeParameter(name);
public void visitFormalTypeParameter(final String name) {
signatureVisitor.visitFormalTypeParameter(name);
}
@Override
public void visitTypeVariable(String name) {
v.visitTypeVariable(name);
public void visitTypeVariable(final String name) {
signatureVisitor.visitTypeVariable(name);
}
@Override
public SignatureVisitor visitArrayType() {
v.visitArrayType();
signatureVisitor.visitArrayType();
return this;
}
@Override
public void visitBaseType(char descriptor) {
v.visitBaseType(descriptor);
public void visitBaseType(final char descriptor) {
signatureVisitor.visitBaseType(descriptor);
}
@Override
public SignatureVisitor visitClassBound() {
v.visitClassBound();
signatureVisitor.visitClassBound();
return this;
}
@Override
public SignatureVisitor visitExceptionType() {
v.visitExceptionType();
signatureVisitor.visitExceptionType();
return this;
}
@Override
public SignatureVisitor visitInterface() {
v.visitInterface();
signatureVisitor.visitInterface();
return this;
}
@Override
public SignatureVisitor visitInterfaceBound() {
v.visitInterfaceBound();
signatureVisitor.visitInterfaceBound();
return this;
}
@Override
public SignatureVisitor visitParameterType() {
v.visitParameterType();
signatureVisitor.visitParameterType();
return this;
}
@Override
public SignatureVisitor visitReturnType() {
v.visitReturnType();
signatureVisitor.visitReturnType();
return this;
}
@Override
public SignatureVisitor visitSuperclass() {
v.visitSuperclass();
signatureVisitor.visitSuperclass();
return this;
}
@Override
public void visitTypeArgument() {
v.visitTypeArgument();
signatureVisitor.visitTypeArgument();
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
v.visitTypeArgument(wildcard);
public SignatureVisitor visitTypeArgument(final char wildcard) {
signatureVisitor.visitTypeArgument(wildcard);
return this;
}
@Override
public void visitEnd() {
v.visitEnd();
signatureVisitor.visitEnd();
}
}

View file

@ -63,252 +63,240 @@ import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
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;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A {@link ClassVisitor} that adds a serial version unique identifier to a
* class if missing. Here is typical usage of this class:
* A {@link ClassVisitor} that adds a serial version unique identifier to a class if missing. A
* typical usage of this class is:
*
* <pre>
* ClassWriter cw = new ClassWriter(...);
* ClassVisitor sv = new SerialVersionUIDAdder(cw);
* ClassVisitor ca = new MyClassAdapter(sv);
* new ClassReader(orginalClass).accept(ca, false);
* ClassWriter classWriter = new ClassWriter(...);
* ClassVisitor svuidAdder = new SerialVersionUIDAdder(classWriter);
* ClassVisitor classVisitor = new MyClassAdapter(svuidAdder);
* new ClassReader(orginalClass).accept(classVisitor, 0);
* </pre>
*
* The SVUID algorithm can be found <a href=
* "http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html"
* >http://java.sun.com/j2se/1.4.2/docs/guide/serialization/spec/class.html</a>:
* <p>The SVUID algorithm can be found at <a href=
* "https://docs.oracle.com/javase/10/docs/specs/serialization/class.html#stream-unique-identifiers"
* >https://docs.oracle.com/javase/10/docs/specs/serialization/class.html#stream-unique-identifiers</a>:
*
* <pre>
* The serialVersionUID is computed using the signature of a stream of bytes
* that reflect the class definition. The National Institute of Standards and
* Technology (NIST) Secure Hash Algorithm (SHA-1) is used to compute a
* signature for the stream. The first two 32-bit quantities are used to form a
* 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data
* types to a sequence of bytes. The values input to the stream are defined by
* the Java Virtual Machine (VM) specification for classes.
* <p>The serialVersionUID is computed using the signature of a stream of bytes that reflect the
* class definition. The National Institute of Standards and Technology (NIST) Secure Hash Algorithm
* (SHA-1) is used to compute a signature for the stream. The first two 32-bit quantities are used
* to form a 64-bit hash. A java.lang.DataOutputStream is used to convert primitive data types to a
* sequence of bytes. The values input to the stream are defined by the Java Virtual Machine (VM)
* specification for classes.
*
* The sequence of items in the stream is as follows:
* <p>The sequence of items in the stream is as follows:
*
* 1. The class name written using UTF encoding.
* 2. The class modifiers written as a 32-bit integer.
* 3. The name of each interface sorted by name written using UTF encoding.
* 4. For each field of the class sorted by field name (except private static
* and private transient fields):
* 1. The name of the field in UTF encoding.
* 2. The modifiers of the field written as a 32-bit integer.
* 3. The descriptor of the field in UTF encoding
* 5. If a class initializer exists, write out the following:
* 1. The name of the method, &lt;clinit&gt;, in UTF encoding.
* 2. The modifier of the method, java.lang.reflect.Modifier.STATIC,
* written as a 32-bit integer.
* 3. The descriptor of the method, ()V, in UTF encoding.
* 6. For each non-private constructor sorted by method name and signature:
* 1. The name of the method, &lt;init&gt;, in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 7. For each non-private method sorted by method name and signature:
* 1. The name of the method in UTF encoding.
* 2. The modifiers of the method written as a 32-bit integer.
* 3. The descriptor of the method in UTF encoding.
* 8. The SHA-1 algorithm is executed on the stream of bytes produced by
* DataOutputStream and produces five 32-bit values sha[0..4].
*
* 9. The hash value is assembled from the first and second 32-bit values of
* the SHA-1 message digest. If the result of the message digest, the five
* 32-bit words H0 H1 H2 H3 H4, is in an array of five int values named
* sha, the hash value would be computed as follows:
*
* long hash = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) |
* ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8 |
* ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 |
* ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 24 |
* ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 |
* ((sha[1] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 40 |
* ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 |
* ((sha[1] &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
* </pre>
* <ol>
* <li>The class name written using UTF encoding.
* <li>The class modifiers written as a 32-bit integer.
* <li>The name of each interface sorted by name written using UTF encoding.
* <li>For each field of the class sorted by field name (except private static and private
* transient fields):
* <ol>
* <li>The name of the field in UTF encoding.
* <li>The modifiers of the field written as a 32-bit integer.
* <li>The descriptor of the field in UTF encoding
* </ol>
* <li>If a class initializer exists, write out the following:
* <ol>
* <li>The name of the method, &lt;clinit&gt;, in UTF encoding.
* <li>The modifier of the method, STATIC, written as a 32-bit integer.
* <li>The descriptor of the method, ()V, in UTF encoding.
* </ol>
* <li>For each non-private constructor sorted by method name and signature:
* <ol>
* <li>The name of the method, &lt;init&gt;, in UTF encoding.
* <li>The modifiers of the method written as a 32-bit integer.
* <li>The descriptor of the method in UTF encoding.
* </ol>
* <li>For each non-private method sorted by method name and signature:
* <ol>
* <li>The name of the method in UTF encoding.
* <li>The modifiers of the method written as a 32-bit integer.
* <li>The descriptor of the method in UTF encoding.
* </ol>
* <li>The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and
* produces five 32-bit values sha[0..4].
* <li>The hash value is assembled from the first and second 32-bit values of the SHA-1 message
* digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an
* array of five int values named sha, the hash value would be computed as follows: long hash
* = ((sha[0] &gt;&gt;&gt; 24) &amp; 0xFF) | ((sha[0] &gt;&gt;&gt; 16) &amp; 0xFF) &lt;&lt; 8
* | ((sha[0] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 16 | ((sha[0] &gt;&gt;&gt; 0) &amp; 0xFF)
* &lt;&lt; 24 | ((sha[1] &gt;&gt;&gt; 24) &amp; 0xFF) &lt;&lt; 32 | ((sha[1] &gt;&gt;&gt; 16)
* &amp; 0xFF) &lt;&lt; 40 | ((sha[1] &gt;&gt;&gt; 8) &amp; 0xFF) &lt;&lt; 48 | ((sha[1]
* &gt;&gt;&gt; 0) &amp; 0xFF) &lt;&lt; 56;
* </ol>
*
* @author Rajendra Inamdar, Vishal Vishnoi
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public class SerialVersionUIDAdder extends ClassVisitor {
/**
* Flag that indicates if we need to compute SVUID.
*/
private boolean computeSVUID;
/** The JVM name of static initializer methods. */
private static final String CLINIT = "<clinit>";
/**
* Set to true if the class already has SVUID.
*/
private boolean hasSVUID;
/** A flag that indicates if we need to compute SVUID. */
private boolean computeSvuid;
/**
* Classes access flags.
*/
/** Whether the class already has a SVUID. */
private boolean hasSvuid;
/** The class access flags. */
private int access;
/**
* Internal name of the class
*/
/** The internal name of the class. */
private String name;
/**
* Interfaces implemented by the class.
*/
/** The interfaces implemented by the class. */
private String[] interfaces;
/**
* Collection of fields. (except private static and private transient
* fields)
*/
/** The fields of the class that are needed to compute the SVUID. */
private Collection<Item> svuidFields;
/**
* Set to true if the class has static initializer.
*/
/** Whether the class has a static initializer. */
private boolean hasStaticInitializer;
/**
* Collection of non-private constructors.
*/
/** The constructors of the class that are needed to compute the SVUID. */
private Collection<Item> svuidConstructors;
/**
* Collection of non-private methods.
*/
/** The methods of the class that are needed to compute the SVUID. */
private Collection<Item> svuidMethods;
/**
* Creates a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use
* this constructor</i>. Instead, they must use the
* {@link #SerialVersionUIDAdder(int, ClassVisitor)} version.
* Constructs a new {@link SerialVersionUIDAdder}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #SerialVersionUIDAdder(int, ClassVisitor)}
* version.
*
* @param cv
* a {@link ClassVisitor} to which this visitor will delegate
* calls.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @param classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public SerialVersionUIDAdder(final ClassVisitor cv) {
this(Opcodes.ASM6, cv);
public SerialVersionUIDAdder(final ClassVisitor classVisitor) {
this(Opcodes.ASM7, classVisitor);
if (getClass() != SerialVersionUIDAdder.class) {
throw new IllegalStateException();
}
}
/**
* Creates a new {@link SerialVersionUIDAdder}.
* 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} or {@link Opcodes#ASM6}.
* @param cv
* a {@link ClassVisitor} to which this visitor will delegate
* calls.
* @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 classVisitor a {@link ClassVisitor} to which this visitor will delegate calls.
*/
protected SerialVersionUIDAdder(final int api, final ClassVisitor cv) {
super(api, cv);
svuidFields = new ArrayList<Item>();
svuidConstructors = new ArrayList<Item>();
svuidMethods = new ArrayList<Item>();
protected SerialVersionUIDAdder(final int api, final ClassVisitor classVisitor) {
super(api, classVisitor);
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Overridden methods
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/*
* Visit class header and get class name, access , and interfaces
* information (step 1,2, and 3) for SVUID computation.
*/
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
computeSVUID = (access & Opcodes.ACC_ENUM) == 0;
// Get the class name, access flags, and interfaces information (step 1, 2 and 3) for SVUID
// computation.
computeSvuid = (access & Opcodes.ACC_ENUM) == 0;
if (computeSVUID) {
if (computeSvuid) {
this.name = name;
this.access = access;
this.interfaces = new String[interfaces.length];
System.arraycopy(interfaces, 0, this.interfaces, 0,
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);
}
super.visit(version, access, name, signature, superName, interfaces);
}
/*
* Visit the methods and get constructor and method information (step 5 and
* 7). Also determine if there is a class initializer (step 6).
*/
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
if (computeSVUID) {
if ("<clinit>".equals(name)) {
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
// Get constructor and method information (step 5 and 7). Also determine if there is a class
// initializer (step 6).
if (computeSvuid) {
if (CLINIT.equals(name)) {
hasStaticInitializer = true;
}
/*
* Remembers non private constructors and methods for SVUID
* computation For constructor and method modifiers, only the
* ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL,
* ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and ACC_STRICT flags
* are used.
*/
int mods = access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL | Opcodes.ACC_SYNCHRONIZED
| Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_STRICT);
// Collect the non private constructors and methods. Only the ACC_PUBLIC, ACC_PRIVATE,
// ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT and
// ACC_STRICT flags are used.
int mods =
access
& (Opcodes.ACC_PUBLIC
| Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED
| Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL
| Opcodes.ACC_SYNCHRONIZED
| Opcodes.ACC_NATIVE
| Opcodes.ACC_ABSTRACT
| Opcodes.ACC_STRICT);
// all non private methods
if ((access & Opcodes.ACC_PRIVATE) == 0) {
if ("<init>".equals(name)) {
svuidConstructors.add(new Item(name, mods, desc));
} else if (!"<clinit>".equals(name)) {
svuidMethods.add(new Item(name, mods, desc));
svuidConstructors.add(new Item(name, mods, descriptor));
} else if (!CLINIT.equals(name)) {
svuidMethods.add(new Item(name, mods, descriptor));
}
}
}
return super.visitMethod(access, name, desc, signature, exceptions);
return super.visitMethod(access, name, descriptor, signature, exceptions);
}
/*
* Gets class field information for step 4 of the algorithm. Also determines
* if the class already has a SVUID.
*/
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
if (computeSVUID) {
public FieldVisitor visitField(
final int access,
final String name,
final String desc,
final String signature,
final Object value) {
// Get the class field information for step 4 of the algorithm. Also determine if the class
// already has a SVUID.
if (computeSvuid) {
if ("serialVersionUID".equals(name)) {
// since the class already has SVUID, we won't be computing it.
computeSVUID = false;
hasSVUID = true;
// Since the class already has SVUID, we won't be computing it.
computeSvuid = false;
hasSvuid = true;
}
/*
* Remember field for SVUID computation For field modifiers, only
* the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC,
* ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when
* computing serialVersionUID values.
*/
// Collect the non private fields. Only the ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED,
// ACC_STATIC, ACC_FINAL, ACC_VOLATILE, and ACC_TRANSIENT flags are used when computing
// serialVersionUID values.
if ((access & Opcodes.ACC_PRIVATE) == 0
|| (access & (Opcodes.ACC_STATIC | Opcodes.ACC_TRANSIENT)) == 0) {
int mods = access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED | Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL | Opcodes.ACC_VOLATILE | Opcodes.ACC_TRANSIENT);
int mods =
access
& (Opcodes.ACC_PUBLIC
| Opcodes.ACC_PRIVATE
| Opcodes.ACC_PROTECTED
| Opcodes.ACC_STATIC
| Opcodes.ACC_FINAL
| Opcodes.ACC_VOLATILE
| Opcodes.ACC_TRANSIENT);
svuidFields.add(new Item(name, mods, desc));
}
}
@ -316,175 +304,150 @@ public class SerialVersionUIDAdder extends ClassVisitor {
return super.visitField(access, name, desc, signature, value);
}
/**
* Handle a bizarre special case. Nested classes (static classes declared
* inside another class) that are protected have their access bit set to
* public in their class files to deal with some odd reflection situation.
* Our SVUID computation must do as the JVM does and ignore access bits in
* the class file in favor of the access bits InnerClass attribute.
*/
@Override
public void visitInnerClass(final String aname, final String outerName,
final String innerName, final int attr_access) {
if ((name != null) && name.equals(aname)) {
this.access = attr_access;
public void visitInnerClass(
final String innerClassName,
final String outerName,
final String innerName,
final int innerClassAccess) {
// Handles a bizarre special case. Nested classes (static classes declared inside another class)
// that are protected have their access bit set to public in their class files to deal with some
// odd reflection situation. Our SVUID computation must do as the JVM does and ignore access
// bits in the class file in favor of the access bits of the InnerClass attribute.
if ((name != null) && name.equals(innerClassName)) {
this.access = innerClassAccess;
}
super.visitInnerClass(aname, outerName, innerName, attr_access);
super.visitInnerClass(innerClassName, outerName, innerName, innerClassAccess);
}
/*
* Add the SVUID if class doesn't have one
*/
@Override
public void visitEnd() {
// compute SVUID and add it to the class
if (computeSVUID && !hasSVUID) {
// Add the SVUID field to the class if it doesn't have one.
if (computeSvuid && !hasSvuid) {
try {
addSVUID(computeSVUID());
} catch (Throwable e) {
throw new RuntimeException("Error while computing SVUID for "
+ name, e);
} catch (IOException e) {
throw new IllegalStateException("Error while computing SVUID for " + name, e);
}
}
super.visitEnd();
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Returns true if the class already has a SVUID field. The result of this
* method is only valid when visitEnd is or has been called.
* Returns true if the class already has a SVUID field. The result of this method is only valid
* when visitEnd has been called.
*
* @return true if the class already has a SVUID field.
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public boolean hasSVUID() {
return hasSVUID;
return hasSvuid;
}
protected void addSVUID(long svuid) {
FieldVisitor fv = super.visitField(Opcodes.ACC_FINAL
+ Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
if (fv != null) {
fv.visitEnd();
/**
* Adds a final static serialVersionUID field to the class, with the given value.
*
* @param svuid the serialVersionUID field value.
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected void addSVUID(final long svuid) {
FieldVisitor fieldVisitor =
super.visitField(
Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "serialVersionUID", "J", null, svuid);
if (fieldVisitor != null) {
fieldVisitor.visitEnd();
}
}
/**
* Computes and returns the value of SVUID.
*
* @return Returns the serial version UID
* @throws IOException
* if an I/O error occurs
* @return the serial version UID.
* @throws IOException if an I/O error occurs.
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected long computeSVUID() throws IOException {
ByteArrayOutputStream bos;
DataOutputStream dos = null;
ByteArrayOutputStream byteArrayOutputStream = null;
DataOutputStream dataOutputStream = null;
long svuid = 0;
try {
bos = new ByteArrayOutputStream();
dos = new DataOutputStream(bos);
byteArrayOutputStream = new ByteArrayOutputStream();
dataOutputStream = new DataOutputStream(byteArrayOutputStream);
/*
* 1. The class name written using UTF encoding.
*/
dos.writeUTF(name.replace('/', '.'));
// 1. The class name written using UTF encoding.
dataOutputStream.writeUTF(name.replace('/', '.'));
/*
* 2. The class modifiers written as a 32-bit integer.
*/
int access = this.access;
if ((access & Opcodes.ACC_INTERFACE) != 0) {
access = (svuidMethods.size() > 0) ? (access | Opcodes.ACC_ABSTRACT)
: (access & ~Opcodes.ACC_ABSTRACT);
// 2. The class modifiers written as a 32-bit integer.
int mods = access;
if ((mods & Opcodes.ACC_INTERFACE) != 0) {
mods =
svuidMethods.isEmpty() ? (mods & ~Opcodes.ACC_ABSTRACT) : (mods | Opcodes.ACC_ABSTRACT);
}
dos.writeInt(access
& (Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL
| Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT));
dataOutputStream.writeInt(
mods
& (Opcodes.ACC_PUBLIC
| Opcodes.ACC_FINAL
| Opcodes.ACC_INTERFACE
| Opcodes.ACC_ABSTRACT));
/*
* 3. The name of each interface sorted by name written using UTF
* encoding.
*/
// 3. The name of each interface sorted by name written using UTF encoding.
Arrays.sort(interfaces);
for (int i = 0; i < interfaces.length; i++) {
dos.writeUTF(interfaces[i].replace('/', '.'));
for (String interfaceName : interfaces) {
dataOutputStream.writeUTF(interfaceName.replace('/', '.'));
}
/*
* 4. For each field of the class sorted by field name (except
* private static and private transient fields):
*
* 1. The name of the field in UTF encoding. 2. The modifiers of the
* field written as a 32-bit integer. 3. The descriptor of the field
* in UTF encoding
*
* Note that field signatures are not dot separated. Method and
* constructor signatures are dot separated. Go figure...
*/
writeItems(svuidFields, dos, false);
// 4. For each field of the class sorted by field name (except private static and private
// transient fields):
// 1. The name of the field in UTF encoding.
// 2. The modifiers of the field written as a 32-bit integer.
// 3. The descriptor of the field in UTF encoding.
// Note that field signatures are not dot separated. Method and constructor signatures are dot
// separated. Go figure...
writeItems(svuidFields, dataOutputStream, false);
/*
* 5. If a class initializer exists, write out the following: 1. The
* name of the method, <clinit>, in UTF encoding. 2. The modifier of
* the method, java.lang.reflect.Modifier.STATIC, written as a
* 32-bit integer. 3. The descriptor of the method, ()V, in UTF
* encoding.
*/
// 5. If a class initializer exists, write out the following:
// 1. The name of the method, <clinit>, in UTF encoding.
// 2. The modifier of the method, ACC_STATIC, written as a 32-bit integer.
// 3. The descriptor of the method, ()V, in UTF encoding.
if (hasStaticInitializer) {
dos.writeUTF("<clinit>");
dos.writeInt(Opcodes.ACC_STATIC);
dos.writeUTF("()V");
} // if..
dataOutputStream.writeUTF(CLINIT);
dataOutputStream.writeInt(Opcodes.ACC_STATIC);
dataOutputStream.writeUTF("()V");
}
/*
* 6. For each non-private constructor sorted by method name and
* signature: 1. The name of the method, <init>, in UTF encoding. 2.
* The modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems(svuidConstructors, dos, true);
// 6. For each non-private constructor sorted by method name and signature:
// 1. The name of the method, <init>, in UTF encoding.
// 2. The modifiers of the method written as a 32-bit integer.
// 3. The descriptor of the method in UTF encoding.
writeItems(svuidConstructors, dataOutputStream, true);
/*
* 7. For each non-private method sorted by method name and
* signature: 1. The name of the method in UTF encoding. 2. The
* modifiers of the method written as a 32-bit integer. 3. The
* descriptor of the method in UTF encoding.
*/
writeItems(svuidMethods, dos, true);
// 7. For each non-private method sorted by method name and signature:
// 1. The name of the method in UTF encoding.
// 2. The modifiers of the method written as a 32-bit integer.
// 3. The descriptor of the method in UTF encoding.
writeItems(svuidMethods, dataOutputStream, true);
dos.flush();
dataOutputStream.flush();
/*
* 8. The SHA-1 algorithm is executed on the stream of bytes
* produced by DataOutputStream and produces five 32-bit values
* sha[0..4].
*/
byte[] hashBytes = computeSHAdigest(bos.toByteArray());
// 8. The SHA-1 algorithm is executed on the stream of bytes produced by DataOutputStream and
// produces five 32-bit values sha[0..4].
byte[] hashBytes = computeSHAdigest(byteArrayOutputStream.toByteArray());
/*
* 9. The hash value is assembled from the first and second 32-bit
* values of the SHA-1 message digest. If the result of the message
* digest, the five 32-bit words H0 H1 H2 H3 H4, is in an array of
* five int values named sha, the hash value would be computed as
* follows:
*
* long hash = ((sha[0] >>> 24) & 0xFF) | ((sha[0] >>> 16) & 0xFF)
* << 8 | ((sha[0] >>> 8) & 0xFF) << 16 | ((sha[0] >>> 0) & 0xFF) <<
* 24 | ((sha[1] >>> 24) & 0xFF) << 32 | ((sha[1] >>> 16) & 0xFF) <<
* 40 | ((sha[1] >>> 8) & 0xFF) << 48 | ((sha[1] >>> 0) & 0xFF) <<
* 56;
*/
// 9. The hash value is assembled from the first and second 32-bit values of the SHA-1 message
// digest. If the result of the message digest, the five 32-bit words H0 H1 H2 H3 H4, is in an
// array of five int values named sha, the hash value would be computed as follows:
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
svuid = (svuid << 8) | (hashBytes[i] & 0xFF);
}
} finally {
// close the stream (if open)
if (dos != null) {
dos.close();
if (dataOutputStream != null) {
dataOutputStream.close();
}
}
@ -494,80 +457,65 @@ public class SerialVersionUIDAdder extends ClassVisitor {
/**
* Returns the SHA-1 message digest of the given value.
*
* @param value
* the value whose SHA message digest must be computed.
* @param value the value whose SHA message digest must be computed.
* @return the SHA-1 message digest of the given value.
*/
// DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
protected byte[] computeSHAdigest(final byte[] value) {
try {
return MessageDigest.getInstance("SHA").digest(value);
} catch (Exception e) {
throw new UnsupportedOperationException(e.toString());
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
}
}
/**
* Sorts the items in the collection and writes it to the data output stream
* Sorts the items in the collection and writes it to the given output stream.
*
* @param itemCollection
* collection of items
* @param dos
* a <code>DataOutputStream</code> value
* @param dotted
* a <code>boolean</code> value
* @exception IOException
* if an error occurs
* @param itemCollection a collection of items.
* @param dataOutputStream where the items must be written.
* @param dotted whether package names must use dots, instead of slashes.
* @exception IOException if an error occurs.
*/
private static void writeItems(final Collection<Item> itemCollection,
final DataOutput dos, final boolean dotted) throws IOException {
int size = itemCollection.size();
Item[] items = itemCollection.toArray(new Item[size]);
Arrays.sort(items);
for (int i = 0; i < size; i++) {
dos.writeUTF(items[i].name);
dos.writeInt(items[i].access);
dos.writeUTF(dotted ? items[i].desc.replace('/', '.')
: items[i].desc);
private static void writeItems(
final Collection<Item> itemCollection,
final DataOutput dataOutputStream,
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;
}
});
for (Item item : items) {
dataOutputStream.writeUTF(item.name);
dataOutputStream.writeInt(item.access);
dataOutputStream.writeUTF(dotted ? item.descriptor.replace('/', '.') : item.descriptor);
}
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Inner classes
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
private static class Item implements Comparable<Item> {
private static final class Item {
final String name;
final int access;
final String descriptor;
final String desc;
Item(final String name, final int access, final String desc) {
Item(final String name, final int access, final String descriptor) {
this.name = name;
this.access = access;
this.desc = desc;
}
public int compareTo(final Item other) {
int retVal = name.compareTo(other.name);
if (retVal == 0) {
retVal = desc.compareTo(other.desc);
}
return retVal;
}
@Override
public boolean equals(final Object o) {
if (o instanceof Item) {
return compareTo((Item) o) == 0;
}
return false;
}
@Override
public int hashCode() {
return (name + desc).hashCode();
this.descriptor = descriptor;
}
}
}

View file

@ -56,133 +56,149 @@
* 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 java.util.Stack;
import java.util.ArrayList;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
/**
* A {@link SignatureVisitor} adapter for type mapping.
* A {@link SignatureVisitor} that remaps types with a {@link Remapper}.
*
* @author Eugene Kuleshov
*/
public class SignatureRemapper extends SignatureVisitor {
private final SignatureVisitor v;
private final SignatureVisitor signatureVisitor;
private final Remapper remapper;
private Stack<String> classNames = new Stack<String>();
private ArrayList<String> classNames = new ArrayList<String>();
public SignatureRemapper(final SignatureVisitor v, final Remapper remapper) {
this(Opcodes.ASM6, v, remapper);
/**
* Constructs a new {@link SignatureRemapper}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #SignatureRemapper(int,SignatureVisitor,Remapper)} version.
*
* @param signatureVisitor the signature visitor this remapper must deleted to.
* @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);
}
protected SignatureRemapper(final int api, final SignatureVisitor v,
final Remapper 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}.
* @param signatureVisitor the signature visitor this remapper must deleted to.
* @param remapper the remapper to use to remap the types in the visited signature.
*/
protected SignatureRemapper(
final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
super(api);
this.v = v;
this.signatureVisitor = signatureVisitor;
this.remapper = remapper;
}
@Override
public void visitClassType(String name) {
classNames.push(name);
v.visitClassType(remapper.mapType(name));
public void visitClassType(final String name) {
classNames.add(name);
signatureVisitor.visitClassType(remapper.mapType(name));
}
@Override
public void visitInnerClassType(String name) {
String outerClassName = classNames.pop();
public void visitInnerClassType(final String name) {
String outerClassName = classNames.remove(classNames.size() - 1);
String className = outerClassName + '$' + name;
classNames.push(className);
classNames.add(className);
String remappedOuter = remapper.mapType(outerClassName) + '$';
String remappedName = remapper.mapType(className);
int index = remappedName.startsWith(remappedOuter) ? remappedOuter
.length() : remappedName.lastIndexOf('$') + 1;
v.visitInnerClassType(remappedName.substring(index));
int index =
remappedName.startsWith(remappedOuter)
? remappedOuter.length()
: remappedName.lastIndexOf('$') + 1;
signatureVisitor.visitInnerClassType(remappedName.substring(index));
}
@Override
public void visitFormalTypeParameter(String name) {
v.visitFormalTypeParameter(name);
public void visitFormalTypeParameter(final String name) {
signatureVisitor.visitFormalTypeParameter(name);
}
@Override
public void visitTypeVariable(String name) {
v.visitTypeVariable(name);
public void visitTypeVariable(final String name) {
signatureVisitor.visitTypeVariable(name);
}
@Override
public SignatureVisitor visitArrayType() {
v.visitArrayType();
signatureVisitor.visitArrayType();
return this;
}
@Override
public void visitBaseType(char descriptor) {
v.visitBaseType(descriptor);
public void visitBaseType(final char descriptor) {
signatureVisitor.visitBaseType(descriptor);
}
@Override
public SignatureVisitor visitClassBound() {
v.visitClassBound();
signatureVisitor.visitClassBound();
return this;
}
@Override
public SignatureVisitor visitExceptionType() {
v.visitExceptionType();
signatureVisitor.visitExceptionType();
return this;
}
@Override
public SignatureVisitor visitInterface() {
v.visitInterface();
signatureVisitor.visitInterface();
return this;
}
@Override
public SignatureVisitor visitInterfaceBound() {
v.visitInterfaceBound();
signatureVisitor.visitInterfaceBound();
return this;
}
@Override
public SignatureVisitor visitParameterType() {
v.visitParameterType();
signatureVisitor.visitParameterType();
return this;
}
@Override
public SignatureVisitor visitReturnType() {
v.visitReturnType();
signatureVisitor.visitReturnType();
return this;
}
@Override
public SignatureVisitor visitSuperclass() {
v.visitSuperclass();
signatureVisitor.visitSuperclass();
return this;
}
@Override
public void visitTypeArgument() {
v.visitTypeArgument();
signatureVisitor.visitTypeArgument();
}
@Override
public SignatureVisitor visitTypeArgument(char wildcard) {
v.visitTypeArgument(wildcard);
public SignatureVisitor visitTypeArgument(final char wildcard) {
signatureVisitor.visitTypeArgument(wildcard);
return this;
}
@Override
public void visitEnd() {
v.visitEnd();
classNames.pop();
signatureVisitor.visitEnd();
classNames.remove(classNames.size() - 1);
}
}

View file

@ -56,7 +56,6 @@
* 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 java.util.Collections;
@ -71,34 +70,57 @@ public class SimpleRemapper extends Remapper {
private final Map<String, String> mapping;
public SimpleRemapper(Map<String, String> mapping) {
/**
* Constructs a new {@link SimpleRemapper} with the given mapping.
*
* @param mapping a map specifying a remapping as follows:
* <ul>
* <li>for method names, the key is the owner, name and descriptor of the method (in the
* form &lt;owner&gt;.&lt;name&gt;&lt;descriptor&gt;), and the value is the new method
* name.
* <li>for invokedynamic method names, the key is the name and descriptor of the method (in
* the form .&lt;name&gt;&lt;descriptor&gt;), and the value is the new method name.
* <li>for field names, the key is the owner and name of the field (in the form
* &lt;owner&gt;.&lt;name&gt;), and the value is the new field name.
* <li>for internal names, the key is the old internal name, and the value is the new
* internal name.
* </ul>
*/
public SimpleRemapper(final Map<String, String> mapping) {
this.mapping = mapping;
}
public SimpleRemapper(String oldName, String newName) {
/**
* Constructs a new {@link SimpleRemapper} with the given mapping.
*
* @param oldName the key corresponding to a method, field or internal name (see {@link
* #SimpleRemapper(Map)} for the format of these keys).
* @param newName the new method, field or internal name.
*/
public SimpleRemapper(final String oldName, final String newName) {
this.mapping = Collections.singletonMap(oldName, newName);
}
@Override
public String mapMethodName(String owner, String name, String desc) {
String s = map(owner + '.' + name + desc);
return s == null ? name : s;
public String mapMethodName(final String owner, final String name, final String descriptor) {
String remappedName = map(owner + '.' + name + descriptor);
return remappedName == null ? name : remappedName;
}
@Override
public String mapInvokeDynamicMethodName(String name, String desc) {
String s = map('.' + name + desc);
return s == null ? name : s;
public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
String remappedName = map('.' + name + descriptor);
return remappedName == null ? name : remappedName;
}
@Override
public String mapFieldName(String owner, String name, String desc) {
String s = map(owner + '.' + name);
return s == null ? name : s;
public String mapFieldName(final String owner, final String name, final String descriptor) {
String remappedName = map(owner + '.' + name);
return remappedName == null ? name : remappedName;
}
@Override
public String map(String key) {
public String map(final String key) {
return mapping.get(key);
}
}

View file

@ -63,64 +63,93 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A {@link ClassVisitor} that merges clinit methods into a single one.
* A {@link ClassVisitor} that merges &lt;clinit&gt; methods into a single one. All the existing
* &lt;clinit&gt; methods are renamed, and a new one is created, which calls all the renamed
* methods.
*
* @author Eric Bruneton
*/
public class StaticInitMerger extends ClassVisitor {
private String name;
/** The internal name of the visited class. */
private String owner;
private MethodVisitor clinit;
/** The prefix to use to rename the existing &lt;clinit&gt; methods. */
private final String renamedClinitMethodPrefix;
private final String prefix;
/** The number of &lt;clinit&gt; methods visited so far. */
private int numClinitMethods;
private int counter;
/** The MethodVisitor for the merged &lt;clinit&gt; method. */
private MethodVisitor mergedClinitVisitor;
public StaticInitMerger(final String prefix, final ClassVisitor cv) {
this(Opcodes.ASM6, prefix, cv);
/**
* Constructs a new {@link StaticInitMerger}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #StaticInitMerger(int, String, ClassVisitor)} version.
*
* @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.
*/
public StaticInitMerger(final String prefix, final ClassVisitor classVisitor) {
this(Opcodes.ASM7, prefix, classVisitor);
}
protected StaticInitMerger(final int api, final String prefix,
final ClassVisitor cv) {
super(api, cv);
this.prefix = prefix;
/**
* 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}.
* @param prefix the prefix to use to rename the existing &lt;clinit&gt; methods.
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.
*/
protected StaticInitMerger(final int api, final String prefix, final ClassVisitor classVisitor) {
super(api, classVisitor);
this.renamedClinitMethodPrefix = prefix;
}
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
cv.visit(version, access, name, signature, superName, interfaces);
this.name = name;
super.visit(version, access, name, signature, superName, interfaces);
this.owner = name;
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodVisitor mv;
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
MethodVisitor methodVisitor;
if ("<clinit>".equals(name)) {
int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
String n = prefix + counter++;
mv = cv.visitMethod(a, n, desc, signature, exceptions);
int newAccess = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
String newName = renamedClinitMethodPrefix + numClinitMethods++;
methodVisitor = super.visitMethod(newAccess, newName, descriptor, signature, exceptions);
if (clinit == null) {
clinit = cv.visitMethod(a, name, desc, null, null);
if (mergedClinitVisitor == null) {
mergedClinitVisitor = super.visitMethod(newAccess, name, descriptor, null, null);
}
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc,
false);
mergedClinitVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, newName, descriptor, false);
} else {
mv = cv.visitMethod(access, name, desc, signature, exceptions);
methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
}
return mv;
return methodVisitor;
}
@Override
public void visitEnd() {
if (clinit != null) {
clinit.visitInsn(Opcodes.RETURN);
clinit.visitMaxs(0, 0);
if (mergedClinitVisitor != null) {
mergedClinitVisitor.visitInsn(Opcodes.RETURN);
mergedClinitVisitor.visitMaxs(0, 0);
}
cv.visitEnd();
super.visitEnd();
}
}

View file

@ -72,15 +72,11 @@ public interface TableSwitchGenerator {
/**
* Generates the code for a switch case.
*
* @param key
* the switch case key.
* @param end
* a label that corresponds to the end of the switch statement.
* @param key the switch case key.
* @param end a label that corresponds to the end of the switch statement.
*/
void generateCase(int key, Label end);
/**
* Generates the code for the default switch case.
*/
/** Generates the code for the default switch case. */
void generateDefault();
}

View file

@ -56,65 +56,89 @@
* 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 java.util.Collections;
import java.util.Comparator;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.tree.MethodNode;
import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
/**
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers
* are sorted in a method innermost-to-outermost. This allows the programmer to
* add handlers without worrying about ordering them correctly with respect to
* existing, in-code handlers.
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers are sorted in a
* method innermost-to-outermost. This allows the programmer to add handlers without worrying about
* ordering them correctly with respect to existing, in-code handlers.
*
* Behavior is only defined for properly-nested handlers. If any "try" blocks
* overlap (something that isn't possible in Java code) then this may not do
* what you want. In fact, this adapter just sorts by the length of the "try"
* block, taking advantage of the fact that a given try block must be larger
* than any block it contains).
* <p>Behavior is only defined for properly-nested handlers. If any "try" blocks overlap (something
* that isn't possible in Java code) then this may not do what you want. In fact, this adapter just
* sorts by the length of the "try" block, taking advantage of the fact that a given try block must
* be larger than any block it contains).
*
* @author Adrian Sampson
*/
public class TryCatchBlockSorter extends MethodNode {
public TryCatchBlockSorter(final MethodVisitor mv, final int access,
final String name, final String desc, final String signature,
/**
* Constructs a new {@link TryCatchBlockSorter}.
*
* @param methodVisitor the method visitor to which this visitor must delegate method calls. May
* be {@literal null}.
* @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.
* @param descriptor the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param signature the method's signature. May be {@literal null} if the method parameters,
* return type and exceptions do not use generic types.
* @param exceptions the internal names of the method's exception classes (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
*/
public TryCatchBlockSorter(
final MethodVisitor methodVisitor,
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
this(Opcodes.ASM6, mv, access, name, desc, signature, exceptions);
this(Opcodes.ASM7, methodVisitor, access, name, descriptor, signature, exceptions);
if (getClass() != TryCatchBlockSorter.class) {
throw new IllegalStateException();
}
}
protected TryCatchBlockSorter(final int api, final MethodVisitor mv,
final int access, final String name, final String desc,
final String signature, final String[] exceptions) {
super(api, access, name, desc, signature, exceptions);
this.mv = mv;
protected TryCatchBlockSorter(
final int api,
final MethodVisitor methodVisitor,
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
super(api, access, name, descriptor, signature, exceptions);
this.mv = methodVisitor;
}
@Override
public void visitEnd() {
// Compares TryCatchBlockNodes by the length of their "try" block.
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() {
// Sort the TryCatchBlockNode elements by the length of their "try" block.
Collections.sort(
tryCatchBlocks,
new Comparator<TryCatchBlockNode>() {
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) {
int len1 = blockLength(t1);
int len2 = blockLength(t2);
return len1 - len2;
@Override
public int compare(
final TryCatchBlockNode tryCatchBlockNode1,
final TryCatchBlockNode tryCatchBlockNode2) {
return blockLength(tryCatchBlockNode1) - blockLength(tryCatchBlockNode2);
}
private int blockLength(TryCatchBlockNode block) {
int startidx = instructions.indexOf(block.start);
int endidx = instructions.indexOf(block.end);
return endidx - startidx;
private int blockLength(final TryCatchBlockNode tryCatchBlockNode) {
int startIndex = instructions.indexOf(tryCatchBlockNode.start);
int endIndex = instructions.indexOf(tryCatchBlockNode.end);
return endIndex - startIndex;
}
};
Collections.sort(tryCatchBlocks, comp);
// Updates the 'target' of each try catch block annotation.
});
// Update the 'target' of each try catch block annotation.
for (int i = 0; i < tryCatchBlocks.size(); ++i) {
tryCatchBlocks.get(i).updateIndex(i);
}

View file

@ -59,125 +59,133 @@
package jdk.internal.org.objectweb.asm.signature;
/**
* A type signature parser to make a signature visitor visit an existing
* signature.
* A parser for signature literals, as defined in the Java Virtual Machine Specification (JVMS), to
* visit them with a SignatureVisitor.
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.9.1">JVMS
* 4.7.9.1</a>
* @author Thomas Hallgren
* @author Eric Bruneton
*/
public class SignatureReader {
/**
* The signature to be read.
*/
private final String signature;
/** The JVMS signature to be read. */
private final String signatureValue;
/**
* Constructs a {@link SignatureReader} for the given signature.
*
* @param signature
* A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or
* <i>FieldTypeSignature</i>.
* @param signature A <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
*/
public SignatureReader(final String signature) {
this.signature = signature;
this.signatureValue = signature;
}
/**
* Makes the given visitor visit the signature of this
* {@link SignatureReader}. This signature is the one specified in the
* constructor (see {@link #SignatureReader(String) SignatureReader}). This
* method is intended to be called on a {@link SignatureReader} that was
* created using a <i>ClassSignature</i> (such as the <code>signature</code>
* parameter of the {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit
* ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the
* <code>signature</code> parameter of the
* {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod
* ClassVisitor.visitMethod} method).
* Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
* the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
* be called on a {@link SignatureReader} that was created using a <i>ClassSignature</i> (such as
* the <code>signature</code> parameter of the {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}
* method) or a <i>MethodSignature</i> (such as the <code>signature</code> parameter of the {@link
* jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod} method).
*
* @param v
* the visitor that must visit this signature.
* @param signatureVistor the visitor that must visit this signature.
*/
public void accept(final SignatureVisitor v) {
String signature = this.signature;
int len = signature.length();
int pos;
char c;
public void accept(final SignatureVisitor signatureVistor) {
String signature = this.signatureValue;
int length = signature.length();
int offset; // Current offset in the parsed signature (parsed from left to right).
char currentChar; // The signature character at 'offset', or just before.
// If the signature starts with '<', it starts with TypeParameters, i.e. a formal type parameter
// identifier, followed by one or more pair ':',ReferenceTypeSignature (for its class bound and
// interface bounds).
if (signature.charAt(0) == '<') {
pos = 2;
// Invariant: offset points to the second character of a formal type parameter name at the
// beginning of each iteration of the loop below.
offset = 2;
do {
int end = signature.indexOf(':', pos);
v.visitFormalTypeParameter(signature.substring(pos - 1, end));
pos = end + 1;
// The formal type parameter name is everything between offset - 1 and the first ':'.
int classBoundStartOffset = signature.indexOf(':', offset);
signatureVistor.visitFormalTypeParameter(
signature.substring(offset - 1, classBoundStartOffset));
c = signature.charAt(pos);
if (c == 'L' || c == '[' || c == 'T') {
pos = parseType(signature, pos, v.visitClassBound());
// If the character after the ':' class bound marker is not the start of a
// ReferenceTypeSignature, it means the class bound is empty (which is a valid case).
offset = classBoundStartOffset + 1;
currentChar = signature.charAt(offset);
if (currentChar == 'L' || currentChar == '[' || currentChar == 'T') {
offset = parseType(signature, offset, signatureVistor.visitClassBound());
}
while ((c = signature.charAt(pos++)) == ':') {
pos = parseType(signature, pos, v.visitInterfaceBound());
// While the character after the class bound or after the last parsed interface bound
// is ':', we need to parse another interface bound.
while ((currentChar = signature.charAt(offset++)) == ':') {
offset = parseType(signature, offset, signatureVistor.visitInterfaceBound());
}
} while (c != '>');
// At this point a TypeParameter has been fully parsed, and we need to parse the next one
// (note that currentChar is now the first character of the next TypeParameter, and that
// offset points to the second character), unless the character just after this
// TypeParameter signals the end of the TypeParameters.
} while (currentChar != '>');
} else {
pos = 0;
offset = 0;
}
if (signature.charAt(pos) == '(') {
pos++;
while (signature.charAt(pos) != ')') {
pos = parseType(signature, pos, v.visitParameterType());
// If the (optional) TypeParameters is followed by '(' this means we are parsing a
// MethodSignature, which has JavaTypeSignature type inside parentheses, followed by a Result
// type and optional ThrowsSignature types.
if (signature.charAt(offset) == '(') {
offset++;
while (signature.charAt(offset) != ')') {
offset = parseType(signature, offset, signatureVistor.visitParameterType());
}
pos = parseType(signature, pos + 1, v.visitReturnType());
while (pos < len) {
pos = parseType(signature, pos + 1, v.visitExceptionType());
// Use offset + 1 to skip ')'.
offset = parseType(signature, offset + 1, signatureVistor.visitReturnType());
while (offset < length) {
// Use offset + 1 to skip the first character of a ThrowsSignature, i.e. '^'.
offset = parseType(signature, offset + 1, signatureVistor.visitExceptionType());
}
} else {
pos = parseType(signature, pos, v.visitSuperclass());
while (pos < len) {
pos = parseType(signature, pos, v.visitInterface());
// Otherwise we are parsing a ClassSignature (by hypothesis on the method input), which has
// one or more ClassTypeSignature for the super class and the implemented interfaces.
offset = parseType(signature, offset, signatureVistor.visitSuperclass());
while (offset < length) {
offset = parseType(signature, offset, signatureVistor.visitInterface());
}
}
}
/**
* Makes the given visitor visit the signature of this
* {@link SignatureReader}. This signature is the one specified in the
* constructor (see {@link #SignatureReader(String) SignatureReader}). This
* method is intended to be called on a {@link SignatureReader} that was
* created using a <i>FieldTypeSignature</i>, such as the
* <code>signature</code> parameter of the
* {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField ClassVisitor.visitField}
* or {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable
* MethodVisitor.visitLocalVariable} methods.
* Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
* the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
* be called on a {@link SignatureReader} that was created using a <i>JavaTypeSignature</i>, such
* as the <code>signature</code> parameter of the {@link
* jdk.internal.org.objectweb.asm.ClassVisitor#visitField} or {@link
* jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable} methods.
*
* @param v
* the visitor that must visit this signature.
* @param signatureVisitor the visitor that must visit this signature.
*/
public void acceptType(final SignatureVisitor v) {
parseType(this.signature, 0, v);
public void acceptType(final SignatureVisitor signatureVisitor) {
parseType(signatureValue, 0, signatureVisitor);
}
/**
* Parses a field type signature and makes the given visitor visit it.
* Parses a JavaTypeSignature and makes the given visitor visit it.
*
* @param signature
* a string containing the signature that must be parsed.
* @param pos
* index of the first character of the signature to parsed.
* @param v
* the visitor that must visit this signature.
* @param signature a string containing the signature that must be parsed.
* @param startOffset index of the first character of the signature to parsed.
* @param signatureVisitor the visitor that must visit this signature.
* @return the index of the first character after the parsed signature.
*/
private static int parseType(final String signature, int pos,
final SignatureVisitor v) {
char c;
int start, end;
boolean visited, inner;
String name;
private static int parseType(
final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
int offset = startOffset; // Current offset in the parsed signature.
char currentChar = signature.charAt(offset++); // The signature character at 'offset'.
switch (c = signature.charAt(pos++)) {
// Switch based on the first character of the JavaTypeSignature, which indicates its kind.
switch (currentChar) {
case 'Z':
case 'C':
case 'B':
@ -187,71 +195,89 @@ public class SignatureReader {
case 'J':
case 'D':
case 'V':
v.visitBaseType(c);
return pos;
// Case of a BaseType or a VoidDescriptor.
signatureVisitor.visitBaseType(currentChar);
return offset;
case '[':
return parseType(signature, pos, v.visitArrayType());
// Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
return parseType(signature, offset, signatureVisitor.visitArrayType());
case 'T':
end = signature.indexOf(';', pos);
v.visitTypeVariable(signature.substring(pos, end));
return end + 1;
// Case of TypeVariableSignature, an identifier between 'T' and ';'.
int endOffset = signature.indexOf(';', offset);
signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
return endOffset + 1;
default: // case 'L':
start = pos;
visited = false;
inner = false;
for (;;) {
switch (c = signature.charAt(pos++)) {
case '.':
case ';':
case 'L':
// Case of a ClassTypeSignature, which ends with ';'.
// These signatures have a main class type followed by zero or more inner class types
// (separated by '.'). Each can have type arguments, inside '<' and '>'.
int start = offset; // The start offset of the currently parsed main or inner class name.
boolean visited = false; // Whether the currently parsed class name has been visited.
boolean inner = false; // Whether we are currently parsing an inner class type.
// Parses the signature, one character at a time.
while (true) {
currentChar = signature.charAt(offset++);
if (currentChar == '.' || currentChar == ';') {
// If a '.' or ';' is encountered, this means we have fully parsed the main class name
// or an inner class name. This name may already have been visited it is was followed by
// type arguments between '<' and '>'. If not, we need to visit it here.
if (!visited) {
name = signature.substring(start, pos - 1);
String name = signature.substring(start, offset - 1);
if (inner) {
v.visitInnerClassType(name);
signatureVisitor.visitInnerClassType(name);
} else {
v.visitClassType(name);
signatureVisitor.visitClassType(name);
}
}
if (c == ';') {
v.visitEnd();
return pos;
// If we reached the end of the ClassTypeSignature return, otherwise start the parsing
// of a new class name, which is necessarily an inner class name.
if (currentChar == ';') {
signatureVisitor.visitEnd();
break;
}
start = pos;
start = offset;
visited = false;
inner = true;
break;
case '<':
name = signature.substring(start, pos - 1);
} else if (currentChar == '<') {
// If a '<' is encountered, this means we have fully parsed the main class name or an
// inner class name, and that we now need to parse TypeArguments. First, we need to
// visit the parsed class name.
String name = signature.substring(start, offset - 1);
if (inner) {
v.visitInnerClassType(name);
signatureVisitor.visitInnerClassType(name);
} else {
v.visitClassType(name);
signatureVisitor.visitClassType(name);
}
visited = true;
top: for (;;) {
switch (c = signature.charAt(pos)) {
case '>':
break top;
// Now, parse the TypeArgument(s), one at a time.
while ((currentChar = signature.charAt(offset)) != '>') {
switch (currentChar) {
case '*':
++pos;
v.visitTypeArgument();
// Unbounded TypeArgument.
++offset;
signatureVisitor.visitTypeArgument();
break;
case '+':
case '-':
pos = parseType(signature, pos + 1,
v.visitTypeArgument(c));
// Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
offset =
parseType(
signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
break;
default:
pos = parseType(signature, pos,
v.visitTypeArgument('='));
// Instanceof TypeArgument. The '=' is implicit.
offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
break;
}
}
}
}
return offset;
default:
throw new IllegalArgumentException();
}
}
}

View file

@ -61,23 +61,19 @@ package jdk.internal.org.objectweb.asm.signature;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A visitor to visit a generic signature. The methods of this interface must be
* called in one of the three following orders (the last one is the only valid
* order for a {@link SignatureVisitor} that is returned by a method of this
* interface):
* A visitor to visit a generic signature. The methods of this interface must be called in one of
* the three following orders (the last one is the only valid order for a {@link SignatureVisitor}
* that is returned by a method of this interface):
*
* <ul>
* <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt>
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
* <tt>visitSuperclass</tt> <tt>visitInterface</tt>* )</li>
* <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt>
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* (
* <tt>visitParameterType</tt>* <tt>visitReturnType</tt>
* <tt>visitExceptionType</tt>* )</li>
* <li><i>TypeSignature</i> = <tt>visitBaseType</tt> |
* <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | (
* <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
* <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt>
* ) )</li>
* <li><i>ClassSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
* visitInterfaceBound}* )* ({@code visitSuperclass} {@code visitInterface}* )
* <li><i>MethodSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
* visitInterfaceBound}* )* ({@code visitParameterType}* {@code visitReturnType} {@code
* visitExceptionType}* )
* <li><i>TypeSignature</i> = {@code visitBaseType} | {@code visitTypeVariable} | {@code
* visitArrayType} | ( {@code visitClassType} {@code visitTypeArgument}* ( {@code
* visitInnerClassType} {@code visitTypeArgument}* )* {@code visitEnd} ) )
* </ul>
*
* @author Thomas Hallgren
@ -85,36 +81,29 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public abstract class SignatureVisitor {
/**
* Wildcard for an "extends" type argument.
*/
public final static char EXTENDS = '+';
/** Wildcard for an "extends" type argument. */
public static final char EXTENDS = '+';
/** Wildcard for a "super" type argument. */
public static final char SUPER = '-';
/** Wildcard for a normal type argument. */
public static final char INSTANCEOF = '=';
/**
* Wildcard for a "super" type argument.
*/
public final static char SUPER = '-';
/**
* Wildcard for a normal type argument.
*/
public final static char INSTANCEOF = '=';
/**
* The ASM API version implemented by this visitor. The value of this field
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
protected final int api;
/**
* Constructs a new {@link SignatureVisitor}.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public SignatureVisitor(final int api) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
throw new IllegalArgumentException();
}
this.api = api;
@ -123,11 +112,9 @@ public abstract class SignatureVisitor {
/**
* Visits a formal type parameter.
*
* @param name
* the name of the formal parameter.
* @param name the name of the formal parameter.
*/
public void visitFormalTypeParameter(String name) {
}
public void visitFormalTypeParameter(final String name) {}
/**
* Visits the class bound of the last visited formal type parameter.
@ -150,8 +137,7 @@ public abstract class SignatureVisitor {
/**
* Visits the type of the super class.
*
* @return a non null visitor to visit the signature of the super class
* type.
* @return a non null visitor to visit the signature of the super class type.
*/
public SignatureVisitor visitSuperclass() {
return this;
@ -196,72 +182,53 @@ public abstract class SignatureVisitor {
/**
* Visits a signature corresponding to a primitive type.
*
* @param descriptor
* the descriptor of the primitive type, or 'V' for <tt>void</tt>
* .
* @param descriptor the descriptor of the primitive type, or 'V' for {@code void} .
*/
public void visitBaseType(char descriptor) {
}
public void visitBaseType(final char descriptor) {}
/**
* Visits a signature corresponding to a type variable.
*
* @param name
* the name of the type variable.
* @param name the name of the type variable.
*/
public void visitTypeVariable(String name) {
}
public void visitTypeVariable(final String name) {}
/**
* Visits a signature corresponding to an array type.
*
* @return a non null visitor to visit the signature of the array element
* type.
* @return a non null visitor to visit the signature of the array element type.
*/
public SignatureVisitor visitArrayType() {
return this;
}
/**
* Starts the visit of a signature corresponding to a class or interface
* type.
* Starts the visit of a signature corresponding to a class or interface type.
*
* @param name
* the internal name of the class or interface.
* @param name the internal name of the class or interface.
*/
public void visitClassType(String name) {
}
public void visitClassType(final String name) {}
/**
* Visits an inner class.
*
* @param name
* the local name of the inner class in its enclosing class.
* @param name the local name of the inner class in its enclosing class.
*/
public void visitInnerClassType(String name) {
}
public void visitInnerClassType(final String name) {}
/**
* Visits an unbounded type argument of the last visited class or inner
* class type.
*/
public void visitTypeArgument() {
}
/** Visits an unbounded type argument of the last visited class or inner class type. */
public void visitTypeArgument() {}
/**
* Visits a type argument of the last visited class or inner class type.
*
* @param wildcard
* '+', '-' or '='.
* @param wildcard '+', '-' or '='.
* @return a non null visitor to visit the signature of the type argument.
*/
public SignatureVisitor visitTypeArgument(char wildcard) {
public SignatureVisitor visitTypeArgument(final char wildcard) {
return this;
}
/**
* Ends the visit of a signature corresponding to a class or interface type.
*/
public void visitEnd() {
}
/** Ends the visit of a signature corresponding to a class or interface type. */
public void visitEnd() {}
}

View file

@ -61,55 +61,61 @@ package jdk.internal.org.objectweb.asm.signature;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A signature visitor that generates signatures in string format.
* A SignatureVisitor that generates signature literals, 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.9.1">JVMS
* 4.7.9.1</a>
* @author Thomas Hallgren
* @author Eric Bruneton
*/
public class SignatureWriter extends SignatureVisitor {
/**
* Builder used to construct the signature.
*/
private final StringBuilder buf = new StringBuilder();
/** The builder used to construct the visited signature. */
private final StringBuilder stringBuilder = new StringBuilder();
/**
* Indicates if the signature contains formal type parameters.
*/
/** Whether the visited signature contains formal type parameters. */
private boolean hasFormals;
/**
* Indicates if the signature contains method parameter types.
*/
/** Whether the visited signature contains method parameter types. */
private boolean hasParameters;
/**
* Stack used to keep track of class types that have arguments. Each element
* of this stack is a boolean encoded in one bit. The top of the stack is
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping =
* /2.
* The stack used to keep track of class types that have arguments. Each element of this stack is
* a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
* = *2, pushing true = *2+1, popping = /2.
*
* <p>Class type arguments must be surrounded with '&lt;' and '&gt;' and, because
*
* <ol>
* <li>class types can be nested (because type arguments can themselves be class types),
* <li>SignatureWriter always returns 'this' in each visit* method (to avoid allocating new
* SignatureWriter instances),
* </ol>
*
* <p>we need a stack to properly balance these 'parentheses'. A new element is pushed on this
* stack for each new visited type, and popped when the visit of this type ends (either is
* visitEnd, or because visitInnerClassType is called).
*/
private int argumentStack;
/**
* Constructs a new {@link SignatureWriter} object.
*/
/** Constructs a new {@link SignatureWriter}. */
public SignatureWriter() {
super(Opcodes.ASM6);
super(Opcodes.ASM7);
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Implementation of the SignatureVisitor interface
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
@Override
public void visitFormalTypeParameter(final String name) {
if (!hasFormals) {
hasFormals = true;
buf.append('<');
stringBuilder.append('<');
}
buf.append(name);
buf.append(':');
stringBuilder.append(name);
stringBuilder.append(':');
}
@Override
@ -119,7 +125,7 @@ public class SignatureWriter extends SignatureVisitor {
@Override
public SignatureVisitor visitInterfaceBound() {
buf.append(':');
stringBuilder.append(':');
return this;
}
@ -139,7 +145,7 @@ public class SignatureWriter extends SignatureVisitor {
endFormals();
if (!hasParameters) {
hasParameters = true;
buf.append('(');
stringBuilder.append('(');
}
return this;
}
@ -148,68 +154,78 @@ public class SignatureWriter extends SignatureVisitor {
public SignatureVisitor visitReturnType() {
endFormals();
if (!hasParameters) {
buf.append('(');
stringBuilder.append('(');
}
buf.append(')');
stringBuilder.append(')');
return this;
}
@Override
public SignatureVisitor visitExceptionType() {
buf.append('^');
stringBuilder.append('^');
return this;
}
@Override
public void visitBaseType(final char descriptor) {
buf.append(descriptor);
stringBuilder.append(descriptor);
}
@Override
public void visitTypeVariable(final String name) {
buf.append('T');
buf.append(name);
buf.append(';');
stringBuilder.append('T');
stringBuilder.append(name);
stringBuilder.append(';');
}
@Override
public SignatureVisitor visitArrayType() {
buf.append('[');
stringBuilder.append('[');
return this;
}
@Override
public void visitClassType(final String name) {
buf.append('L');
buf.append(name);
stringBuilder.append('L');
stringBuilder.append(name);
// Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
// we can tell at this point).
argumentStack *= 2;
}
@Override
public void visitInnerClassType(final String name) {
endArguments();
buf.append('.');
buf.append(name);
stringBuilder.append('.');
stringBuilder.append(name);
// Pushes 'false' on the stack, meaning that this type does not have type arguments (as far as
// we can tell at this point).
argumentStack *= 2;
}
@Override
public void visitTypeArgument() {
// If the top of the stack is 'false', this means we are visiting the first type argument of the
// currently visited type. We therefore need to append a '<', and to replace the top stack
// element with 'true' (meaning that the current type does have type arguments).
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
argumentStack |= 1;
stringBuilder.append('<');
}
buf.append('*');
stringBuilder.append('*');
}
@Override
public SignatureVisitor visitTypeArgument(final char wildcard) {
// If the top of the stack is 'false', this means we are visiting the first type argument of the
// currently visited type. We therefore need to append a '<', and to replace the top stack
// element with 'true' (meaning that the current type does have type arguments).
if (argumentStack % 2 == 0) {
++argumentStack;
buf.append('<');
argumentStack |= 1;
stringBuilder.append('<');
}
if (wildcard != '=') {
buf.append(wildcard);
stringBuilder.append(wildcard);
}
return this;
}
@ -217,7 +233,7 @@ public class SignatureWriter extends SignatureVisitor {
@Override
public void visitEnd() {
endArguments();
buf.append(';');
stringBuilder.append(';');
}
/**
@ -227,29 +243,28 @@ public class SignatureWriter extends SignatureVisitor {
*/
@Override
public String toString() {
return buf.toString();
return stringBuilder.toString();
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Utility methods
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Ends the formal type parameters section of the signature.
*/
/** Ends the formal type parameters section of the signature. */
private void endFormals() {
if (hasFormals) {
hasFormals = false;
buf.append('>');
stringBuilder.append('>');
}
}
/**
* Ends the type arguments of a class or inner class type.
*/
/** Ends the type arguments of a class or inner class type. */
private void endArguments() {
if (argumentStack % 2 != 0) {
buf.append('>');
// If the top of the stack is 'true', this means that some type arguments have been visited for
// the type whose visit is now ending. We therefore need to append a '>', and to pop one element
// from the stack.
if (argumentStack % 2 == 1) {
stringBuilder.append('>');
}
argumentStack /= 2;
}

View file

@ -61,147 +61,98 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a bytecode instruction. <i>An instruction can appear
* at most once in at most one {@link InsnList} at a time</i>.
* A node that represents a bytecode instruction. <i>An instruction can appear at most once in at
* most one {@link InsnList} at a time</i>.
*
* @author Eric Bruneton
*/
public abstract class AbstractInsnNode {
/**
* The type of {@link InsnNode} instructions.
*/
/** The type of {@link InsnNode} instructions. */
public static final int INSN = 0;
/**
* The type of {@link IntInsnNode} instructions.
*/
/** The type of {@link IntInsnNode} instructions. */
public static final int INT_INSN = 1;
/**
* The type of {@link VarInsnNode} instructions.
*/
/** The type of {@link VarInsnNode} instructions. */
public static final int VAR_INSN = 2;
/**
* The type of {@link TypeInsnNode} instructions.
*/
/** The type of {@link TypeInsnNode} instructions. */
public static final int TYPE_INSN = 3;
/**
* The type of {@link FieldInsnNode} instructions.
*/
/** The type of {@link FieldInsnNode} instructions. */
public static final int FIELD_INSN = 4;
/**
* The type of {@link MethodInsnNode} instructions.
*/
/** The type of {@link MethodInsnNode} instructions. */
public static final int METHOD_INSN = 5;
/**
* The type of {@link InvokeDynamicInsnNode} instructions.
*/
/** The type of {@link InvokeDynamicInsnNode} instructions. */
public static final int INVOKE_DYNAMIC_INSN = 6;
/**
* The type of {@link JumpInsnNode} instructions.
*/
/** The type of {@link JumpInsnNode} instructions. */
public static final int JUMP_INSN = 7;
/**
* The type of {@link LabelNode} "instructions".
*/
/** The type of {@link LabelNode} "instructions". */
public static final int LABEL = 8;
/**
* The type of {@link LdcInsnNode} instructions.
*/
/** The type of {@link LdcInsnNode} instructions. */
public static final int LDC_INSN = 9;
/**
* The type of {@link IincInsnNode} instructions.
*/
/** The type of {@link IincInsnNode} instructions. */
public static final int IINC_INSN = 10;
/**
* The type of {@link TableSwitchInsnNode} instructions.
*/
/** The type of {@link TableSwitchInsnNode} instructions. */
public static final int TABLESWITCH_INSN = 11;
/**
* The type of {@link LookupSwitchInsnNode} instructions.
*/
/** The type of {@link LookupSwitchInsnNode} instructions. */
public static final int LOOKUPSWITCH_INSN = 12;
/**
* The type of {@link MultiANewArrayInsnNode} instructions.
*/
/** The type of {@link MultiANewArrayInsnNode} instructions. */
public static final int MULTIANEWARRAY_INSN = 13;
/**
* The type of {@link FrameNode} "instructions".
*/
/** The type of {@link FrameNode} "instructions". */
public static final int FRAME = 14;
/**
* The type of {@link LineNumberNode} "instructions".
*/
/** The type of {@link LineNumberNode} "instructions". */
public static final int LINE = 15;
/**
* The opcode of this instruction.
*/
/** The opcode of this instruction. */
protected int opcode;
/**
* The runtime visible type annotations of this instruction. This field is
* only used for real instructions (i.e. not for labels, frames, or line
* number nodes). This list is a list of {@link TypeAnnotationNode} objects.
* May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
* The runtime visible type annotations of this instruction. This field is only used for real
* instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
* TypeAnnotationNode} objects. May be {@literal null}.
*/
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this instruction. This field is
* only used for real instructions (i.e. not for labels, frames, or line
* number nodes). This list is a list of {@link TypeAnnotationNode} objects.
* May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
* The runtime invisible type annotations of this instruction. This field is only used for real
* instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
* TypeAnnotationNode} objects. May be {@literal null}.
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* Previous instruction in the list to which this instruction belongs.
*/
AbstractInsnNode prev;
/** The previous instruction in the list to which this instruction belongs. */
AbstractInsnNode previousInsn;
/** The next instruction in the list to which this instruction belongs. */
AbstractInsnNode nextInsn;
/**
* Next instruction in the list to which this instruction belongs.
*/
AbstractInsnNode next;
/**
* Index of this instruction in the list to which it belongs. The value of
* this field is correct only when {@link InsnList#cache} is not null. A
* value of -1 indicates that this instruction does not belong to any
* {@link InsnList}.
* The index of this instruction in the list to which it belongs. The value of this field is
* correct only when {@link InsnList#cache} is not null. A value of -1 indicates that this
* instruction does not belong to any {@link InsnList}.
*/
int index;
/**
* Constructs a new {@link AbstractInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed.
* @param opcode the opcode of the instruction to be constructed.
*/
protected AbstractInsnNode(final int opcode) {
this.opcode = opcode;
@ -220,103 +171,93 @@ public abstract class AbstractInsnNode {
/**
* Returns the type of this instruction.
*
* @return the type of this instruction, i.e. one the constants defined in
* this class.
* @return the type of this instruction, i.e. one the constants defined in this class.
*/
public abstract int getType();
/**
* Returns the previous instruction in the list to which this instruction
* belongs, if any.
* Returns the previous instruction in the list to which this instruction belongs, if any.
*
* @return the previous instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
* @return the previous instruction in the list to which this instruction belongs, if any. May be
* {@literal null}.
*/
public AbstractInsnNode getPrevious() {
return prev;
return previousInsn;
}
/**
* Returns the next instruction in the list to which this instruction
* belongs, if any.
* Returns the next instruction in the list to which this instruction belongs, if any.
*
* @return the next instruction in the list to which this instruction
* belongs, if any. May be <tt>null</tt>.
* @return the next instruction in the list to which this instruction belongs, if any. May be
* {@literal null}.
*/
public AbstractInsnNode getNext() {
return next;
return nextInsn;
}
/**
* Makes the given code visitor visit this instruction.
* Makes the given method visitor visit this instruction.
*
* @param cv
* a code visitor.
* @param methodVisitor a method visitor.
*/
public abstract void accept(final MethodVisitor cv);
public abstract void accept(MethodVisitor methodVisitor);
/**
* Makes the given visitor visit the annotations of this instruction.
*
* @param mv
* a method visitor.
* @param methodVisitor a method visitor.
*/
protected final void acceptAnnotations(final MethodVisitor mv) {
int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
true));
protected final void acceptAnnotations(final MethodVisitor methodVisitor) {
if (visibleTypeAnnotations != null) {
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
typeAnnotation.accept(
methodVisitor.visitInsnAnnotation(
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(
methodVisitor.visitInsnAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
}
/**
* Returns a copy of this instruction.
*
* @param labels
* a map from LabelNodes to cloned LabelNodes.
* @return a copy of this instruction. The returned instruction does not
* belong to any {@link InsnList}.
* @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* @return a copy of this instruction. The returned instruction does not belong to any {@link
* InsnList}.
*/
public abstract AbstractInsnNode clone(
final Map<LabelNode, LabelNode> labels);
public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
/**
* Returns the clone of the given label.
*
* @param label
* a label.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @param label a label.
* @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* @return the clone of the given label.
*/
static LabelNode clone(final LabelNode label,
final Map<LabelNode, LabelNode> map) {
return map.get(label);
static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> clonedLabels) {
return clonedLabels.get(label);
}
/**
* Returns the clones of the given labels.
*
* @param labels
* a list of labels.
* @param map
* a map from LabelNodes to cloned LabelNodes.
* @param labels a list of labels.
* @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* @return the clones of the given labels.
*/
static LabelNode[] clone(final List<LabelNode> labels,
final Map<LabelNode, LabelNode> map) {
static LabelNode[] clone(
final List<LabelNode> labels, final Map<LabelNode, LabelNode> clonedLabels) {
LabelNode[] clones = new LabelNode[labels.size()];
for (int i = 0; i < clones.length; ++i) {
clones[i] = map.get(labels.get(i));
for (int i = 0, n = clones.length; i < n; ++i) {
clones[i] = clonedLabels.get(labels.get(i));
}
return clones;
}
@ -324,30 +265,30 @@ public abstract class AbstractInsnNode {
/**
* Clones the annotations of the given instruction into this instruction.
*
* @param insn
* the source instruction.
* @param insnNode the source instruction.
* @return this instruction.
*/
protected final AbstractInsnNode cloneAnnotations(
final AbstractInsnNode insn) {
if (insn.visibleTypeAnnotations != null) {
protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
if (insnNode.visibleTypeAnnotations != null) {
this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) {
TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
src.typePath, src.desc);
src.accept(ann);
this.visibleTypeAnnotations.add(ann);
for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
TypeAnnotationNode cloneAnnotation =
new TypeAnnotationNode(
sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
sourceAnnotation.accept(cloneAnnotation);
this.visibleTypeAnnotations.add(cloneAnnotation);
}
}
if (insn.invisibleTypeAnnotations != null) {
if (insnNode.invisibleTypeAnnotations != null) {
this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) {
TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef,
src.typePath, src.desc);
src.accept(ann);
this.invisibleTypeAnnotations.add(ann);
for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
TypeAnnotationNode cloneAnnotation =
new TypeAnnotationNode(
sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
sourceAnnotation.accept(cloneAnnotation);
this.invisibleTypeAnnotations.add(cloneAnnotation);
}
}
return this;

View file

@ -60,7 +60,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.Opcodes;
@ -71,36 +70,28 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class AnnotationNode extends AnnotationVisitor {
/**
* The class descriptor of the annotation class.
*/
/** The class descriptor of the annotation class. */
public String desc;
/**
* The name value pairs of this annotation. Each name value pair is stored
* as two consecutive elements in the list. The name is a {@link String},
* and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Float},
* {@link Double}, {@link String} or {@link jdk.internal.org.objectweb.asm.Type}, or a
* two elements String array (for enumeration values), an
* {@link AnnotationNode}, or a {@link List} of values of one of the
* preceding types. The list may be <tt>null</tt> if there is no name value
* pair.
* The name value pairs of this annotation. Each name value pair is stored as two consecutive
* elements in the list. The name is a {@link String}, and the value may be a {@link Byte}, {@link
* Boolean}, {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Float},
* {@link Double}, {@link String} or {@link jdk.internal.org.objectweb.asm.Type}, or a two elements String
* array (for enumeration values), an {@link AnnotationNode}, or a {@link List} of values of one
* of the preceding types. The list may be {@literal null} if there is no name value pair.
*/
public List<Object> values;
/**
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #AnnotationNode(int, String)} version.
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #AnnotationNode(int, String)} version.
*
* @param desc
* the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @param descriptor the class descriptor of the annotation class.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public AnnotationNode(final String desc) {
this(Opcodes.ASM6, desc);
public AnnotationNode(final String descriptor) {
this(Opcodes.ASM7, descriptor);
if (getClass() != AnnotationNode.class) {
throw new IllegalStateException();
}
@ -109,25 +100,22 @@ 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} or {@link Opcodes#ASM6}.
* @param desc
* the class descriptor of the annotation class.
* @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 descriptor the class descriptor of the annotation class.
*/
public AnnotationNode(final int api, final String desc) {
public AnnotationNode(final int api, final String descriptor) {
super(api);
this.desc = desc;
this.desc = descriptor;
}
/**
* Constructs a new {@link AnnotationNode} to visit an array value.
*
* @param values
* where the visited values must be stored.
* @param values where the visited values must be stored.
*/
AnnotationNode(final List<Object> values) {
super(Opcodes.ASM6);
super(Opcodes.ASM7);
this.values = values;
}
@ -144,88 +132,46 @@ public class AnnotationNode extends AnnotationVisitor {
values.add(name);
}
if (value instanceof byte[]) {
byte[] v = (byte[]) value;
ArrayList<Byte> l = new ArrayList<Byte>(v.length);
for (byte b : v) {
l.add(b);
}
values.add(l);
values.add(Util.asArrayList((byte[]) value));
} else if (value instanceof boolean[]) {
boolean[] v = (boolean[]) value;
ArrayList<Boolean> l = new ArrayList<Boolean>(v.length);
for (boolean b : v) {
l.add(b);
}
values.add(l);
values.add(Util.asArrayList((boolean[]) value));
} else if (value instanceof short[]) {
short[] v = (short[]) value;
ArrayList<Short> l = new ArrayList<Short>(v.length);
for (short s : v) {
l.add(s);
}
values.add(l);
values.add(Util.asArrayList((short[]) value));
} else if (value instanceof char[]) {
char[] v = (char[]) value;
ArrayList<Character> l = new ArrayList<Character>(v.length);
for (char c : v) {
l.add(c);
}
values.add(l);
values.add(Util.asArrayList((char[]) value));
} else if (value instanceof int[]) {
int[] v = (int[]) value;
ArrayList<Integer> l = new ArrayList<Integer>(v.length);
for (int i : v) {
l.add(i);
}
values.add(l);
values.add(Util.asArrayList((int[]) value));
} else if (value instanceof long[]) {
long[] v = (long[]) value;
ArrayList<Long> l = new ArrayList<Long>(v.length);
for (long lng : v) {
l.add(lng);
}
values.add(l);
values.add(Util.asArrayList((long[]) value));
} else if (value instanceof float[]) {
float[] v = (float[]) value;
ArrayList<Float> l = new ArrayList<Float>(v.length);
for (float f : v) {
l.add(f);
}
values.add(l);
values.add(Util.asArrayList((float[]) value));
} else if (value instanceof double[]) {
double[] v = (double[]) value;
ArrayList<Double> l = new ArrayList<Double>(v.length);
for (double d : v) {
l.add(d);
}
values.add(l);
values.add(Util.asArrayList((double[]) value));
} else {
values.add(value);
}
}
@Override
public void visitEnum(final String name, final String desc,
final String value) {
public void visitEnum(final String name, final String descriptor, final String value) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
values.add(new String[] { desc, value });
values.add(new String[] {descriptor, value});
}
@Override
public AnnotationVisitor visitAnnotation(final String name,
final String desc) {
public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
if (values == null) {
values = new ArrayList<Object>(this.desc != null ? 2 : 1);
}
if (this.desc != null) {
values.add(name);
}
AnnotationNode annotation = new AnnotationNode(desc);
AnnotationNode annotation = new AnnotationNode(descriptor);
values.add(annotation);
return annotation;
}
@ -245,6 +191,7 @@ public class AnnotationNode extends AnnotationVisitor {
@Override
public void visitEnd() {
// Nothing to do.
}
// ------------------------------------------------------------------------
@ -252,14 +199,12 @@ public class AnnotationNode extends AnnotationVisitor {
// ------------------------------------------------------------------------
/**
* Checks that this annotation node is compatible with the given ASM API
* version. This methods checks that this node, and all its nodes
* recursively, do not contain elements that were introduced in more recent
* versions of the ASM API than the given version.
* Checks that this annotation 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 one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public void check(final int api) {
// nothing to do
@ -268,52 +213,48 @@ public class AnnotationNode extends AnnotationVisitor {
/**
* Makes the given visitor visit this annotation.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
* @param annotationVisitor an annotation visitor. Maybe {@literal null}.
*/
public void accept(final AnnotationVisitor av) {
if (av != null) {
public void accept(final AnnotationVisitor annotationVisitor) {
if (annotationVisitor != null) {
if (values != null) {
for (int i = 0; i < values.size(); i += 2) {
for (int i = 0, n = values.size(); i < n; i += 2) {
String name = (String) values.get(i);
Object value = values.get(i + 1);
accept(av, name, value);
accept(annotationVisitor, name, value);
}
}
av.visitEnd();
annotationVisitor.visitEnd();
}
}
/**
* Makes the given visitor visit a given annotation value.
*
* @param av
* an annotation visitor. Maybe <tt>null</tt>.
* @param name
* the value name.
* @param value
* the actual value.
* @param annotationVisitor an annotation visitor. Maybe {@literal null}.
* @param name the value name.
* @param value the actual value.
*/
static void accept(final AnnotationVisitor av, final String name,
final Object value) {
if (av != null) {
static void accept(
final AnnotationVisitor annotationVisitor, final String name, final Object value) {
if (annotationVisitor != null) {
if (value instanceof String[]) {
String[] typeconst = (String[]) value;
av.visitEnum(name, typeconst[0], typeconst[1]);
String[] typeValue = (String[]) value;
annotationVisitor.visitEnum(name, typeValue[0], typeValue[1]);
} else if (value instanceof AnnotationNode) {
AnnotationNode an = (AnnotationNode) value;
an.accept(av.visitAnnotation(name, an.desc));
AnnotationNode annotationValue = (AnnotationNode) value;
annotationValue.accept(annotationVisitor.visitAnnotation(name, annotationValue.desc));
} else if (value instanceof List) {
AnnotationVisitor v = av.visitArray(name);
if (v != null) {
List<?> array = (List<?>) value;
for (int j = 0; j < array.size(); ++j) {
accept(v, null, array.get(j));
AnnotationVisitor arrayAnnotationVisitor = annotationVisitor.visitArray(name);
if (arrayAnnotationVisitor != null) {
List<?> arrayValue = (List<?>) value;
for (int i = 0, n = arrayValue.size(); i < n; ++i) {
accept(arrayAnnotationVisitor, null, arrayValue.get(i));
}
v.visitEnd();
arrayAnnotationVisitor.visitEnd();
}
} else {
av.visit(name, value);
annotationVisitor.visit(name, value);
}
}
}

View file

@ -59,9 +59,7 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
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;
@ -79,155 +77,100 @@ import jdk.internal.org.objectweb.asm.TypePath;
public class ClassNode extends ClassVisitor {
/**
* The class 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.
*/
public int version;
/**
* The class's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This
* field also indicates if the class is deprecated.
* The class's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This field also indicates if
* the class is deprecated.
*/
public int access;
/**
* The internal name of the class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
/** The internal name of this class (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName}). */
public String name;
/**
* The signature of the class. May be <tt>null</tt>.
*/
/** The signature of this class. May be {@literal null}. */
public String signature;
/**
* The internal of name of the super class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). For
* interfaces, the super class is {@link Object}. May be <tt>null</tt>, but
* only for the {@link Object} class.
* The internal of name of the super class (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName}).
* For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
* {@link Object} class.
*/
public String superName;
/**
* The internal names of the class's interfaces (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). This
* list is a list of {@link String} objects.
* The internal names of the interfaces directly implemented by this class (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName}).
*/
public List<String> interfaces;
/**
* The name of the source file from which this class was compiled. May be
* <tt>null</tt>.
*/
/** The name of the source file from which this class was compiled. May be {@literal null}. */
public String sourceFile;
/**
* Debug information to compute the correspondence between source and
* compiled elements of the class. May be <tt>null</tt>.
* The correspondence between source and compiled elements of this class. May be {@literal null}.
*/
public String sourceDebug;
/**
* Module information. May be <tt>null</tt>.
*/
/** The module stored in this class. May be {@literal null}. */
public ModuleNode module;
/**
* The internal name of the enclosing class of the class. May be
* <tt>null</tt>.
*/
/** The internal name of the enclosing class of this class. May be {@literal null}. */
public String outerClass;
/**
* The name of the method that contains the class, or <tt>null</tt> if the
* class is not enclosed in a method.
* The name of the method that contains this class, or {@literal null} if this class is not
* enclosed in a method.
*/
public String outerMethod;
/**
* The descriptor of the method that contains the class, or <tt>null</tt> if
* the class is not enclosed in a method.
* The descriptor of the method that contains this class, or {@literal null} if this class is not
* enclosed in a method.
*/
public String outerMethodDesc;
/**
* The runtime visible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
/** The runtime visible annotations of this class. May be {@literal null}. */
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this class. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
/** The runtime invisible annotations of this class. May be {@literal null}. */
public List<AnnotationNode> invisibleAnnotations;
/**
* The runtime visible type annotations of this class. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
/** The runtime visible type annotations of this class. May be {@literal null}. */
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this class. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
/** The runtime invisible type annotations of this class. May be {@literal null}. */
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* The non standard attributes of this class. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.Attribute
*/
/** The non standard attributes of this class. May be {@literal null}. */
public List<Attribute> attrs;
/**
* Informations about the inner classes of this class. This list is a list
* of {@link InnerClassNode} objects.
*
* @associates jdk.internal.org.objectweb.asm.tree.InnerClassNode
*/
/** The inner classes of this class. */
public List<InnerClassNode> innerClasses;
/**
* The fields of this class. This list is a list of {@link FieldNode}
* objects.
*
* @associates jdk.internal.org.objectweb.asm.tree.FieldNode
*/
/** The internal name of the nest host class of this class. May be {@literal null}. */
public String nestHostClass;
/** The internal names of the nest members of this class. May be {@literal null}. */
public List<String> nestMembers;
/** The fields of this class. */
public List<FieldNode> fields;
/**
* The methods of this class. This list is a list of {@link MethodNode}
* objects.
*
* @associates jdk.internal.org.objectweb.asm.tree.MethodNode
*/
/** The methods of this class. */
public List<MethodNode> methods;
/**
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #ClassNode(int)}
* version.
* Constructs a new {@link ClassNode}. <i>Subclasses must not use this constructor</i>. Instead,
* they must use the {@link #ClassNode(int)} version.
*
* @throws IllegalStateException
* If a subclass calls this constructor.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public ClassNode() {
this(Opcodes.ASM6);
this(Opcodes.ASM7);
if (getClass() != ClassNode.class) {
throw new IllegalStateException();
}
@ -236,9 +179,8 @@ 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} or {@link Opcodes#ASM6}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public ClassNode(final int api) {
super(api);
@ -248,22 +190,24 @@ public class ClassNode extends ClassVisitor {
this.methods = new ArrayList<MethodNode>();
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Implementation of the ClassVisitor abstract class
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
@Override
public void visit(final int version, final int access, final String name,
final String signature, final String superName,
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.version = version;
this.access = access;
this.name = name;
this.signature = signature;
this.superName = superName;
if (interfaces != null) {
this.interfaces.addAll(Arrays.asList(interfaces));
}
this.interfaces = Util.asArrayList(interfaces);
}
@Override
@ -273,214 +217,245 @@ public class ClassNode extends ClassVisitor {
}
@Override
public ModuleVisitor visitModule(final String name, final int access,
final String version) {
return module = new ModuleNode(name, access, version);
public ModuleVisitor visitModule(final String name, final int access, final String version) {
module = new ModuleNode(name, access, version);
return module;
}
@Override
public void visitOuterClass(final String owner, final String name,
final String desc) {
public void visitNestHost(final String nestHost) {
this.nestHostClass = nestHost;
}
@Override
public void visitOuterClass(final String owner, final String name, final String descriptor) {
outerClass = owner;
outerMethod = name;
outerMethodDesc = desc;
outerMethodDesc = descriptor;
}
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
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(an);
visibleAnnotations.add(annotation);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
invisibleAnnotations.add(annotation);
}
return an;
return annotation;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
public AnnotationVisitor visitTypeAnnotation(
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(an);
visibleTypeAnnotations.add(typeAnnotation);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(an);
invisibleTypeAnnotations.add(typeAnnotation);
}
return an;
return typeAnnotation;
}
@Override
public void visitAttribute(final Attribute attr) {
public void visitAttribute(final Attribute attribute) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
attrs.add(attribute);
}
@Override
public void visitInnerClass(final String name, final String outerName,
final String innerName, final int access) {
InnerClassNode icn = new InnerClassNode(name, outerName, innerName,
access);
innerClasses.add(icn);
public void visitNestMember(final String nestMember) {
if (nestMembers == null) {
nestMembers = new ArrayList<String>();
}
nestMembers.add(nestMember);
}
@Override
public FieldVisitor visitField(final int access, final String name,
final String desc, final String signature, final Object value) {
FieldNode fn = new FieldNode(access, name, desc, signature, value);
fields.add(fn);
return fn;
public void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
InnerClassNode innerClass = new InnerClassNode(name, outerName, innerName, access);
innerClasses.add(innerClass);
}
@Override
public MethodVisitor visitMethod(final int access, final String name,
final String desc, final String signature, final String[] exceptions) {
MethodNode mn = new MethodNode(access, name, desc, signature,
exceptions);
methods.add(mn);
return mn;
public FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
FieldNode field = new FieldNode(access, name, descriptor, signature, value);
fields.add(field);
return field;
}
@Override
public MethodVisitor visitMethod(
final int access,
final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
MethodNode method = new MethodNode(access, name, descriptor, signature, exceptions);
methods.add(method);
return method;
}
@Override
public void visitEnd() {
// Nothing to do.
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Accept method
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Checks that this class node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
* Checks that this class 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 one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public void check(final int api) {
if (api < Opcodes.ASM6) {
if (module != null) {
throw new RuntimeException();
if (api < Opcodes.ASM7 && (nestHostClass != null || nestMembers != null)) {
throw new UnsupportedClassVersionException();
}
if (api < Opcodes.ASM6 && module != null) {
throw new UnsupportedClassVersionException();
}
if (api < Opcodes.ASM5) {
if (visibleTypeAnnotations != null
&& visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
throw new UnsupportedClassVersionException();
}
if (invisibleTypeAnnotations != null
&& invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
throw new UnsupportedClassVersionException();
}
}
// checks attributes
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
// Check the annotations.
if (visibleAnnotations != null) {
for (int i = visibleAnnotations.size() - 1; i >= 0; --i) {
visibleAnnotations.get(i).check(api);
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
}
if (invisibleAnnotations != null) {
for (int i = invisibleAnnotations.size() - 1; i >= 0; --i) {
invisibleAnnotations.get(i).check(api);
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
}
if (visibleTypeAnnotations != null) {
for (int i = visibleTypeAnnotations.size() - 1; i >= 0; --i) {
visibleTypeAnnotations.get(i).check(api);
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
}
if (invisibleTypeAnnotations != null) {
for (int i = invisibleTypeAnnotations.size() - 1; i >= 0; --i) {
invisibleTypeAnnotations.get(i).check(api);
}
for (FieldNode f : fields) {
f.check(api);
}
for (MethodNode m : methods) {
m.check(api);
for (int i = fields.size() - 1; i >= 0; --i) {
fields.get(i).check(api);
}
for (int i = methods.size() - 1; i >= 0; --i) {
methods.get(i).check(api);
}
}
/**
* Makes the given class visitor visit this class.
*
* @param cv
* a class visitor.
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor cv) {
// visits header
String[] interfaces = new String[this.interfaces.size()];
this.interfaces.toArray(interfaces);
cv.visit(version, access, name, signature, superName, interfaces);
// visits source
public void accept(final ClassVisitor classVisitor) {
// Visit the header.
String[] interfacesArray = new String[this.interfaces.size()];
this.interfaces.toArray(interfacesArray);
classVisitor.visit(version, access, name, signature, superName, interfacesArray);
// Visit the source.
if (sourceFile != null || sourceDebug != null) {
cv.visitSource(sourceFile, sourceDebug);
classVisitor.visitSource(sourceFile, sourceDebug);
}
// visits module
// Visit the module.
if (module != null) {
module.accept(cv);
module.accept(classVisitor);
}
// visits outer class
// Visit the nest host class.
if (nestHostClass != null) {
classVisitor.visitNestHost(nestHostClass);
}
// Visit the outer class.
if (outerClass != null) {
cv.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
classVisitor.visitOuterClass(outerClass, outerMethod, outerMethodDesc);
}
// visits attributes
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, true));
// Visit the annotations.
if (visibleAnnotations != null) {
for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = visibleAnnotations.get(i);
annotation.accept(classVisitor.visitAnnotation(annotation.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(cv.visitAnnotation(an.desc, false));
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
true));
if (invisibleAnnotations != null) {
for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = invisibleAnnotations.get(i);
annotation.accept(classVisitor.visitAnnotation(annotation.desc, false));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(cv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
cv.visitAttribute(attrs.get(i));
if (visibleTypeAnnotations != null) {
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
typeAnnotation.accept(
classVisitor.visitTypeAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
}
// visits inner classes
for (i = 0; i < innerClasses.size(); ++i) {
innerClasses.get(i).accept(cv);
}
// visits fields
for (i = 0; i < fields.size(); ++i) {
fields.get(i).accept(cv);
if (invisibleTypeAnnotations != null) {
for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
typeAnnotation.accept(
classVisitor.visitTypeAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
}
// visits methods
for (i = 0; i < methods.size(); ++i) {
methods.get(i).accept(cv);
}
// visits end
cv.visitEnd();
// Visit the non standard attributes.
if (attrs != null) {
for (int i = 0, n = attrs.size(); i < n; ++i) {
classVisitor.visitAttribute(attrs.get(i));
}
}
// Visit the nest members.
if (nestMembers != null) {
for (int i = 0, n = nestMembers.size(); i < n; ++i) {
classVisitor.visitNestMember(nestMembers.get(i));
}
}
// Visit the inner classes.
for (int i = 0, n = innerClasses.size(); i < n; ++i) {
innerClasses.get(i).accept(classVisitor);
}
// Visit the fields.
for (int i = 0, n = fields.size(); i < n; ++i) {
fields.get(i).accept(classVisitor);
}
// Visit the methods.
for (int i = 0, n = methods.size(); i < n; ++i) {
methods.get(i).accept(classVisitor);
}
classVisitor.visitEnd();
}
}

View file

@ -59,62 +59,51 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a field instruction. A field instruction is an
* instruction that loads or stores the value of a field of an object.
* A node that represents a field instruction. A field instruction is an instruction that loads or
* stores the value of a field of an object.
*
* @author Eric Bruneton
*/
public class FieldInsnNode extends AbstractInsnNode {
/**
* The internal name of the field's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}).
* The internal name of the field's owner class (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName}).
*/
public String owner;
/**
* The field's name.
*/
/** The field's name. */
public String name;
/**
* The field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
/** The field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String desc;
/**
* Constructs a new {@link FieldInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner
* the internal name of the field's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the field's name.
* @param desc
* the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param opcode the opcode of the type instruction to be constructed. This opcode must be
* GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD.
* @param owner the internal name of the field's owner class (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName}).
* @param name the field's name.
* @param descriptor the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
public FieldInsnNode(final int opcode, final String owner,
final String name, final String desc) {
public FieldInsnNode(
final int opcode, final String owner, final String name, final String descriptor) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
this.desc = descriptor;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be GETSTATIC,
* PUTSTATIC, GETFIELD or PUTFIELD.
* @param opcode the new instruction opcode. This opcode must be GETSTATIC, PUTSTATIC, GETFIELD or
* PUTFIELD.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
@ -126,14 +115,13 @@ public class FieldInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitFieldInsn(opcode, owner, name, desc);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitFieldInsn(opcode, owner, name, desc);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new FieldInsnNode(opcode, owner, name, desc)
.cloneAnnotations(this);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new FieldInsnNode(opcode, owner, name, desc).cloneAnnotations(this);
}
}

View file

@ -60,7 +60,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;
import jdk.internal.org.objectweb.asm.ClassVisitor;
@ -76,218 +75,168 @@ import jdk.internal.org.objectweb.asm.TypePath;
public class FieldNode extends FieldVisitor {
/**
* The field's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This
* field also indicates if the field is synthetic and/or deprecated.
* The field's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). This field also indicates if
* the field is synthetic and/or deprecated.
*/
public int access;
/**
* The field's name.
*/
/** The field's name. */
public String name;
/**
* The field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
/** The field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String desc;
/**
* The field's signature. May be <tt>null</tt>.
*/
/** The field's signature. May be {@literal null}. */
public String signature;
/**
* The field's initial value. This field, which may be <tt>null</tt> if the
* field does not have an initial value, must be an {@link Integer}, a
* {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
* The field's initial value. This field, which may be {@literal null} if the field does not have
* an initial value, must be an {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}
* or a {@link String}.
*/
public Object value;
/**
* The runtime visible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
* @label visible
*/
/** The runtime visible annotations of this field. May be {@literal null}. */
public List<AnnotationNode> visibleAnnotations;
/**
* The runtime invisible annotations of this field. This list is a list of
* {@link AnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.AnnotationNode
* @label invisible
*/
/** The runtime invisible annotations of this field. May be {@literal null}. */
public List<AnnotationNode> invisibleAnnotations;
/**
* The runtime visible type annotations of this field. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
/** The runtime visible type annotations of this field. May be {@literal null}. */
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations of this field. This list is a list
* of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
/** The runtime invisible type annotations of this field. May be {@literal null}. */
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* The non standard attributes of this field. This list is a list of
* {@link Attribute} objects. May be <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.Attribute
*/
/** The non standard attributes of this field. * May be {@literal null}. */
public List<Attribute> attrs;
/**
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #FieldNode(int, int, String, String, String, Object)} version.
* Constructs a new {@link FieldNode}. <i>Subclasses must not use this constructor</i>. Instead,
* they must use the {@link #FieldNode(int, int, String, String, String, Object)} version.
*
* @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.
* @param desc
* the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @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.
* @param descriptor the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param signature the field's signature.
* @param value the field's initial value. This parameter, which may be {@literal null} if the
* field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
* Long}, a {@link Double} or a {@link String}.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public FieldNode(final int access, final String name, final String desc,
final String signature, final Object value) {
this(Opcodes.ASM6, access, name, desc, signature, value);
public FieldNode(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
this(Opcodes.ASM7, 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}. <i>Subclasses must not use this constructor</i>.
*
* @param api
* the ASM API version implemented by this visitor. Must be one
* of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
* @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.
* @param desc
* the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type
* Type}).
* @param signature
* the field's signature.
* @param value
* the field's initial value. This parameter, which may be
* <tt>null</tt> if the field does not have an initial value,
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
* @param api the ASM API version implemented by this visitor. Must be one of {@link Opcodes#ASM4}
* or {@link Opcodes#ASM5}.
* @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.
* @param descriptor the field's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param signature the field's signature.
* @param value the field's initial value. This parameter, which may be {@literal null} if the
* field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
* Long}, a {@link Double} or a {@link String}.
*/
public FieldNode(final int api, final int access, final String name,
final String desc, final String signature, final Object value) {
public FieldNode(
final int api,
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
super(api);
this.access = access;
this.name = name;
this.desc = desc;
this.desc = descriptor;
this.signature = signature;
this.value = value;
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
AnnotationNode an = new AnnotationNode(desc);
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(an);
visibleAnnotations.add(annotation);
} else {
if (invisibleAnnotations == null) {
invisibleAnnotations = new ArrayList<AnnotationNode>(1);
}
invisibleAnnotations.add(an);
invisibleAnnotations.add(annotation);
}
return an;
return annotation;
}
@Override
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
public AnnotationVisitor visitTypeAnnotation(
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(an);
visibleTypeAnnotations.add(typeAnnotation);
} else {
if (invisibleTypeAnnotations == null) {
invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
}
invisibleTypeAnnotations.add(an);
invisibleTypeAnnotations.add(typeAnnotation);
}
return an;
return typeAnnotation;
}
@Override
public void visitAttribute(final Attribute attr) {
public void visitAttribute(final Attribute attribute) {
if (attrs == null) {
attrs = new ArrayList<Attribute>(1);
}
attrs.add(attr);
attrs.add(attribute);
}
@Override
public void visitEnd() {
// Nothing to do.
}
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
// Accept methods
// ------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------
/**
* Checks that this field node is compatible with the given ASM API version.
* This methods checks that this node, and all its nodes recursively, do not
* contain elements that were introduced in more recent versions of the ASM
* API than the given version.
* Checks that this field 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 one of {@link Opcodes#ASM4},
* {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
* @param api an ASM API version. Must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5},
* {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/
public void check(final int api) {
if (api == Opcodes.ASM4) {
if (visibleTypeAnnotations != null
&& visibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
if (visibleTypeAnnotations != null && !visibleTypeAnnotations.isEmpty()) {
throw new UnsupportedClassVersionException();
}
if (invisibleTypeAnnotations != null
&& invisibleTypeAnnotations.size() > 0) {
throw new RuntimeException();
if (invisibleTypeAnnotations != null && !invisibleTypeAnnotations.isEmpty()) {
throw new UnsupportedClassVersionException();
}
}
}
@ -295,42 +244,48 @@ public class FieldNode extends FieldVisitor {
/**
* Makes the given class visitor visit this field.
*
* @param cv
* a class visitor.
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor cv) {
FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
if (fv == null) {
public void accept(final ClassVisitor classVisitor) {
FieldVisitor fieldVisitor = classVisitor.visitField(access, name, desc, signature, value);
if (fieldVisitor == null) {
return;
}
int i, n;
n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = visibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, true));
// Visit the annotations.
if (visibleAnnotations != null) {
for (int i = 0, n = visibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = visibleAnnotations.get(i);
annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, true));
}
n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
for (i = 0; i < n; ++i) {
AnnotationNode an = invisibleAnnotations.get(i);
an.accept(fv.visitAnnotation(an.desc, false));
}
n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
true));
if (invisibleAnnotations != null) {
for (int i = 0, n = invisibleAnnotations.size(); i < n; ++i) {
AnnotationNode annotation = invisibleAnnotations.get(i);
annotation.accept(fieldVisitor.visitAnnotation(annotation.desc, false));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
false));
}
n = attrs == null ? 0 : attrs.size();
for (i = 0; i < n; ++i) {
fv.visitAttribute(attrs.get(i));
if (visibleTypeAnnotations != null) {
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
typeAnnotation.accept(
fieldVisitor.visitTypeAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
}
fv.visitEnd();
}
if (invisibleTypeAnnotations != null) {
for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
typeAnnotation.accept(
fieldVisitor.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) {
fieldVisitor.visitAttribute(attrs.get(i));
}
}
fieldVisitor.visitEnd();
}
}

View file

@ -59,50 +59,44 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A node that represents a stack map frame. These nodes are pseudo instruction
* nodes in order to be inserted in an instruction list. In fact these nodes
* must(*) be inserted <i>just before</i> any instruction node <b>i</b> that
* follows an unconditionnal branch instruction such as GOTO or THROW, that is
* the target of a jump instruction, or that starts an exception handler block.
* The stack map frame types must describe the values of the local variables and
* of the operand stack elements <i>just before</i> <b>i</b> is executed. <br>
* A node that represents a stack map frame. These nodes are pseudo instruction nodes in order to be
* inserted in an instruction list. In fact these nodes must(*) be inserted <i>just before</i> any
* instruction node <b>i</b> that follows an unconditionnal branch instruction such as GOTO or
* THROW, that is the target of a jump instruction, or that starts an exception handler block. The
* stack map frame types must describe the values of the local variables and of the operand stack
* elements <i>just before</i> <b>i</b> is executed. <br>
* <br>
* (*) this is mandatory only for classes whose version is greater than or equal
* to {@link Opcodes#V1_6 V1_6}.
* (*) this is mandatory only for classes whose version is greater than or equal to {@link
* Opcodes#V1_6}.
*
* @author Eric Bruneton
*/
public class FrameNode extends AbstractInsnNode {
/**
* The type of this frame. Must be {@link Opcodes#F_NEW} for expanded
* frames, or {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND},
* {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* The type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or {@link
* Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link Opcodes#F_SAME} or
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
*/
public int type;
/**
* The types of the local variables of this stack map frame. Elements of
* this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
* The types of the local variables of this stack map frame. Elements of this list can be Integer,
* String or LabelNode objects (for primitive, reference and uninitialized types respectively -
* see {@link MethodVisitor}).
*/
public List<Object> local;
/**
* The types of the operand stack elements of this stack map frame. Elements
* of this list can be Integer, String or LabelNode objects (for primitive,
* reference and uninitialized types respectively - see
* {@link MethodVisitor}).
* The types of the operand stack elements of this stack map frame. Elements of this list can be
* Integer, String or LabelNode objects (for primitive, reference and uninitialized types
* respectively - see {@link MethodVisitor}).
*/
public List<Object> stack;
@ -113,48 +107,45 @@ public class FrameNode extends AbstractInsnNode {
/**
* Constructs a new {@link FrameNode}.
*
* @param type
* the type of this frame. Must be {@link Opcodes#F_NEW} for
* expanded frames, or {@link Opcodes#F_FULL},
* {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP},
* {@link Opcodes#F_SAME} or {@link Opcodes#F_APPEND},
* {@link Opcodes#F_SAME1} for compressed frames.
* @param nLocal
* number of local variables of this stack map frame.
* @param local
* the types of the local variables of this stack map frame.
* Elements of this list can be Integer, String or LabelNode
* objects (for primitive, reference and uninitialized types
* respectively - see {@link MethodVisitor}).
* @param nStack
* number of operand stack elements of this stack map frame.
* @param stack
* the types of the operand stack elements of this stack map
* frame. Elements of this list can be Integer, String or
* LabelNode objects (for primitive, reference and uninitialized
* @param type the type of this frame. Must be {@link Opcodes#F_NEW} for expanded frames, or
* {@link Opcodes#F_FULL}, {@link Opcodes#F_APPEND}, {@link Opcodes#F_CHOP}, {@link
* Opcodes#F_SAME} or {@link Opcodes#F_APPEND}, {@link Opcodes#F_SAME1} for compressed frames.
* @param numLocal number of local variables of this stack map frame.
* @param local the types of the local variables of this stack map frame. Elements of this list
* can be Integer, String or LabelNode objects (for primitive, reference and uninitialized
* types respectively - see {@link MethodVisitor}).
* @param numStack number of operand stack elements of this stack map frame.
* @param stack the types of the operand stack elements of this stack map frame. Elements of this
* list can be Integer, String or LabelNode objects (for primitive, reference and
* uninitialized types respectively - see {@link MethodVisitor}).
*/
public FrameNode(final int type, final int nLocal, final Object[] local,
final int nStack, final Object[] stack) {
public FrameNode(
final int type,
final int numLocal,
final Object[] local,
final int numStack,
final Object[] stack) {
super(-1);
this.type = type;
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
this.local = asList(nLocal, local);
this.stack = asList(nStack, stack);
this.local = Util.asArrayList(numLocal, local);
this.stack = Util.asArrayList(numStack, stack);
break;
case Opcodes.F_APPEND:
this.local = asList(nLocal, local);
this.local = Util.asArrayList(numLocal, local);
break;
case Opcodes.F_CHOP:
this.local = Arrays.asList(new Object[nLocal]);
this.local = Util.asArrayList(numLocal);
break;
case Opcodes.F_SAME:
break;
case Opcodes.F_SAME1:
this.stack = asList(1, stack);
this.stack = Util.asArrayList(1, stack);
break;
default:
throw new IllegalArgumentException();
}
}
@ -163,77 +154,66 @@ public class FrameNode extends AbstractInsnNode {
return FRAME;
}
/**
* Makes the given visitor visit this stack map frame.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
public void accept(final MethodVisitor methodVisitor) {
switch (type) {
case Opcodes.F_NEW:
case Opcodes.F_FULL:
mv.visitFrame(type, local.size(), asArray(local), stack.size(),
asArray(stack));
methodVisitor.visitFrame(type, local.size(), asArray(local), stack.size(), asArray(stack));
break;
case Opcodes.F_APPEND:
mv.visitFrame(type, local.size(), asArray(local), 0, null);
methodVisitor.visitFrame(type, local.size(), asArray(local), 0, null);
break;
case Opcodes.F_CHOP:
mv.visitFrame(type, local.size(), null, 0, null);
methodVisitor.visitFrame(type, local.size(), null, 0, null);
break;
case Opcodes.F_SAME:
mv.visitFrame(type, 0, null, 0, null);
methodVisitor.visitFrame(type, 0, null, 0, null);
break;
case Opcodes.F_SAME1:
mv.visitFrame(type, 0, null, 1, asArray(stack));
methodVisitor.visitFrame(type, 0, null, 1, asArray(stack));
break;
default:
throw new IllegalArgumentException();
}
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
FrameNode clone = new FrameNode();
clone.type = type;
if (local != null) {
clone.local = new ArrayList<Object>();
for (int i = 0; i < local.size(); ++i) {
Object l = local.get(i);
if (l instanceof LabelNode) {
l = labels.get(l);
for (int i = 0, n = local.size(); i < n; ++i) {
Object localElement = local.get(i);
if (localElement instanceof LabelNode) {
localElement = clonedLabels.get(localElement);
}
clone.local.add(l);
clone.local.add(localElement);
}
}
if (stack != null) {
clone.stack = new ArrayList<Object>();
for (int i = 0; i < stack.size(); ++i) {
Object s = stack.get(i);
if (s instanceof LabelNode) {
s = labels.get(s);
for (int i = 0, n = stack.size(); i < n; ++i) {
Object stackElement = stack.get(i);
if (stackElement instanceof LabelNode) {
stackElement = clonedLabels.get(stackElement);
}
clone.stack.add(s);
clone.stack.add(stackElement);
}
}
return clone;
}
// ------------------------------------------------------------------------
private static List<Object> asList(final int n, final Object[] o) {
return Arrays.asList(o).subList(0, n);
}
private static Object[] asArray(final List<Object> l) {
Object[] objs = new Object[l.size()];
for (int i = 0; i < objs.length; ++i) {
Object o = l.get(i);
private static Object[] asArray(final List<Object> list) {
Object[] array = new Object[list.size()];
for (int i = 0, n = array.length; i < n; ++i) {
Object o = list.get(i);
if (o instanceof LabelNode) {
o = ((LabelNode) o).getLabel();
}
objs[i] = o;
array[i] = o;
}
return objs;
return array;
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -70,23 +69,17 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class IincInsnNode extends AbstractInsnNode {
/**
* Index of the local variable to be incremented.
*/
/** Index of the local variable to be incremented. */
public int var;
/**
* Amount to increment the local variable by.
*/
/** Amount to increment the local variable by. */
public int incr;
/**
* Constructs a new {@link IincInsnNode}.
*
* @param var
* index of the local variable to be incremented.
* @param incr
* increment amount to increment the local variable by.
* @param var index of the local variable to be incremented.
* @param incr increment amount to increment the local variable by.
*/
public IincInsnNode(final int var, final int incr) {
super(Opcodes.IINC);
@ -100,13 +93,13 @@ public class IincInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIincInsn(var, incr);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitIincInsn(var, incr);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new IincInsnNode(var, incr).cloneAnnotations(this);
}
}

View file

@ -67,51 +67,38 @@ import jdk.internal.org.objectweb.asm.ClassVisitor;
*/
public class InnerClassNode {
/**
* The internal name of an inner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}).
*/
/** The internal name of an inner class (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName()}). */
public String name;
/**
* The internal name of the class to which the inner class belongs (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}). May be
* <tt>null</tt>.
* The internal name of the class to which the inner class belongs (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
*/
public String outerName;
/**
* The (simple) name of the inner class inside its enclosing class. May be
* <tt>null</tt> for anonymous inner classes.
* The (simple) name of the inner class inside its enclosing class. May be {@literal null} for
* anonymous inner classes.
*/
public String innerName;
/**
* The access flags of the inner class as originally declared in the
* enclosing class.
*/
/** The access flags of the inner class as originally declared in the enclosing class. */
public int access;
/**
* Constructs a new {@link InnerClassNode}.
*
* @param name
* the internal name of an inner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param outerName
* the internal name of the class to which the inner class
* belongs (see {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}). May be <tt>null</tt>.
* @param innerName
* the (simple) name of the inner class inside its enclosing
* class. May be <tt>null</tt> for anonymous inner classes.
* @param access
* the access flags of the inner class as originally declared in
* the enclosing class.
* @param name the internal name of an inner class (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName()}).
* @param outerName the internal name of the class to which the inner class belongs (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName()}). May be {@literal null}.
* @param innerName the (simple) name of the inner class inside its enclosing class. May be
* {@literal null} for anonymous inner classes.
* @param access the access flags of the inner class as originally declared in the enclosing
* class.
*/
public InnerClassNode(final String name, final String outerName,
final String innerName, final int access) {
public InnerClassNode(
final String name, final String outerName, final String innerName, final int access) {
this.name = name;
this.outerName = outerName;
this.innerName = innerName;
@ -121,10 +108,9 @@ public class InnerClassNode {
/**
* Makes the given class visitor visit this inner class.
*
* @param cv
* a class visitor.
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor cv) {
cv.visitInnerClass(name, outerName, innerName, access);
public void accept(final ClassVisitor classVisitor) {
classVisitor.visitInnerClass(name, outerName, innerName, access);
}
}

View file

@ -60,33 +60,26 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This
* implementation is not thread safe</i>.
* A doubly linked list of {@link AbstractInsnNode} objects. <i>This implementation is not thread
* safe</i>.
*/
public class InsnList {
/**
* The number of instructions in this list.
*/
/** The number of instructions in this list. */
private int size;
/**
* The first instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode first;
/** The first instruction in this list. May be {@literal null}. */
private AbstractInsnNode firstInsn;
/** The last instruction in this list. May be {@literal null}. */
private AbstractInsnNode lastInsn;
/**
* The last instruction in this list. May be <tt>null</tt>.
*/
private AbstractInsnNode last;
/**
* A cache of the instructions of this list. This cache is used to improve
* the performance of the {@link #get} method.
* A cache of the instructions of this list. This cache is used to improve the performance of the
* {@link #get} method.
*/
AbstractInsnNode[] cache;
@ -102,34 +95,30 @@ public class InsnList {
/**
* Returns the first instruction in this list.
*
* @return the first instruction in this list, or <tt>null</tt> if the list
* is empty.
* @return the first instruction in this list, or {@literal null} if the list is empty.
*/
public AbstractInsnNode getFirst() {
return first;
return firstInsn;
}
/**
* Returns the last instruction in this list.
*
* @return the last instruction in this list, or <tt>null</tt> if the list
* is empty.
* @return the last instruction in this list, or {@literal null} if the list is empty.
*/
public AbstractInsnNode getLast() {
return last;
return lastInsn;
}
/**
* Returns the instruction whose index is given. This method builds a cache
* of the instructions in this list to avoid scanning the whole list each
* time it is called. Once the cache is built, this method run in constant
* time. This cache is invalidated by all the methods that modify the list.
* Returns the instruction whose index is given. This method builds a cache of the instructions in
* this list to avoid scanning the whole list each time it is called. Once the cache is built,
* this method runs in constant time. This cache is invalidated by all the methods that modify the
* list.
*
* @param index
* the index of the instruction that must be returned.
* @param index the index of the instruction that must be returned.
* @return the instruction whose index is given.
* @throws IndexOutOfBoundsException
* if (index &lt; 0 || index &gt;= size()).
* @throws IndexOutOfBoundsException if (index &lt; 0 || index &gt;= size()).
*/
public AbstractInsnNode get(final int index) {
if (index < 0 || index >= size) {
@ -142,54 +131,49 @@ public class InsnList {
}
/**
* Returns <tt>true</tt> if the given instruction belongs to this list. This
* method always scans the instructions of this list until it finds the
* given instruction or reaches the end of the list.
* Returns {@literal true} if the given instruction belongs to this list. This method always scans
* the instructions of this list until it finds the given instruction or reaches the end of the
* list.
*
* @param insn
* an instruction.
* @return <tt>true</tt> if the given instruction belongs to this list.
* @param insnNode an instruction.
* @return {@literal true} if the given instruction belongs to this list.
*/
public boolean contains(final AbstractInsnNode insn) {
AbstractInsnNode i = first;
while (i != null && i != insn) {
i = i.next;
public boolean contains(final AbstractInsnNode insnNode) {
AbstractInsnNode currentInsn = firstInsn;
while (currentInsn != null && currentInsn != insnNode) {
currentInsn = currentInsn.nextInsn;
}
return i != null;
return currentInsn != null;
}
/**
* Returns the index of the given instruction in this list. This method
* builds a cache of the instruction indexes to avoid scanning the whole
* list each time it is called. Once the cache is built, this method run in
* constant time. The cache is invalidated by all the methods that modify
* the list.
* Returns the index of the given instruction in this list. This method builds a cache of the
* instruction indexes to avoid scanning the whole list each time it is called. Once the cache is
* built, this method run in constant time. The cache is invalidated by all the methods that
* modify the list.
*
* @param insn
* an instruction <i>of this list</i>.
* @return the index of the given instruction in this list. <i>The result of
* this method is undefined if the given instruction does not belong
* to this list</i>. Use {@link #contains contains} to test if an
* instruction belongs to an instruction list or not.
* @param insnNode an instruction <i>of this list</i>.
* @return the index of the given instruction in this list. <i>The result of this method is
* undefined if the given instruction does not belong to this list</i>. Use {@link #contains }
* to test if an instruction belongs to an instruction list or not.
*/
public int indexOf(final AbstractInsnNode insn) {
public int indexOf(final AbstractInsnNode insnNode) {
if (cache == null) {
cache = toArray();
}
return insn.index;
return insnNode.index;
}
/**
* Makes the given visitor visit all of the instructions in this list.
* Makes the given visitor visit all the instructions in this list.
*
* @param mv
* the method visitor that must visit the instructions.
* @param methodVisitor the method visitor that must visit the instructions.
*/
public void accept(final MethodVisitor mv) {
AbstractInsnNode insn = first;
while (insn != null) {
insn.accept(mv);
insn = insn.next;
public void accept(final MethodVisitor methodVisitor) {
AbstractInsnNode currentInsn = firstInsn;
while (currentInsn != null) {
currentInsn.accept(methodVisitor);
currentInsn = currentInsn.nextInsn;
}
}
@ -205,394 +189,367 @@ public class InsnList {
/**
* Returns an iterator over the instructions in this list.
*
* @param index
* index of instruction for the iterator to start at
*
* @param index index of instruction for the iterator to start at.
* @return an iterator over the instructions in this list.
*/
@SuppressWarnings("unchecked")
public ListIterator<AbstractInsnNode> iterator(int index) {
public ListIterator<AbstractInsnNode> iterator(final int index) {
return new InsnListIterator(index);
}
/**
* Returns an array containing all of the instructions in this list.
* Returns an array containing all the instructions in this list.
*
* @return an array containing all of the instructions in this list.
* @return an array containing all the instructions in this list.
*/
public AbstractInsnNode[] toArray() {
int i = 0;
AbstractInsnNode elem = first;
AbstractInsnNode[] insns = new AbstractInsnNode[size];
while (elem != null) {
insns[i] = elem;
elem.index = i++;
elem = elem.next;
int currentInsnIndex = 0;
AbstractInsnNode currentInsn = firstInsn;
AbstractInsnNode[] insnNodeArray = new AbstractInsnNode[size];
while (currentInsn != null) {
insnNodeArray[currentInsnIndex] = currentInsn;
currentInsn.index = currentInsnIndex++;
currentInsn = currentInsn.nextInsn;
}
return insns;
return insnNodeArray;
}
/**
* Replaces an instruction of this list with another instruction.
*
* @param location
* an instruction <i>of this list</i>.
* @param insn
* another instruction, <i>which must not belong to any
* {@link InsnList}</i>.
* @param oldInsnNode an instruction <i>of this list</i>.
* @param newInsnNode another instruction, <i>which must not belong to any {@link InsnList}</i>.
*/
public void set(final AbstractInsnNode location, final AbstractInsnNode insn) {
AbstractInsnNode next = location.next;
insn.next = next;
if (next != null) {
next.prev = insn;
public void set(final AbstractInsnNode oldInsnNode, final AbstractInsnNode newInsnNode) {
AbstractInsnNode nextInsn = oldInsnNode.nextInsn;
newInsnNode.nextInsn = nextInsn;
if (nextInsn != null) {
nextInsn.previousInsn = newInsnNode;
} else {
last = insn;
lastInsn = newInsnNode;
}
AbstractInsnNode prev = location.prev;
insn.prev = prev;
if (prev != null) {
prev.next = insn;
AbstractInsnNode previousInsn = oldInsnNode.previousInsn;
newInsnNode.previousInsn = previousInsn;
if (previousInsn != null) {
previousInsn.nextInsn = newInsnNode;
} else {
first = insn;
firstInsn = newInsnNode;
}
if (cache != null) {
int index = location.index;
cache[index] = insn;
insn.index = index;
int index = oldInsnNode.index;
cache[index] = newInsnNode;
newInsnNode.index = index;
} else {
insn.index = 0; // insn now belongs to an InsnList
newInsnNode.index = 0; // newInnsnNode now belongs to an InsnList.
}
location.index = -1; // i no longer belongs to an InsnList
location.prev = null;
location.next = null;
oldInsnNode.index = -1; // oldInsnNode no longer belongs to an InsnList.
oldInsnNode.previousInsn = null;
oldInsnNode.nextInsn = null;
}
/**
* Adds the given instruction to the end of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
* @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
*/
public void add(final AbstractInsnNode insn) {
public void add(final AbstractInsnNode insnNode) {
++size;
if (last == null) {
first = insn;
last = insn;
if (lastInsn == null) {
firstInsn = insnNode;
lastInsn = insnNode;
} else {
last.next = insn;
insn.prev = last;
lastInsn.nextInsn = insnNode;
insnNode.previousInsn = lastInsn;
}
last = insn;
lastInsn = insnNode;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
insnNode.index = 0; // insnNode now belongs to an InsnList.
}
/**
* Adds the given instructions to the end of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
* @param insnList an instruction list, which is cleared during the process. This list must be
* different from 'this'.
*/
public void add(final InsnList insns) {
if (insns.size == 0) {
public void add(final InsnList insnList) {
if (insnList.size == 0) {
return;
}
size += insns.size;
if (last == null) {
first = insns.first;
last = insns.last;
size += insnList.size;
if (lastInsn == null) {
firstInsn = insnList.firstInsn;
lastInsn = insnList.lastInsn;
} else {
AbstractInsnNode elem = insns.first;
last.next = elem;
elem.prev = last;
last = insns.last;
AbstractInsnNode firstInsnListElement = insnList.firstInsn;
lastInsn.nextInsn = firstInsnListElement;
firstInsnListElement.previousInsn = lastInsn;
lastInsn = insnList.lastInsn;
}
cache = null;
insns.removeAll(false);
insnList.removeAll(false);
}
/**
* Inserts the given instruction at the begining of this list.
* Inserts the given instruction at the beginning of this list.
*
* @param insn
* an instruction, <i>which must not belong to any
* {@link InsnList}</i>.
* @param insnNode an instruction, <i>which must not belong to any {@link InsnList}</i>.
*/
public void insert(final AbstractInsnNode insn) {
public void insert(final AbstractInsnNode insnNode) {
++size;
if (first == null) {
first = insn;
last = insn;
if (firstInsn == null) {
firstInsn = insnNode;
lastInsn = insnNode;
} else {
first.prev = insn;
insn.next = first;
firstInsn.previousInsn = insnNode;
insnNode.nextInsn = firstInsn;
}
first = insn;
firstInsn = insnNode;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
insnNode.index = 0; // insnNode now belongs to an InsnList.
}
/**
* Inserts the given instructions at the begining of this list.
* Inserts the given instructions at the beginning of this list.
*
* @param insns
* an instruction list, which is cleared during the process. This
* list must be different from 'this'.
* @param insnList an instruction list, which is cleared during the process. This list must be
* different from 'this'.
*/
public void insert(final InsnList insns) {
if (insns.size == 0) {
public void insert(final InsnList insnList) {
if (insnList.size == 0) {
return;
}
size += insns.size;
if (first == null) {
first = insns.first;
last = insns.last;
size += insnList.size;
if (firstInsn == null) {
firstInsn = insnList.firstInsn;
lastInsn = insnList.lastInsn;
} else {
AbstractInsnNode elem = insns.last;
first.prev = elem;
elem.next = first;
first = insns.first;
AbstractInsnNode lastInsnListElement = insnList.lastInsn;
firstInsn.previousInsn = lastInsnListElement;
lastInsnListElement.nextInsn = firstInsn;
firstInsn = insnList.firstInsn;
}
cache = null;
insns.removeAll(false);
insnList.removeAll(false);
}
/**
* Inserts the given instruction after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
* @param previousInsn an instruction <i>of this list</i> after which insnNode must be inserted.
* @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
* InsnList}</i>.
*/
public void insert(final AbstractInsnNode location,
final AbstractInsnNode insn) {
public void insert(final AbstractInsnNode previousInsn, final AbstractInsnNode insnNode) {
++size;
AbstractInsnNode next = location.next;
if (next == null) {
last = insn;
AbstractInsnNode nextInsn = previousInsn.nextInsn;
if (nextInsn == null) {
lastInsn = insnNode;
} else {
next.prev = insn;
nextInsn.previousInsn = insnNode;
}
location.next = insn;
insn.next = next;
insn.prev = location;
previousInsn.nextInsn = insnNode;
insnNode.nextInsn = nextInsn;
insnNode.previousInsn = previousInsn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
insnNode.index = 0; // insnNode now belongs to an InsnList.
}
/**
* Inserts the given instructions after the specified instruction.
*
* @param location
* an instruction <i>of this list</i> after which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
* @param previousInsn an instruction <i>of this list</i> after which the instructions must be
* inserted.
* @param insnList the instruction list to be inserted, which is cleared during the process. This
* list must be different from 'this'.
*/
public void insert(final AbstractInsnNode location, final InsnList insns) {
if (insns.size == 0) {
public void insert(final AbstractInsnNode previousInsn, final InsnList insnList) {
if (insnList.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode next = location.next;
if (next == null) {
last = ilast;
size += insnList.size;
AbstractInsnNode firstInsnListElement = insnList.firstInsn;
AbstractInsnNode lastInsnListElement = insnList.lastInsn;
AbstractInsnNode nextInsn = previousInsn.nextInsn;
if (nextInsn == null) {
lastInsn = lastInsnListElement;
} else {
next.prev = ilast;
nextInsn.previousInsn = lastInsnListElement;
}
location.next = ifirst;
ilast.next = next;
ifirst.prev = location;
previousInsn.nextInsn = firstInsnListElement;
lastInsnListElement.nextInsn = nextInsn;
firstInsnListElement.previousInsn = previousInsn;
cache = null;
insns.removeAll(false);
insnList.removeAll(false);
}
/**
* Inserts the given instruction before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which insn must be
* inserted.
* @param insn
* the instruction to be inserted, <i>which must not belong to
* any {@link InsnList}</i>.
* @param nextInsn an instruction <i>of this list</i> before which insnNode must be inserted.
* @param insnNode the instruction to be inserted, <i>which must not belong to any {@link
* InsnList}</i>.
*/
public void insertBefore(final AbstractInsnNode location,
final AbstractInsnNode insn) {
public void insertBefore(final AbstractInsnNode nextInsn, final AbstractInsnNode insnNode) {
++size;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = insn;
AbstractInsnNode previousInsn = nextInsn.previousInsn;
if (previousInsn == null) {
firstInsn = insnNode;
} else {
prev.next = insn;
previousInsn.nextInsn = insnNode;
}
location.prev = insn;
insn.next = location;
insn.prev = prev;
nextInsn.previousInsn = insnNode;
insnNode.nextInsn = nextInsn;
insnNode.previousInsn = previousInsn;
cache = null;
insn.index = 0; // insn now belongs to an InsnList
insnNode.index = 0; // insnNode now belongs to an InsnList.
}
/**
* Inserts the given instructions before the specified instruction.
*
* @param location
* an instruction <i>of this list</i> before which the
* instructions must be inserted.
* @param insns
* the instruction list to be inserted, which is cleared during
* the process. This list must be different from 'this'.
* @param nextInsn an instruction <i>of this list</i> before which the instructions must be
* inserted.
* @param insnList the instruction list to be inserted, which is cleared during the process. This
* list must be different from 'this'.
*/
public void insertBefore(final AbstractInsnNode location,
final InsnList insns) {
if (insns.size == 0) {
public void insertBefore(final AbstractInsnNode nextInsn, final InsnList insnList) {
if (insnList.size == 0) {
return;
}
size += insns.size;
AbstractInsnNode ifirst = insns.first;
AbstractInsnNode ilast = insns.last;
AbstractInsnNode prev = location.prev;
if (prev == null) {
first = ifirst;
size += insnList.size;
AbstractInsnNode firstInsnListElement = insnList.firstInsn;
AbstractInsnNode lastInsnListElement = insnList.lastInsn;
AbstractInsnNode previousInsn = nextInsn.previousInsn;
if (previousInsn == null) {
firstInsn = firstInsnListElement;
} else {
prev.next = ifirst;
previousInsn.nextInsn = firstInsnListElement;
}
location.prev = ilast;
ilast.next = location;
ifirst.prev = prev;
nextInsn.previousInsn = lastInsnListElement;
lastInsnListElement.nextInsn = nextInsn;
firstInsnListElement.previousInsn = previousInsn;
cache = null;
insns.removeAll(false);
insnList.removeAll(false);
}
/**
* Removes the given instruction from this list.
*
* @param insn
* the instruction <i>of this list</i> that must be removed.
* @param insnNode the instruction <i>of this list</i> that must be removed.
*/
public void remove(final AbstractInsnNode insn) {
public void remove(final AbstractInsnNode insnNode) {
--size;
AbstractInsnNode next = insn.next;
AbstractInsnNode prev = insn.prev;
if (next == null) {
if (prev == null) {
first = null;
last = null;
AbstractInsnNode nextInsn = insnNode.nextInsn;
AbstractInsnNode previousInsn = insnNode.previousInsn;
if (nextInsn == null) {
if (previousInsn == null) {
firstInsn = null;
lastInsn = null;
} else {
prev.next = null;
last = prev;
previousInsn.nextInsn = null;
lastInsn = previousInsn;
}
} else {
if (prev == null) {
first = next;
next.prev = null;
if (previousInsn == null) {
firstInsn = nextInsn;
nextInsn.previousInsn = null;
} else {
prev.next = next;
next.prev = prev;
previousInsn.nextInsn = nextInsn;
nextInsn.previousInsn = previousInsn;
}
}
cache = null;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
insnNode.index = -1; // insnNode no longer belongs to an InsnList.
insnNode.previousInsn = null;
insnNode.nextInsn = null;
}
/**
* Removes all of the instructions of this list.
* Removes all the instructions of this list.
*
* @param mark
* if the instructions must be marked as no longer belonging to
* any {@link InsnList}.
* @param mark if the instructions must be marked as no longer belonging to any {@link InsnList}.
*/
void removeAll(final boolean mark) {
if (mark) {
AbstractInsnNode insn = first;
while (insn != null) {
AbstractInsnNode next = insn.next;
insn.index = -1; // insn no longer belongs to an InsnList
insn.prev = null;
insn.next = null;
insn = next;
AbstractInsnNode currentInsn = firstInsn;
while (currentInsn != null) {
AbstractInsnNode next = currentInsn.nextInsn;
currentInsn.index = -1; // currentInsn no longer belongs to an InsnList.
currentInsn.previousInsn = null;
currentInsn.nextInsn = null;
currentInsn = next;
}
}
size = 0;
first = null;
last = null;
firstInsn = null;
lastInsn = null;
cache = null;
}
/**
* Removes all of the instructions of this list.
*/
/** Removes all the instructions of this list. */
public void clear() {
removeAll(false);
}
/**
* Reset all labels in the instruction list. This method should be called
* before reusing same instructions list between several
* <code>ClassWriter</code>s.
* Resets all the labels in the instruction list. This method should be called before reusing an
* instruction list between several <code>ClassWriter</code>s.
*/
public void resetLabels() {
AbstractInsnNode insn = first;
while (insn != null) {
if (insn instanceof LabelNode) {
((LabelNode) insn).resetLabel();
AbstractInsnNode currentInsn = firstInsn;
while (currentInsn != null) {
if (currentInsn instanceof LabelNode) {
((LabelNode) currentInsn).resetLabel();
}
insn = insn.next;
currentInsn = currentInsn.nextInsn;
}
}
// this class is not generified because it will create bridges
// Note: this class is not generified because it would create bridges.
@SuppressWarnings("rawtypes")
private final class InsnListIterator implements ListIterator {
AbstractInsnNode next;
AbstractInsnNode nextInsn;
AbstractInsnNode prev;
AbstractInsnNode previousInsn;
AbstractInsnNode remove;
InsnListIterator(int index) {
InsnListIterator(final int index) {
if (index == size()) {
next = null;
prev = getLast();
nextInsn = null;
previousInsn = getLast();
} else {
next = get(index);
prev = next.prev;
nextInsn = get(index);
previousInsn = nextInsn.previousInsn;
}
}
@Override
public boolean hasNext() {
return next != null;
return nextInsn != null;
}
@Override
public Object next() {
if (next == null) {
if (nextInsn == null) {
throw new NoSuchElementException();
}
AbstractInsnNode result = next;
prev = result;
next = result.next;
AbstractInsnNode result = nextInsn;
previousInsn = result;
nextInsn = result.nextInsn;
remove = result;
return result;
}
@Override
public void remove() {
if (remove != null) {
if (remove == next) {
next = next.next;
if (remove == nextInsn) {
nextInsn = nextInsn.nextInsn;
} else {
prev = prev.prev;
previousInsn = previousInsn.previousInsn;
}
InsnList.this.remove(remove);
remove = null;
@ -601,57 +558,63 @@ public class InsnList {
}
}
@Override
public boolean hasPrevious() {
return prev != null;
return previousInsn != null;
}
@Override
public Object previous() {
AbstractInsnNode result = prev;
next = result;
prev = result.prev;
AbstractInsnNode result = previousInsn;
nextInsn = result;
previousInsn = result.previousInsn;
remove = result;
return result;
}
@Override
public int nextIndex() {
if (next == null) {
if (nextInsn == null) {
return size();
}
if (cache == null) {
cache = toArray();
}
return next.index;
return nextInsn.index;
}
@Override
public int previousIndex() {
if (prev == null) {
if (previousInsn == null) {
return -1;
}
if (cache == null) {
cache = toArray();
}
return prev.index;
return previousInsn.index;
}
public void add(Object o) {
if (next != null) {
InsnList.this.insertBefore(next, (AbstractInsnNode) o);
} else if (prev != null) {
InsnList.this.insert(prev, (AbstractInsnNode) o);
@Override
public void add(final Object o) {
if (nextInsn != null) {
InsnList.this.insertBefore(nextInsn, (AbstractInsnNode) o);
} else if (previousInsn != null) {
InsnList.this.insert(previousInsn, (AbstractInsnNode) o);
} else {
InsnList.this.add((AbstractInsnNode) o);
}
prev = (AbstractInsnNode) o;
previousInsn = (AbstractInsnNode) o;
remove = null;
}
public void set(Object o) {
@Override
public void set(final Object o) {
if (remove != null) {
InsnList.this.set(remove, (AbstractInsnNode) o);
if (remove == prev) {
prev = (AbstractInsnNode) o;
if (remove == previousInsn) {
previousInsn = (AbstractInsnNode) o;
} else {
next = (AbstractInsnNode) o;
nextInsn = (AbstractInsnNode) o;
}
} else {
throw new IllegalStateException();

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
@ -72,22 +71,16 @@ public class InsnNode extends AbstractInsnNode {
/**
* Constructs a new {@link InsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be NOP, ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1,
* ICONST_2, ICONST_3, ICONST_4, ICONST_5, LCONST_0, LCONST_1,
* FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD,
* LALOAD, FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD,
* IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE,
* SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1,
* DUP2_X2, SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB,
* IMUL, LMUL, FMUL, DMUL, IDIV, LDIV, FDIV, DDIV, IREM, LREM,
* FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR,
* IUSHR, LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D,
* L2I, L2F, L2D, F2I, F2L, F2D, D2I, D2L, D2F, I2B, I2C, I2S,
* LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER,
* or MONITOREXIT.
* @param opcode the opcode of the instruction to be constructed. This opcode must be NOP,
* ACONST_NULL, ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5,
* LCONST_0, LCONST_1, FCONST_0, FCONST_1, FCONST_2, DCONST_0, DCONST_1, IALOAD, LALOAD,
* FALOAD, DALOAD, AALOAD, BALOAD, CALOAD, SALOAD, IASTORE, LASTORE, FASTORE, DASTORE,
* AASTORE, BASTORE, CASTORE, SASTORE, POP, POP2, DUP, DUP_X1, DUP_X2, DUP2, DUP2_X1, DUP2_X2,
* SWAP, IADD, LADD, FADD, DADD, ISUB, LSUB, FSUB, DSUB, IMUL, LMUL, FMUL, DMUL, IDIV, LDIV,
* FDIV, DDIV, IREM, LREM, FREM, DREM, INEG, LNEG, FNEG, DNEG, ISHL, LSHL, ISHR, LSHR, IUSHR,
* LUSHR, IAND, LAND, IOR, LOR, IXOR, LXOR, I2L, I2F, I2D, L2I, L2F, L2D, F2I, F2L, F2D, D2I,
* D2L, D2F, I2B, I2C, I2S, LCMP, FCMPL, FCMPG, DCMPL, DCMPG, IRETURN, LRETURN, FRETURN,
* DRETURN, ARETURN, RETURN, ARRAYLENGTH, ATHROW, MONITORENTER, or MONITOREXIT.
*/
public InsnNode(final int opcode) {
super(opcode);
@ -98,20 +91,14 @@ public class InsnNode extends AbstractInsnNode {
return INSN;
}
/**
* Makes the given visitor visit this instruction.
*
* @param mv
* a method visitor.
*/
@Override
public void accept(final MethodVisitor mv) {
mv.visitInsn(opcode);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitInsn(opcode);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new InsnNode(opcode).cloneAnnotations(this);
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
@ -69,19 +68,15 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
*/
public class IntInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction.
*/
/** The operand of this instruction. */
public int operand;
/**
* Constructs a new {@link IntInsnNode}.
*
* @param opcode
* the opcode of the instruction to be constructed. This opcode
* must be BIPUSH, SIPUSH or NEWARRAY.
* @param operand
* the operand of the instruction to be constructed.
* @param opcode the opcode of the instruction to be constructed. This opcode must be BIPUSH,
* SIPUSH or NEWARRAY.
* @param operand the operand of the instruction to be constructed.
*/
public IntInsnNode(final int opcode, final int operand) {
super(opcode);
@ -91,9 +86,7 @@ public class IntInsnNode extends AbstractInsnNode {
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be BIPUSH, SIPUSH
* or NEWARRAY.
* @param opcode the new instruction opcode. This opcode must be BIPUSH, SIPUSH or NEWARRAY.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
@ -105,13 +98,13 @@ public class IntInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitIntInsn(opcode, operand);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitIntInsn(opcode, operand);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new IntInsnNode(opcode, operand).cloneAnnotations(this);
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Handle;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -71,45 +70,39 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class InvokeDynamicInsnNode extends AbstractInsnNode {
/**
* Invokedynamic name.
*/
/** The method's name. */
public String name;
/**
* Invokedynamic descriptor.
*/
/** The method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String desc;
/**
* Bootstrap method
*/
/** The bootstrap method. */
public Handle bsm;
/**
* Bootstrap constant arguments
*/
/** The bootstrap method constant arguments. */
public Object[] bsmArgs;
/**
* Constructs a new {@link InvokeDynamicInsnNode}.
*
* @param name
* invokedynamic name.
* @param desc
* invokedynamic descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param bsm
* the bootstrap method.
* @param bsmArgs
* the boostrap constant arguments.
* @param name the method's name.
* @param descriptor the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* jdk.internal.org.objectweb.asm.Type} or {@link Handle} value. This method is allowed to modify the
* content of the array so a caller should expect that this array may change.
*/
public InvokeDynamicInsnNode(final String name, final String desc,
final Handle bsm, final Object... bsmArgs) {
public InvokeDynamicInsnNode(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) { // NOPMD(ArrayIsStoredDirectly): public field.
super(Opcodes.INVOKEDYNAMIC);
this.name = name;
this.desc = desc;
this.bsm = bsm;
this.bsmArgs = bsmArgs;
this.desc = descriptor;
this.bsm = bootstrapMethodHandle;
this.bsmArgs = bootstrapMethodArguments;
}
@Override
@ -118,14 +111,13 @@ public class InvokeDynamicInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs)
.cloneAnnotations(this);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new InvokeDynamicInsnNode(name, desc, bsm, bsmArgs).cloneAnnotations(this);
}
}

View file

@ -59,35 +59,30 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a jump instruction. A jump instruction is an
* instruction that may jump to another instruction.
* A node that represents a jump instruction. A jump instruction is an instruction that may jump to
* another instruction.
*
* @author Eric Bruneton
*/
public class JumpInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is a label that designates
* the instruction to which this instruction may jump.
* The operand of this instruction. This operand is a label that designates the instruction to
* which this instruction may jump.
*/
public LabelNode label;
/**
* Constructs a new {@link JumpInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ,
* IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE,
* IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label
* the operand of the instruction to be constructed. This operand
* is a label that designates the instruction to which the jump
* instruction may jump.
* @param opcode the opcode of the type instruction to be constructed. This opcode must be IFEQ,
* IFNE, IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT,
* IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
* @param label the operand of the instruction to be constructed. This operand is a label that
* designates the instruction to which the jump instruction may jump.
*/
public JumpInsnNode(final int opcode, final LabelNode label) {
super(opcode);
@ -97,11 +92,9 @@ public class JumpInsnNode extends AbstractInsnNode {
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be IFEQ, IFNE,
* IFLT, IFGE, IFGT, IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT,
* IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, GOTO,
* JSR, IFNULL or IFNONNULL.
* @param opcode the new instruction opcode. This opcode must be IFEQ, IFNE, IFLT, IFGE, IFGT,
* IFLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ,
* IF_ACMPNE, GOTO, JSR, IFNULL or IFNONNULL.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
@ -113,14 +106,13 @@ public class JumpInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitJumpInsn(opcode, label.getLabel());
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitJumpInsn(opcode, label.getLabel());
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new JumpInsnNode(opcode, clone(label, labels))
.cloneAnnotations(this);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new JumpInsnNode(opcode, clone(label, clonedLabels)).cloneAnnotations(this);
}
}

View file

@ -59,16 +59,13 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* An {@link AbstractInsnNode} that encapsulates a {@link Label}.
*/
/** An {@link AbstractInsnNode} that encapsulates a {@link Label}. */
public class LabelNode extends AbstractInsnNode {
private Label label;
private Label value;
public LabelNode() {
super(-1);
@ -76,7 +73,7 @@ public class LabelNode extends AbstractInsnNode {
public LabelNode(final Label label) {
super(-1);
this.label = label;
this.value = label;
}
@Override
@ -84,24 +81,30 @@ public class LabelNode extends AbstractInsnNode {
return LABEL;
}
/**
* Returns the label encapsulated by this node. A new label is created and associated with this
* node if it was created without an encapsulated label.
*
* @return the label encapsulated by this node.
*/
public Label getLabel() {
if (label == null) {
label = new Label();
if (value == null) {
value = new Label();
}
return label;
return value;
}
@Override
public void accept(final MethodVisitor cv) {
cv.visitLabel(getLabel());
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitLabel(getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return labels.get(this);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return clonedLabels.get(this);
}
public void resetLabel() {
label = null;
value = null;
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -71,23 +70,21 @@ import jdk.internal.org.objectweb.asm.Opcodes;
public class LdcInsnNode extends AbstractInsnNode {
/**
* The constant to be loaded on the stack. This parameter must be a non null
* {@link Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a
* {@link String} or a {@link jdk.internal.org.objectweb.asm.Type}.
* The constant to be loaded on the stack. This parameter must be a non null {@link Integer}, a
* {@link Float}, a {@link Long}, a {@link Double}, a {@link String} or a {@link
* jdk.internal.org.objectweb.asm.Type}.
*/
public Object cst;
/**
* Constructs a new {@link LdcInsnNode}.
*
* @param cst
* the constant to be loaded on the stack. This parameter must be
* a non null {@link Integer}, a {@link Float}, a {@link Long}, a
* {@link Double} or a {@link String}.
* @param value the constant to be loaded on the stack. This parameter must be a non null {@link
* Integer}, a {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
*/
public LdcInsnNode(final Object cst) {
public LdcInsnNode(final Object value) {
super(Opcodes.LDC);
this.cst = cst;
this.cst = value;
}
@Override
@ -96,13 +93,13 @@ public class LdcInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitLdcInsn(cst);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitLdcInsn(cst);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new LdcInsnNode(cst).cloneAnnotations(this);
}
}

View file

@ -59,36 +59,28 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a line number declaration. These nodes are pseudo
* instruction nodes in order to be inserted in an instruction list.
* A node that represents a line number declaration. These nodes are pseudo instruction nodes in
* order to be inserted in an instruction list.
*
* @author Eric Bruneton
*/
public class LineNumberNode extends AbstractInsnNode {
/**
* A line number. This number refers to the source file from which the class
* was compiled.
*/
/** A line number. This number refers to the source file from which the class was compiled. */
public int line;
/**
* The first instruction corresponding to this line number.
*/
/** The first instruction corresponding to this line number. */
public LabelNode start;
/**
* Constructs a new {@link LineNumberNode}.
*
* @param line
* a line number. This number refers to the source file from
* which the class was compiled.
* @param start
* the first instruction corresponding to this line number.
* @param line a line number. This number refers to the source file from which the class was
* compiled.
* @param start the first instruction corresponding to this line number.
*/
public LineNumberNode(final int line, final LabelNode start) {
super(-1);
@ -102,12 +94,12 @@ public class LineNumberNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitLineNumber(line, start.getLabel());
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitLineNumber(line, start.getLabel());
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new LineNumberNode(line, clone(start, labels));
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new LineNumberNode(line, clone(start, clonedLabels));
}
}

View file

@ -56,18 +56,13 @@
* 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.ArrayList;
import java.util.Arrays;
import java.util.List;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/**
* A node that represents a type annotation on a local or resource variable.
@ -77,110 +72,99 @@ import jdk.internal.org.objectweb.asm.TypeReference;
public class LocalVariableAnnotationNode extends TypeAnnotationNode {
/**
* The fist instructions corresponding to the continuous ranges that make
* the scope of this local variable (inclusive). Must not be <tt>null</tt>.
* The fist instructions corresponding to the continuous ranges that make the scope of this local
* variable (inclusive). Must not be {@literal null}.
*/
public List<LabelNode> start;
/**
* The last instructions corresponding to the continuous ranges that make
* the scope of this local variable (exclusive). This list must have the
* same size as the 'start' list. Must not be <tt>null</tt>.
* The last instructions corresponding to the continuous ranges that make the scope of this local
* variable (exclusive). This list must have the same size as the 'start' list. Must not be
* {@literal null}.
*/
public List<LabelNode> end;
/**
* The local variable's index in each range. This list must have the same
* size as the 'start' list. Must not be <tt>null</tt>.
* The local variable's index in each range. This list must have the same size as the 'start'
* list. Must not be {@literal null}.
*/
public List<Integer> index;
/**
* Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must
* not use this constructor</i>. Instead, they must use the
* {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)}
* version.
* Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the {@link #LocalVariableAnnotationNode(int, TypePath,
* LabelNode[], LabelNode[], int[], String)} version.
*
* @param typeRef
* a reference to the annotated type. 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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
* @param end
* the last instructions corresponding to the continuous ranges
* that make the scope of this local variable (exclusive). This
* array must have the same size as the 'start' array.
* @param index
* the local variable's index in each range. This array must have
* the same size as the 'start' array.
* @param desc
* the class descriptor of the annotation class.
* @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
* 'typeRef' as a whole.
* @param start the fist instructions corresponding to the continuous ranges that make the scope
* of this local variable (inclusive).
* @param end the last instructions corresponding to the continuous ranges that make the scope of
* this local variable (exclusive). This array must have the same size as the 'start' array.
* @param index the local variable's index in each range. This array must have the same size as
* the 'start' array.
* @param descriptor the class descriptor of the annotation class.
*/
public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
LabelNode[] start, LabelNode[] end, int[] index, String desc) {
this(Opcodes.ASM6, typeRef, typePath, start, end, index, desc);
public LocalVariableAnnotationNode(
final int typeRef,
final TypePath typePath,
final LabelNode[] start,
final LabelNode[] end,
final int[] index,
final String descriptor) {
this(Opcodes.ASM7, 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} or {@link Opcodes#ASM6}.
* @param typeRef
* a reference to the annotated type. See {@link TypeReference}.
* @param start
* the fist instructions corresponding to the continuous ranges
* that make the scope of this local variable (inclusive).
* @param end
* the last instructions corresponding to the continuous ranges
* that make the scope of this local variable (exclusive). This
* array must have the same size as the 'start' array.
* @param index
* the local variable's index in each range. This array must have
* the same size as the 'start' array.
* @param typePath
* the path to the annotated type argument, wildcard bound, array
* element type, or static inner type within 'typeRef'. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @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 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).
* @param end the last instructions corresponding to the continuous ranges that make the scope of
* this local variable (exclusive). This array must have the same size as the 'start' array.
* @param index the local variable's index in each range. This array must have the same size as
* the 'start' array.
* @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.
*/
public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath,
LabelNode[] start, LabelNode[] end, int[] index, String desc) {
super(api, typeRef, typePath, desc);
this.start = new ArrayList<LabelNode>(start.length);
this.start.addAll(Arrays.asList(start));
this.end = new ArrayList<LabelNode>(end.length);
this.end.addAll(Arrays.asList(end));
this.index = new ArrayList<Integer>(index.length);
for (int i : index) {
this.index.add(i);
}
public LocalVariableAnnotationNode(
final int api,
final int typeRef,
final TypePath typePath,
final LabelNode[] start,
final LabelNode[] end,
final int[] index,
final String descriptor) {
super(api, typeRef, typePath, descriptor);
this.start = Util.asArrayList(start);
this.end = Util.asArrayList(end);
this.index = Util.asArrayList(index);
}
/**
* Makes the given visitor visit this type annotation.
*
* @param mv
* the visitor that must visit this annotation.
* @param visible
* <tt>true</tt> if the annotation is visible at runtime.
* @param methodVisitor the visitor that must visit this annotation.
* @param visible {@literal true} if the annotation is visible at runtime.
*/
public void accept(final MethodVisitor mv, boolean visible) {
Label[] start = new Label[this.start.size()];
Label[] end = new Label[this.end.size()];
int[] index = new int[this.index.size()];
for (int i = 0; i < start.length; ++i) {
start[i] = this.start.get(i).getLabel();
end[i] = this.end.get(i).getLabel();
index[i] = this.index.get(i);
public void accept(final MethodVisitor methodVisitor, final boolean visible) {
Label[] startLabels = new Label[this.start.size()];
Label[] endLabels = new Label[this.end.size()];
int[] indices = new int[this.index.size()];
for (int i = 0, n = startLabels.length; i < n; ++i) {
startLabels[i] = this.start.get(i).getLabel();
endLabels[i] = this.end.get(i).getLabel();
indices[i] = this.index.get(i);
}
accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end,
index, desc, visible));
accept(
methodVisitor.visitLocalVariableAnnotation(
typeRef, typePath, startLabels, endLabels, indices, desc, visible));
}
}

View file

@ -67,61 +67,44 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
*/
public class LocalVariableNode {
/**
* The name of a local variable.
*/
/** The name of a local variable. */
public String name;
/**
* The type descriptor of this local variable.
*/
/** The type descriptor of this local variable. */
public String desc;
/**
* The signature of this local variable. May be <tt>null</tt>.
*/
/** The signature of this local variable. May be {@literal null}. */
public String signature;
/**
* The first instruction corresponding to the scope of this local variable
* (inclusive).
*/
/** The first instruction corresponding to the scope of this local variable (inclusive). */
public LabelNode start;
/**
* The last instruction corresponding to the scope of this local variable
* (exclusive).
*/
/** The last instruction corresponding to the scope of this local variable (exclusive). */
public LabelNode end;
/**
* The local variable's index.
*/
/** The local variable's index. */
public int index;
/**
* Constructs a new {@link LocalVariableNode}.
*
* @param name
* the name of a local variable.
* @param desc
* the type descriptor of this local variable.
* @param signature
* the signature of this local variable. May be <tt>null</tt>.
* @param start
* the first instruction corresponding to the scope of this local
* variable (inclusive).
* @param end
* the last instruction corresponding to the scope of this local
* variable (exclusive).
* @param index
* the local variable's index.
* @param name the name of a local variable.
* @param descriptor the type descriptor of this local variable.
* @param signature the signature of this local variable. May be {@literal null}.
* @param start the first instruction corresponding to the scope of this local variable
* (inclusive).
* @param end the last instruction corresponding to the scope of this local variable (exclusive).
* @param index the local variable's index.
*/
public LocalVariableNode(final String name, final String desc,
final String signature, final LabelNode start, final LabelNode end,
public LocalVariableNode(
final String name,
final String descriptor,
final String signature,
final LabelNode start,
final LabelNode end,
final int index) {
this.name = name;
this.desc = desc;
this.desc = descriptor;
this.signature = signature;
this.start = start;
this.end = end;
@ -131,11 +114,10 @@ public class LocalVariableNode {
/**
* Makes the given visitor visit this local variable declaration.
*
* @param mv
* a method visitor.
* @param methodVisitor a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitLocalVariable(name, desc, signature, start.getLabel(),
end.getLabel(), index);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitLocalVariable(
name, desc, signature, start.getLabel(), end.getLabel(), index);
}
}

View file

@ -58,11 +58,8 @@
*/
package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -74,48 +71,28 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class LookupSwitchInsnNode extends AbstractInsnNode {
/**
* Beginning of the default handler block.
*/
/** Beginning of the default handler block. */
public LabelNode dflt;
/**
* The values of the keys. This list is a list of {@link Integer} objects.
*/
/** The values of the keys. */
public List<Integer> keys;
/**
* Beginnings of the handler blocks. This list is a list of
* {@link LabelNode} objects.
*/
/** Beginnings of the handler blocks. */
public List<LabelNode> labels;
/**
* Constructs a new {@link LookupSwitchInsnNode}.
*
* @param dflt
* beginning of the default handler block.
* @param keys
* the values of the keys.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>keys[i]</tt> key.
* @param dflt beginning of the default handler block.
* @param keys the values of the keys.
* @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
* handler block for the {@code keys[i]} key.
*/
public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys,
final LabelNode[] labels) {
public LookupSwitchInsnNode(final LabelNode dflt, final int[] keys, final LabelNode[] labels) {
super(Opcodes.LOOKUPSWITCH);
this.dflt = dflt;
this.keys = new ArrayList<Integer>(keys == null ? 0 : keys.length);
this.labels = new ArrayList<LabelNode>(labels == null ? 0
: labels.length);
if (keys != null) {
for (int i = 0; i < keys.length; ++i) {
this.keys.add(keys[i]);
}
}
if (labels != null) {
this.labels.addAll(Arrays.asList(labels));
}
this.keys = Util.asArrayList(keys);
this.labels = Util.asArrayList(labels);
}
@Override
@ -124,23 +101,23 @@ public class LookupSwitchInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
int[] keys = new int[this.keys.size()];
for (int i = 0; i < keys.length; ++i) {
keys[i] = this.keys.get(i).intValue();
public void accept(final MethodVisitor methodVisitor) {
int[] keysArray = new int[this.keys.size()];
for (int i = 0, n = keysArray.length; i < n; ++i) {
keysArray[i] = this.keys.get(i).intValue();
}
Label[] labels = new Label[this.labels.size()];
for (int i = 0; i < labels.length; ++i) {
labels[i] = this.labels.get(i).getLabel();
Label[] labelsArray = new Label[this.labels.size()];
for (int i = 0, n = labelsArray.length; i < n; ++i) {
labelsArray[i] = this.labels.get(i).getLabel();
}
mv.visitLookupSwitchInsn(dflt.getLabel(), keys, labels);
acceptAnnotations(mv);
methodVisitor.visitLookupSwitchInsn(dflt.getLabel(), keysArray, labelsArray);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
LookupSwitchInsnNode clone = new LookupSwitchInsnNode(clone(dflt,
labels), null, clone(this.labels, labels));
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
LookupSwitchInsnNode clone =
new LookupSwitchInsnNode(clone(dflt, clonedLabels), null, clone(labels, clonedLabels));
clone.keys.addAll(keys);
return clone.cloneAnnotations(this);
}

View file

@ -59,94 +59,80 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
/**
* A node that represents a method instruction. A method instruction is an
* instruction that invokes a method.
* A node that represents a method instruction. A method instruction is an instruction that invokes
* a method.
*
* @author Eric Bruneton
*/
public class MethodInsnNode extends AbstractInsnNode {
/**
* The internal name of the method's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName() getInternalName}).
* The internal name of the method's owner class (see {@link
* jdk.internal.org.objectweb.asm.Type#getInternalName()}).
*
* <p>For methods of arrays, e.g., {@code clone()}, the array type descriptor.
*/
public String owner;
/**
* The method's name.
*/
/** The method's name. */
public String name;
/**
* The method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
/** The method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String desc;
/**
* If the method's owner class if an interface.
*/
/** Whether the method's owner class if an interface. */
public boolean itf;
/**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param opcode the opcode of the type instruction to be constructed. This opcode must be
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
* @param owner the internal name of the method's owner class (see {@link
* 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 desc) {
this(opcode, owner, name, desc, opcode == Opcodes.INVOKEINTERFACE);
public MethodInsnNode(
final int opcode, final String owner, final String name, final String descriptor) {
this(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
}
/**
* Constructs a new {@link MethodInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or
* INVOKEINTERFACE.
* @param owner
* the internal name of the method's owner class (see
* {@link jdk.internal.org.objectweb.asm.Type#getInternalName()
* getInternalName}).
* @param name
* the method's name.
* @param desc
* the method's descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param itf
* if the method's owner class is an interface.
* @param opcode the opcode of the type instruction to be constructed. This opcode must be
* INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
* @param owner the internal name of the method's owner class (see {@link
* 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}).
* @param isInterface if the method's owner class is an interface.
*/
public MethodInsnNode(final int opcode, final String owner,
final String name, final String desc, final boolean itf) {
public MethodInsnNode(
final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
super(opcode);
this.owner = owner;
this.name = name;
this.desc = desc;
this.itf = itf;
this.desc = descriptor;
this.itf = isInterface;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be INVOKEVIRTUAL,
* INVOKESPECIAL, INVOKESTATIC or INVOKEINTERFACE.
* @param opcode the new instruction opcode. This opcode must be INVOKEVIRTUAL, INVOKESPECIAL,
* INVOKESTATIC or INVOKEINTERFACE.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
@ -158,13 +144,13 @@ public class MethodInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitMethodInsn(opcode, owner, name, desc, itf);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitMethodInsn(opcode, owner, name, desc, itf);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new MethodInsnNode(opcode, owner, name, desc, itf);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new MethodInsnNode(opcode, owner, name, desc, itf).cloneAnnotations(this);
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.List;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
/**
@ -68,30 +67,30 @@ import jdk.internal.org.objectweb.asm.ModuleVisitor;
* @author Remi Forax
*/
public class ModuleExportNode {
/**
* The package name.
*/
/** The internal name of the exported package. */
public String packaze;
/**
* The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). Valid values are {@code
* ACC_SYNTHETIC} and {@code ACC_MANDATED}.
*/
public int access;
/**
* A list of modules that can access to this exported package.
* May be <tt>null</tt>.
* The list of modules that can access this exported package, specified with fully qualified names
* (using dots). May be {@literal null}.
*/
public List<String> modules;
/**
* Constructs a new {@link ModuleExportNode}.
*
* @param packaze
* the parameter's name.
* @param modules
* a list of modules that can access to this exported package.
* @param packaze the internal name of the exported package.
* @param access the package access flags, one or more of {@code ACC_SYNTHETIC} and {@code
* ACC_MANDATED}.
* @param modules a list of modules that can access this exported package, specified with fully
* qualified names (using dots).
*/
public ModuleExportNode(final String packaze, final int access, final List<String> modules) {
this.packaze = packaze;
@ -102,10 +101,10 @@ public class ModuleExportNode {
/**
* Makes the given module visitor visit this export declaration.
*
* @param mv
* a module visitor.
* @param moduleVisitor a module visitor.
*/
public void accept(final ModuleVisitor mv) {
mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0]));
public void accept(final ModuleVisitor moduleVisitor) {
moduleVisitor.visitExport(
packaze, access, modules == null ? null : modules.toArray(new String[0]));
}
}

View file

@ -60,7 +60,6 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.List;
import jdk.internal.org.objectweb.asm.ClassVisitor;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -71,74 +70,78 @@ import jdk.internal.org.objectweb.asm.Opcodes;
* @author Remi Forax
*/
public class ModuleNode extends ModuleVisitor {
/**
* Module name
*/
/** The fully qualified name (using dots) of this module. */
public String name;
/**
* Module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC}
* and {@code ACC_MANDATED}.
* The module's access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
* ACC_MANDATED}.
*/
public int access;
/**
* Version of the module.
* May be <tt>null</tt>.
*/
/** The version of this module. May be {@literal null}. */
public String version;
/**
* Name of the main class in internal form
* May be <tt>null</tt>.
*/
/** The internal name of the main class of this module. May be {@literal null}. */
public String mainClass;
/**
* A list of packages that are declared by the current module.
* May be <tt>null</tt>.
*/
/** The internal name of the packages declared by this module. May be {@literal null}. */
public List<String> packages;
/**
* A list of modules can are required by the current module.
* May be <tt>null</tt>.
*/
/** The dependencies of this module. May be {@literal null}. */
public List<ModuleRequireNode> requires;
/**
* A list of packages that are exported by the current module.
* May be <tt>null</tt>.
*/
/** The packages exported by this module. May be {@literal null}. */
public List<ModuleExportNode> exports;
/**
* A list of packages that are opened by the current module.
* May be <tt>null</tt>.
*/
/** The packages opened by this module. May be {@literal null}. */
public List<ModuleOpenNode> opens;
/**
* A list of classes in their internal forms that are used
* as a service by the current module. May be <tt>null</tt>.
*/
/** The internal names of the services used by this module. May be {@literal null}. */
public List<String> uses;
/**
* A list of services along with their implementations provided
* by the current module. May be <tt>null</tt>.
*/
/** The services provided by this module. May be {@literal null}. */
public List<ModuleProvideNode> provides;
public ModuleNode(final String name, final int access,
final String version) {
super(Opcodes.ASM6);
/**
* Constructs a {@link ModuleNode}. <i>Subclasses must not use this constructor</i>. Instead, they
* must use the {@link #ModuleNode(int,String,int,String,List,List,List,List,List)} version.
*
* @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}.
* @param version the module version, or {@literal null}.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public ModuleNode(final String name, final int access, final String version) {
super(Opcodes.ASM7);
if (getClass() != ModuleNode.class) {
throw new IllegalStateException();
}
this.name = name;
this.access = access;
this.version = version;
}
public ModuleNode(final int api,
// TODO(forax): why is there no 'mainClass' and 'packages' parameters in this constructor?
/**
* 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 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}.
* @param version the module version, or {@literal null}.
* @param requires The dependencies of this module. May be {@literal null}.
* @param exports The packages exported by this module. May be {@literal null}.
* @param opens The packages opened by this module. May be {@literal null}.
* @param uses The internal names of the services used by this module. May be {@literal null}.
* @param provides The services provided by this module. May be {@literal null}.
*/
public ModuleNode(
final int api,
final String name,
final int access,
final String version,
@ -156,18 +159,15 @@ public class ModuleNode extends ModuleVisitor {
this.opens = opens;
this.uses = uses;
this.provides = provides;
if (getClass() != ModuleNode.class) {
throw new IllegalStateException();
}
}
@Override
public void visitMainClass(String mainClass) {
public void visitMainClass(final String mainClass) {
this.mainClass = mainClass;
}
@Override
public void visitPackage(String packaze) {
public void visitPackage(final String packaze) {
if (packages == null) {
packages = new ArrayList<String>(5);
}
@ -175,7 +175,7 @@ public class ModuleNode extends ModuleVisitor {
}
@Override
public void visitRequire(String module, int access, String version) {
public void visitRequire(final String module, final int access, final String version) {
if (requires == null) {
requires = new ArrayList<ModuleRequireNode>(5);
}
@ -183,37 +183,23 @@ public class ModuleNode extends ModuleVisitor {
}
@Override
public void visitExport(String packaze, int access, String... modules) {
public void visitExport(final String packaze, final int access, final String... modules) {
if (exports == null) {
exports = new ArrayList<ModuleExportNode>(5);
}
List<String> moduleList = null;
if (modules != null) {
moduleList = new ArrayList<String>(modules.length);
for (int i = 0; i < modules.length; i++) {
moduleList.add(modules[i]);
}
}
exports.add(new ModuleExportNode(packaze, access, moduleList));
exports.add(new ModuleExportNode(packaze, access, Util.asArrayList(modules)));
}
@Override
public void visitOpen(String packaze, int access, String... modules) {
public void visitOpen(final String packaze, final int access, final String... modules) {
if (opens == null) {
opens = new ArrayList<ModuleOpenNode>(5);
}
List<String> moduleList = null;
if (modules != null) {
moduleList = new ArrayList<String>(modules.length);
for (int i = 0; i < modules.length; i++) {
moduleList.add(modules[i]);
}
}
opens.add(new ModuleOpenNode(packaze, access, moduleList));
opens.add(new ModuleOpenNode(packaze, access, Util.asArrayList(modules)));
}
@Override
public void visitUse(String service) {
public void visitUse(final String service) {
if (uses == null) {
uses = new ArrayList<String>(5);
}
@ -221,59 +207,59 @@ public class ModuleNode extends ModuleVisitor {
}
@Override
public void visitProvide(String service, String... providers) {
public void visitProvide(final String service, final String... providers) {
if (provides == null) {
provides = new ArrayList<ModuleProvideNode>(5);
}
ArrayList<String> providerList =
new ArrayList<String>(providers.length);
for (int i = 0; i < providers.length; i++) {
providerList.add(providers[i]);
}
provides.add(new ModuleProvideNode(service, providerList));
provides.add(new ModuleProvideNode(service, Util.asArrayList(providers)));
}
@Override
public void visitEnd() {
// Nothing to do.
}
public void accept(final ClassVisitor cv) {
ModuleVisitor mv = cv.visitModule(name, access, version);
if (mv == null) {
/**
* Makes the given class visitor visit this module.
*
* @param classVisitor a class visitor.
*/
public void accept(final ClassVisitor classVisitor) {
ModuleVisitor moduleVisitor = classVisitor.visitModule(name, access, version);
if (moduleVisitor == null) {
return;
}
if (mainClass != null) {
mv.visitMainClass(mainClass);
moduleVisitor.visitMainClass(mainClass);
}
if (packages != null) {
for (int i = 0; i < packages.size(); i++) {
mv.visitPackage(packages.get(i));
for (int i = 0, n = packages.size(); i < n; i++) {
moduleVisitor.visitPackage(packages.get(i));
}
}
if (requires != null) {
for (int i = 0; i < requires.size(); i++) {
requires.get(i).accept(mv);
for (int i = 0, n = requires.size(); i < n; i++) {
requires.get(i).accept(moduleVisitor);
}
}
if (exports != null) {
for (int i = 0; i < exports.size(); i++) {
exports.get(i).accept(mv);
for (int i = 0, n = exports.size(); i < n; i++) {
exports.get(i).accept(moduleVisitor);
}
}
if (opens != null) {
for (int i = 0; i < opens.size(); i++) {
opens.get(i).accept(mv);
for (int i = 0, n = opens.size(); i < n; i++) {
opens.get(i).accept(moduleVisitor);
}
}
if (uses != null) {
for (int i = 0; i < uses.size(); i++) {
mv.visitUse(uses.get(i));
for (int i = 0, n = uses.size(); i < n; i++) {
moduleVisitor.visitUse(uses.get(i));
}
}
if (provides != null) {
for (int i = 0; i < provides.size(); i++) {
provides.get(i).accept(mv);
for (int i = 0, n = provides.size(); i < n; i++) {
provides.get(i).accept(moduleVisitor);
}
}
}

View file

@ -59,39 +59,38 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.List;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
/**
* A node that represents an opened package with its name and the module that can access to it.
* A node that represents an opened package with its name and the module that can access it.
*
* @author Remi Forax
*/
public class ModuleOpenNode {
/**
* The package name.
*/
/** The internal name of the opened package. */
public String packaze;
/**
* The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* Valid values are {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* The access flag of the opened package, valid values are among {@code ACC_SYNTHETIC} and {@code
* ACC_MANDATED}.
*/
public int access;
/**
* A list of modules that can access to this exported package.
* May be <tt>null</tt>.
* The fully qualified names (using dots) of the modules that can use deep reflection to the
* classes of the open package, or {@literal null}.
*/
public List<String> modules;
/**
* Constructs a new {@link ModuleOpenNode}.
*
* @param packaze
* the parameter's name.
* @param modules
* a list of modules that can access to this open package.
* @param packaze the internal name of the opened package.
* @param access the access flag of the opened package, valid values are among {@code
* ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param modules the fully qualified names (using dots) of the modules that can use deep
* reflection to the classes of the open package, or {@literal null}.
*/
public ModuleOpenNode(final String packaze, final int access, final List<String> modules) {
this.packaze = packaze;
@ -100,12 +99,12 @@ public class ModuleOpenNode {
}
/**
* Makes the given module visitor visit this open declaration.
* Makes the given module visitor visit this opened package.
*
* @param mv
* a module visitor.
* @param moduleVisitor a module visitor.
*/
public void accept(final ModuleVisitor mv) {
mv.visitExport(packaze, access, (modules == null) ? null : modules.toArray(new String[0]));
public void accept(final ModuleVisitor moduleVisitor) {
moduleVisitor.visitOpen(
packaze, access, modules == null ? null : modules.toArray(new String[0]));
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.List;
import jdk.internal.org.objectweb.asm.ModuleVisitor;
/**
@ -68,23 +67,19 @@ import jdk.internal.org.objectweb.asm.ModuleVisitor;
* @author Remi Forax
*/
public class ModuleProvideNode {
/**
* The service name (in its internal form).
*/
/** The internal name of the service. */
public String service;
/**
* The service provider names (in their internal form).
*/
/** The internal names of the implementations of the service (there is at least one provider). */
public List<String> providers;
/**
* Constructs a new {@link ModuleProvideNode}.
*
* @param service
* the service name (in its internal form).
* @param providers
* the service provider names (in their internal form).
* @param service the internal name of the service.
* @param providers the internal names of the implementations of the service (there is at least
* one provider).
*/
public ModuleProvideNode(final String service, final List<String> providers) {
this.service = service;
@ -94,10 +89,9 @@ public class ModuleProvideNode {
/**
* Makes the given module visitor visit this require declaration.
*
* @param mv
* a module visitor.
* @param moduleVisitor a module visitor.
*/
public void accept(final ModuleVisitor mv) {
mv.visitProvide(service, providers.toArray(new String[0]));
public void accept(final ModuleVisitor moduleVisitor) {
moduleVisitor.visitProvide(service, providers.toArray(new String[0]));
}
}

View file

@ -66,39 +66,28 @@ import jdk.internal.org.objectweb.asm.ModuleVisitor;
* @author Remi Forax
*/
public class ModuleRequireNode {
/**
* The name of the required module.
*/
/** The fully qualified name (using dots) of the dependence. */
public String module;
/**
* The access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* Valid values are <tt>ACC_TRANSITIVE</tt>, <tt>ACC_STATIC_PHASE</tt>,
* <tt>ACC_SYNTHETIC</tt> and <tt>ACC_MANDATED</tt>.
* The access flag of the dependence among {@code ACC_TRANSITIVE}, {@code ACC_STATIC_PHASE},
* {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
*/
public int access;
/**
* Version at compile time of the required module or null.
*/
/** The module version at compile time, or {@literal null}. */
public String version;
/**
* Constructs a new {@link ModuleRequireNode}.
*
* @param module
* the name of the required module.
* @param access
* The access flags. Valid values are
* <tt>ACC_TRANSITIVE</tt>, <tt>ACC_STATIC_PHASE</tt>,
* <tt>ACC_SYNTHETIC</tt> and <tt>ACC_MANDATED</tt>
* (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* @param version
* Version of the required module at compile time,
* null if not defined.
* @param module the fully qualified name (using dots) of the dependence.
* @param access the access flag of the dependence among {@code ACC_TRANSITIVE}, {@code
* ACC_STATIC_PHASE}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* @param version the module version at compile time, or {@literal null}.
*/
public ModuleRequireNode(final String module, final int access,
final String version) {
public ModuleRequireNode(final String module, final int access, final String version) {
this.module = module;
this.access = access;
this.version = version;
@ -107,10 +96,9 @@ public class ModuleRequireNode {
/**
* Makes the given module visitor visit this require directive.
*
* @param mv
* a module visitor.
* @param moduleVisitor a module visitor.
*/
public void accept(final ModuleVisitor mv) {
mv.visitRequire(module, access, version);
public void accept(final ModuleVisitor moduleVisitor) {
moduleVisitor.visitRequire(module, access, version);
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -70,28 +69,22 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class MultiANewArrayInsnNode extends AbstractInsnNode {
/**
* An array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
/** An array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type}). */
public String desc;
/**
* Number of dimensions of the array to allocate.
*/
/** Number of dimensions of the array to allocate. */
public int dims;
/**
* Constructs a new {@link MultiANewArrayInsnNode}.
*
* @param desc
* an array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param dims
* number of dimensions of the array to allocate.
* @param descriptor an array type descriptor (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param numDimensions the number of dimensions of the array to allocate.
*/
public MultiANewArrayInsnNode(final String desc, final int dims) {
public MultiANewArrayInsnNode(final String descriptor, final int numDimensions) {
super(Opcodes.MULTIANEWARRAY);
this.desc = desc;
this.dims = dims;
this.desc = descriptor;
this.dims = numDimensions;
}
@Override
@ -100,14 +93,13 @@ public class MultiANewArrayInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitMultiANewArrayInsn(desc, dims);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitMultiANewArrayInsn(desc, dims);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new MultiANewArrayInsnNode(desc, dims).cloneAnnotations(this);
}
}

View file

@ -61,32 +61,27 @@ package jdk.internal.org.objectweb.asm.tree;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a parameter access and name.
* A node that represents a parameter of a method.
*
* @author Remi Forax
*/
public class ParameterNode {
/**
* The parameter's name.
*/
/** The parameter's name. */
public String name;
/**
* The parameter's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and
* <tt>ACC_MANDATED</tt>.
* The parameter's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). Valid values are {@code
* ACC_FINAL}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
*/
public int access;
/**
* Constructs a new {@link ParameterNode}.
*
* @param access
* The parameter's access flags. Valid values are
* <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and
* <tt>ACC_MANDATED</tt> (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* @param name
* the parameter's name.
* @param access The parameter's access flags. Valid values are {@code ACC_FINAL}, {@code
* ACC_SYNTHETIC} or/and {@code ACC_MANDATED} (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* @param name the parameter's name.
*/
public ParameterNode(final String name, final int access) {
this.name = name;
@ -96,10 +91,9 @@ public class ParameterNode {
/**
* Makes the given visitor visit this parameter declaration.
*
* @param mv
* a method visitor.
* @param methodVisitor a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitParameter(name, access);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitParameter(name, access);
}
}

View file

@ -58,11 +58,8 @@
*/
package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes;
@ -74,50 +71,34 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/
public class TableSwitchInsnNode extends AbstractInsnNode {
/**
* The minimum key value.
*/
/** The minimum key value. */
public int min;
/**
* The maximum key value.
*/
/** The maximum key value. */
public int max;
/**
* Beginning of the default handler block.
*/
/** Beginning of the default handler block. */
public LabelNode dflt;
/**
* Beginnings of the handler blocks. This list is a list of
* {@link LabelNode} objects.
*/
/** Beginnings of the handler blocks. This list is a list of {@link LabelNode} objects. */
public List<LabelNode> labels;
/**
* Constructs a new {@link TableSwitchInsnNode}.
*
* @param min
* the minimum key value.
* @param max
* the maximum key value.
* @param dflt
* beginning of the default handler block.
* @param labels
* beginnings of the handler blocks. <tt>labels[i]</tt> is the
* beginning of the handler block for the <tt>min + i</tt> key.
* @param min the minimum key value.
* @param max the maximum key value.
* @param dflt beginning of the default handler block.
* @param labels beginnings of the handler blocks. {@code labels[i]} is the beginning of the
* handler block for the {@code min + i} key.
*/
public TableSwitchInsnNode(final int min, final int max,
final LabelNode dflt, final LabelNode... labels) {
public TableSwitchInsnNode(
final int min, final int max, final LabelNode dflt, final LabelNode... labels) {
super(Opcodes.TABLESWITCH);
this.min = min;
this.max = max;
this.dflt = dflt;
this.labels = new ArrayList<LabelNode>();
if (labels != null) {
this.labels.addAll(Arrays.asList(labels));
}
this.labels = Util.asArrayList(labels);
}
@Override
@ -126,18 +107,18 @@ public class TableSwitchInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
Label[] labels = new Label[this.labels.size()];
for (int i = 0; i < labels.length; ++i) {
labels[i] = this.labels.get(i).getLabel();
public void accept(final MethodVisitor methodVisitor) {
Label[] labelsArray = new Label[this.labels.size()];
for (int i = 0, n = labelsArray.length; i < n; ++i) {
labelsArray[i] = this.labels.get(i).getLabel();
}
mv.visitTableSwitchInsn(min, max, dflt.getLabel(), labels);
acceptAnnotations(mv);
methodVisitor.visitTableSwitchInsn(min, max, dflt.getLabel(), labelsArray);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
return new TableSwitchInsnNode(min, max, clone(dflt, labels), clone(
this.labels, labels)).cloneAnnotations(this);
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new TableSwitchInsnNode(min, max, clone(dflt, clonedLabels), clone(labels, clonedLabels))
.cloneAnnotations(this);
}
}

View file

@ -59,7 +59,6 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.List;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
@ -69,63 +68,40 @@ import jdk.internal.org.objectweb.asm.MethodVisitor;
*/
public class TryCatchBlockNode {
/**
* Beginning of the exception handler's scope (inclusive).
*/
/** The beginning of the exception handler's scope (inclusive). */
public LabelNode start;
/**
* End of the exception handler's scope (exclusive).
*/
/** The end of the exception handler's scope (exclusive). */
public LabelNode end;
/**
* Beginning of the exception handler's code.
*/
/** The beginning of the exception handler's code. */
public LabelNode handler;
/**
* Internal name of the type of exceptions handled by the handler. May be
* <tt>null</tt> to catch any exceptions (for "finally" blocks).
* The internal name of the type of exceptions handled by the handler. May be {@literal null} to
* catch any exceptions (for "finally" blocks).
*/
public String type;
/**
* The runtime visible type annotations on the exception handler type. This
* list is a list of {@link TypeAnnotationNode} objects. May be
* <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
/** The runtime visible type annotations on the exception handler type. May be {@literal null}. */
public List<TypeAnnotationNode> visibleTypeAnnotations;
/**
* The runtime invisible type annotations on the exception handler type.
* This list is a list of {@link TypeAnnotationNode} objects. May be
* <tt>null</tt>.
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
* The runtime invisible type annotations on the exception handler type. May be {@literal null}.
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations;
/**
* Constructs a new {@link TryCatchBlockNode}.
*
* @param start
* beginning of the exception handler's scope (inclusive).
* @param end
* end of the exception handler's scope (exclusive).
* @param handler
* beginning of the exception handler's code.
* @param type
* internal name of the type of exceptions handled by the
* handler, or <tt>null</tt> to catch any exceptions (for
* "finally" blocks).
* @param start the beginning of the exception handler's scope (inclusive).
* @param end the end of the exception handler's scope (exclusive).
* @param handler the beginning of the exception handler's code.
* @param type the internal name of the type of exceptions handled by the handler, or {@literal
* null} to catch any exceptions (for "finally" blocks).
*/
public TryCatchBlockNode(final LabelNode start, final LabelNode end,
final LabelNode handler, final String type) {
public TryCatchBlockNode(
final LabelNode start, final LabelNode end, final LabelNode handler, final String type) {
this.start = start;
this.end = end;
this.handler = handler;
@ -133,24 +109,22 @@ public class TryCatchBlockNode {
}
/**
* Updates the index of this try catch block in the method's list of try
* catch block nodes. This index maybe stored in the 'target' field of the
* type annotations of this block.
* Updates the index of this try catch block in the method's list of try catch block nodes. This
* index maybe stored in the 'target' field of the type annotations of this block.
*
* @param index
* the new index of this try catch block in the method's list of
* try catch block nodes.
* @param index the new index of this try catch block in the method's list of try catch block
* nodes.
*/
public void updateIndex(final int index) {
int newTypeRef = 0x42000000 | (index << 8);
if (visibleTypeAnnotations != null) {
for (TypeAnnotationNode tan : visibleTypeAnnotations) {
tan.typeRef = newTypeRef;
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
visibleTypeAnnotations.get(i).typeRef = newTypeRef;
}
}
if (invisibleTypeAnnotations != null) {
for (TypeAnnotationNode tan : invisibleTypeAnnotations) {
tan.typeRef = newTypeRef;
for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
invisibleTypeAnnotations.get(i).typeRef = newTypeRef;
}
}
}
@ -158,25 +132,26 @@ public class TryCatchBlockNode {
/**
* Makes the given visitor visit this try catch block.
*
* @param mv
* a method visitor.
* @param methodVisitor a method visitor.
*/
public void accept(final MethodVisitor mv) {
mv.visitTryCatchBlock(start.getLabel(), end.getLabel(),
handler == null ? null : handler.getLabel(), type);
int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = visibleTypeAnnotations.get(i);
an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
an.desc, true));
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitTryCatchBlock(
start.getLabel(), end.getLabel(), handler == null ? null : handler.getLabel(), type);
if (visibleTypeAnnotations != null) {
for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
typeAnnotation.accept(
methodVisitor.visitTryCatchAnnotation(
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(
methodVisitor.visitTryCatchAnnotation(
typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
}
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
.size();
for (int i = 0; i < n; ++i) {
TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
an.accept(mv.visitTryCatchAnnotation(an.typeRef, an.typePath,
an.desc, false));
}
}
}

View file

@ -60,46 +60,37 @@ package jdk.internal.org.objectweb.asm.tree;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath;
import jdk.internal.org.objectweb.asm.TypeReference;
/**
* A node that represents a type annotationn.
* A node that represents a type annotation.
*
* @author Eric Bruneton
*/
public class TypeAnnotationNode extends AnnotationNode {
/**
* A reference to the annotated type. See {@link TypeReference}.
*/
/** A reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}. */
public int typeRef;
/**
* The path to the annotated type argument, wildcard bound, array element
* type, or static outer type within the referenced type. May be
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* The path to the annotated type argument, wildcard bound, array element type, or static outer
* type within the referenced type. May be {@literal null} if the annotation targets 'typeRef' as
* a whole.
*/
public TypePath typePath;
/**
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
* constructor</i>. Instead, they must use the
* {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
* Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this constructor</i>.
* Instead, they must use the {@link #TypeAnnotationNode(int, int, TypePath, String)} version.
*
* @param typeRef
* a reference to the annotated type. 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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @throws IllegalStateException
* If a subclass calls this constructor.
* @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
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
* @throws IllegalStateException If a subclass calls this constructor.
*/
public TypeAnnotationNode(final int typeRef, final TypePath typePath,
final String desc) {
this(Opcodes.ASM6, typeRef, typePath, desc);
public TypeAnnotationNode(final int typeRef, final TypePath typePath, final String descriptor) {
this(Opcodes.ASM7, typeRef, typePath, descriptor);
if (getClass() != TypeAnnotationNode.class) {
throw new IllegalStateException();
}
@ -108,21 +99,17 @@ 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} or {@link Opcodes#ASM6}.
* @param typeRef
* a reference to the annotated type. 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
* <tt>null</tt> if the annotation targets 'typeRef' as a whole.
* @param desc
* the class descriptor of the annotation class.
* @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 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
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
*/
public TypeAnnotationNode(final int api, final int typeRef,
final TypePath typePath, final String desc) {
super(api, desc);
public TypeAnnotationNode(
final int api, final int typeRef, final TypePath typePath, final String descriptor) {
super(api, descriptor);
this.typeRef = typeRef;
this.typePath = typePath;
}

View file

@ -59,44 +59,40 @@
package jdk.internal.org.objectweb.asm.tree;
import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor;
/**
* A node that represents a type instruction. A type instruction is an
* instruction that takes a type descriptor as parameter.
* A node that represents a type instruction. A type instruction is an instruction that takes a type
* descriptor as parameter.
*
* @author Eric Bruneton
*/
public class TypeInsnNode extends AbstractInsnNode {
/**
* The operand of this instruction. This operand is an internal name (see
* {@link jdk.internal.org.objectweb.asm.Type}).
* The operand of this instruction. This operand is an internal name (see {@link
* jdk.internal.org.objectweb.asm.Type}).
*/
public String desc;
/**
* Constructs a new {@link TypeInsnNode}.
*
* @param opcode
* the opcode of the type instruction to be constructed. This
* opcode must be NEW, ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param desc
* the operand of the instruction to be constructed. This operand
* is an internal name (see {@link jdk.internal.org.objectweb.asm.Type}).
* @param opcode the opcode of the type instruction to be constructed. This opcode must be NEW,
* ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param descriptor the operand of the instruction to be constructed. This operand is an internal
* name (see {@link jdk.internal.org.objectweb.asm.Type}).
*/
public TypeInsnNode(final int opcode, final String desc) {
public TypeInsnNode(final int opcode, final String descriptor) {
super(opcode);
this.desc = desc;
this.desc = descriptor;
}
/**
* Sets the opcode of this instruction.
*
* @param opcode
* the new instruction opcode. This opcode must be NEW,
* ANEWARRAY, CHECKCAST or INSTANCEOF.
* @param opcode the new instruction opcode. This opcode must be NEW, ANEWARRAY, CHECKCAST or
* INSTANCEOF.
*/
public void setOpcode(final int opcode) {
this.opcode = opcode;
@ -108,13 +104,13 @@ public class TypeInsnNode extends AbstractInsnNode {
}
@Override
public void accept(final MethodVisitor mv) {
mv.visitTypeInsn(opcode, desc);
acceptAnnotations(mv);
public void accept(final MethodVisitor methodVisitor) {
methodVisitor.visitTypeInsn(opcode, desc);
acceptAnnotations(methodVisitor);
}
@Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) {
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new TypeInsnNode(opcode, desc).cloneAnnotations(this);
}
}

View file

@ -0,0 +1,71 @@
/*
* 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;
/**
* Exception thrown in {@link AnnotationNode#check}, {@link ClassNode#check}, {@link
* FieldNode#check} and {@link MethodNode#check} when these nodes (or their children, recursively)
* contain elements that were introduced in more recent versions of the ASM API than version passed
* to these methods.
*
* @author Eric Bruneton
*/
public class UnsupportedClassVersionException extends RuntimeException {
private static final long serialVersionUID = -3502347765891805831L;
}

View file

@ -0,0 +1,188 @@
/*
* 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.ArrayList;
import java.util.List;
/**
* Utility methods to convert an array of primitive or object values to a mutable ArrayList, not
* baked by the array (unlike {@link java.util.Arrays#asList}).
*
* @author Eric Bruneton
*/
final class Util {
private Util() {}
static <T> List<T> asArrayList(final int length) {
List<T> list = new ArrayList<T>(length);
for (int i = 0; i < length; ++i) {
list.add(null);
}
return list;
}
static <T> List<T> asArrayList(final T[] array) {
if (array == null) {
return new ArrayList<T>();
}
ArrayList<T> list = new ArrayList<T>(array.length);
for (T t : array) {
list.add(t);
}
return list;
}
static List<Byte> asArrayList(final byte[] byteArray) {
if (byteArray == null) {
return new ArrayList<Byte>();
}
ArrayList<Byte> byteList = new ArrayList<Byte>(byteArray.length);
for (byte b : byteArray) {
byteList.add(b);
}
return byteList;
}
static List<Boolean> asArrayList(final boolean[] booleanArray) {
if (booleanArray == null) {
return new ArrayList<Boolean>();
}
ArrayList<Boolean> booleanList = new ArrayList<Boolean>(booleanArray.length);
for (boolean b : booleanArray) {
booleanList.add(b);
}
return booleanList;
}
static List<Short> asArrayList(final short[] shortArray) {
if (shortArray == null) {
return new ArrayList<Short>();
}
ArrayList<Short> shortList = new ArrayList<Short>(shortArray.length);
for (short s : shortArray) {
shortList.add(s);
}
return shortList;
}
static List<Character> asArrayList(final char[] charArray) {
if (charArray == null) {
return new ArrayList<Character>();
}
ArrayList<Character> charList = new ArrayList<Character>(charArray.length);
for (char c : charArray) {
charList.add(c);
}
return charList;
}
static List<Integer> asArrayList(final int[] intArray) {
if (intArray == null) {
return new ArrayList<Integer>();
}
ArrayList<Integer> intList = new ArrayList<Integer>(intArray.length);
for (int i : intArray) {
intList.add(i);
}
return intList;
}
static List<Float> asArrayList(final float[] floatArray) {
if (floatArray == null) {
return new ArrayList<Float>();
}
ArrayList<Float> floatList = new ArrayList<Float>(floatArray.length);
for (float f : floatArray) {
floatList.add(f);
}
return floatList;
}
static List<Long> asArrayList(final long[] longArray) {
if (longArray == null) {
return new ArrayList<Long>();
}
ArrayList<Long> longList = new ArrayList<Long>(longArray.length);
for (long l : longArray) {
longList.add(l);
}
return longList;
}
static List<Double> asArrayList(final double[] doubleArray) {
if (doubleArray == null) {
return new ArrayList<Double>();
}
ArrayList<Double> doubleList = new ArrayList<Double>(doubleArray.length);
for (double d : doubleArray) {
doubleList.add(d);
}
return doubleList;
}
static <T> List<T> asArrayList(final int length, final T[] array) {
List<T> list = new ArrayList<T>(length);
for (int i = 0; i < length; ++i) {
list.add(array[i]); // NOPMD(UseArraysAsList): we convert a part of the array.
}
return list;
}
}

Some files were not shown because too many files have changed in this diff Show more