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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,7 +43,7 @@ public class Main {
/** /**
* ASM version to be used by nasgen tool. * 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"); 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 cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+ ClassWriter.COMPUTE_FRAMES); + ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
@Override @Override
public void visit(int version, public void visit(int version,
int access, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ import static sun.invoke.util.Wrapper.*;
class TypeConvertingMethodAdapter extends MethodVisitor { class TypeConvertingMethodAdapter extends MethodVisitor {
TypeConvertingMethodAdapter(MethodVisitor mv) { TypeConvertingMethodAdapter(MethodVisitor mv) {
super(Opcodes.ASM5, mv); super(Opcodes.ASM7, mv);
} }
private static final int NUM_WRAPPERS = Wrapper.COUNT; 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -153,7 +153,7 @@ public final class ModuleInfoExtender {
ClassReader cr = new ClassReader(in); ClassReader cr = new ClassReader(in);
ClassVisitor cv = new ClassVisitor(Opcodes.ASM6, cw) { ClassVisitor cv = new ClassVisitor(Opcodes.ASM7, cw) {
@Override @Override
public ModuleVisitor visitModule(String name, int flags, String version) { public ModuleVisitor visitModule(String name, int flags, String version) {
Version v = ModuleInfoExtender.this.version; Version v = ModuleInfoExtender.this.version;
@ -170,7 +170,7 @@ public final class ModuleInfoExtender {
packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/'))); packages.forEach(pn -> mv.visitPackage(pn.replace('.', '/')));
} }
return new ModuleVisitor(Opcodes.ASM6, mv) { return new ModuleVisitor(Opcodes.ASM7, mv) {
public void visitMainClass(String existingMainClass) { public void visitMainClass(String existingMainClass) {
// skip main class if there is a new value // skip main class if there is a new value
if (mainClass == null) { if (mainClass == null) {

View file

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

View file

@ -59,342 +59,391 @@
package jdk.internal.org.objectweb.asm; 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 Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
final class AnnotationWriter extends AnnotationVisitor { final class AnnotationWriter extends AnnotationVisitor {
/** /** Where the constants used in this AnnotationWriter must be stored. */
* The class writer to which this annotation must be added. private final SymbolTable symbolTable;
*/
private final ClassWriter cw;
/** /**
* 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
private int size; * value, instead of an element_name_index followed by an element_value).
*/
private final boolean useNamedValues;
/** /**
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation * The 'annotation' or 'type_annotation' JVMS structure corresponding to the annotation values
* writers used for annotation default and annotation arrays use unnamed * visited so far. All the fields of these structures, except the last one - the
* values. * 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
private final boolean named; * #visitEnd()}). The element_value_pairs array is filled incrementally in the various visit()
* methods.
*
* <p>Note: as an exception to the above rules, for AnnotationDefault attributes (which contain a
* single element_value by definition), this ByteVector is initially empty when passed to the
* constructor, and {@link #numElementValuePairsOffset} is set to -1.
*/
private final ByteVector annotation;
/** /**
* The annotation values in bytecode form. This byte vector only contains * The offset in {@link #annotation} where {@link #numElementValuePairs} must be stored (or -1 for
* the values themselves, i.e. the number of values must be stored as a * the case of AnnotationDefault attributes).
* unsigned short just before these bytes. */
*/ private final int numElementValuePairsOffset;
private final ByteVector bv;
/** 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 * The previous AnnotationWriter. This field is used to store the list of annotations of a
* annotation. See {@link #bv}. * 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 * The next AnnotationWriter. This field is used to store the list of annotations of a
* {@link #parent}. * 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;
// -----------------------------------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------------------------------
/** /**
* Next annotation writer. This field is used to store annotation lists. * Constructs a new {@link AnnotationWriter}.
*/ *
AnnotationWriter next; * @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.
* Previous annotation writer. This field is used to store annotation lists. * @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
AnnotationWriter prev; * 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
// Constructor * other cases (e.g. nested or array annotations).
// ------------------------------------------------------------------------ */
AnnotationWriter(
/** final SymbolTable symbolTable,
* Constructs a new {@link AnnotationWriter}. final boolean useNamedValues,
* final ByteVector annotation,
* @param cw final AnnotationWriter previousAnnotation) {
* the class writer to which this annotation must be added. super(Opcodes.ASM7);
* @param named this.symbolTable = symbolTable;
* <tt>true<tt> if values are named, <tt>false</tt> otherwise. this.useNamedValues = useNamedValues;
* @param bv this.annotation = annotation;
* where the annotation values must be stored. // By hypothesis, num_element_value_pairs is stored in the last unsigned short of 'annotation'.
* @param parent this.numElementValuePairsOffset = annotation.length == 0 ? -1 : annotation.length - 2;
* where the number of annotation values must be stored. this.previousAnnotation = previousAnnotation;
* @param offset if (previousAnnotation != null) {
* where in <tt>parent</tt> the number of annotation values must previousAnnotation.nextAnnotation = this;
* be stored. }
*/
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;
} }
// ------------------------------------------------------------------------ /**
* 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 // Implementation of the AnnotationVisitor abstract class
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
@Override @Override
public void visit(final String name, final Object value) { public void visit(final String name, final Object value) {
++size; // Case of an element_value with a const_value_index, class_info_index or array_index field.
if (named) { // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
bv.putShort(cw.newUTF8(name)); ++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
} }
if (value instanceof String) { if (value instanceof String) {
bv.put12('s', cw.newUTF8((String) value)); annotation.put12('s', symbolTable.addConstantUtf8((String) value));
} else if (value instanceof Byte) { } 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) { } else if (value instanceof Boolean) {
int v = ((Boolean) value).booleanValue() ? 1 : 0; int booleanValue = ((Boolean) value).booleanValue() ? 1 : 0;
bv.put12('Z', cw.newInteger(v).index); annotation.put12('Z', symbolTable.addConstantInteger(booleanValue).index);
} else if (value instanceof Character) { } 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) { } 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) { } 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[]) { } else if (value instanceof byte[]) {
byte[] v = (byte[]) value; byte[] byteArray = (byte[]) value;
bv.put12('[', v.length); annotation.put12('[', byteArray.length);
for (int i = 0; i < v.length; i++) { for (byte byteValue : byteArray) {
bv.put12('B', cw.newInteger(v[i]).index); annotation.put12('B', symbolTable.addConstantInteger(byteValue).index);
} }
} else if (value instanceof boolean[]) { } else if (value instanceof boolean[]) {
boolean[] v = (boolean[]) value; boolean[] booleanArray = (boolean[]) value;
bv.put12('[', v.length); annotation.put12('[', booleanArray.length);
for (int i = 0; i < v.length; i++) { for (boolean booleanValue : booleanArray) {
bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index); annotation.put12('Z', symbolTable.addConstantInteger(booleanValue ? 1 : 0).index);
} }
} else if (value instanceof short[]) { } else if (value instanceof short[]) {
short[] v = (short[]) value; short[] shortArray = (short[]) value;
bv.put12('[', v.length); annotation.put12('[', shortArray.length);
for (int i = 0; i < v.length; i++) { for (short shortValue : shortArray) {
bv.put12('S', cw.newInteger(v[i]).index); annotation.put12('S', symbolTable.addConstantInteger(shortValue).index);
} }
} else if (value instanceof char[]) { } else if (value instanceof char[]) {
char[] v = (char[]) value; char[] charArray = (char[]) value;
bv.put12('[', v.length); annotation.put12('[', charArray.length);
for (int i = 0; i < v.length; i++) { for (char charValue : charArray) {
bv.put12('C', cw.newInteger(v[i]).index); annotation.put12('C', symbolTable.addConstantInteger(charValue).index);
} }
} else if (value instanceof int[]) { } else if (value instanceof int[]) {
int[] v = (int[]) value; int[] intArray = (int[]) value;
bv.put12('[', v.length); annotation.put12('[', intArray.length);
for (int i = 0; i < v.length; i++) { for (int intValue : intArray) {
bv.put12('I', cw.newInteger(v[i]).index); annotation.put12('I', symbolTable.addConstantInteger(intValue).index);
} }
} else if (value instanceof long[]) { } else if (value instanceof long[]) {
long[] v = (long[]) value; long[] longArray = (long[]) value;
bv.put12('[', v.length); annotation.put12('[', longArray.length);
for (int i = 0; i < v.length; i++) { for (long longValue : longArray) {
bv.put12('J', cw.newLong(v[i]).index); annotation.put12('J', symbolTable.addConstantLong(longValue).index);
} }
} else if (value instanceof float[]) { } else if (value instanceof float[]) {
float[] v = (float[]) value; float[] floatArray = (float[]) value;
bv.put12('[', v.length); annotation.put12('[', floatArray.length);
for (int i = 0; i < v.length; i++) { for (float floatValue : floatArray) {
bv.put12('F', cw.newFloat(v[i]).index); annotation.put12('F', symbolTable.addConstantFloat(floatValue).index);
} }
} else if (value instanceof double[]) { } else if (value instanceof double[]) {
double[] v = (double[]) value; double[] doubleArray = (double[]) value;
bv.put12('[', v.length); annotation.put12('[', doubleArray.length);
for (int i = 0; i < v.length; i++) { for (double doubleValue : doubleArray) {
bv.put12('D', cw.newDouble(v[i]).index); annotation.put12('D', symbolTable.addConstantDouble(doubleValue).index);
} }
} else { } else {
Item i = cw.newConstItem(value); Symbol symbol = symbolTable.addConstant(value);
bv.put12(".s.IFJDCS".charAt(i.type), i.index); annotation.put12(".s.IFJDCS".charAt(symbol.tag), symbol.index);
} }
} }
@Override @Override
public void visitEnum(final String name, final String desc, public void visitEnum(final String name, final String descriptor, final String value) {
final String value) { // Case of an element_value with an enum_const_value field.
++size; // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
if (named) { ++numElementValuePairs;
bv.putShort(cw.newUTF8(name)); 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 @Override
public AnnotationVisitor visitAnnotation(final String name, public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
final String desc) { // Case of an element_value with an annotation_value field.
++size; // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1.
if (named) { ++numElementValuePairs;
bv.putShort(cw.newUTF8(name)); if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
} }
// write tag and type, and reserve space for values count // Write tag and type_index, and reserve 2 bytes for num_element_value_pairs.
bv.put12('@', cw.newUTF8(desc)).putShort(0); annotation.put12('@', symbolTable.addConstantUtf8(descriptor)).putShort(0);
return new AnnotationWriter(cw, true, bv, bv, bv.length - 2); return new AnnotationWriter(symbolTable, annotation, null);
} }
@Override @Override
public AnnotationVisitor visitArray(final String name) { public AnnotationVisitor visitArray(final String name) {
++size; // Case of an element_value with an array_value field.
if (named) { // https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.1
bv.putShort(cw.newUTF8(name)); ++numElementValuePairs;
if (useNamedValues) {
annotation.putShort(symbolTable.addConstantUtf8(name));
} }
// write tag, and reserve space for array size // Write tag, and reserve 2 bytes for num_values. Here we take advantage of the fact that the
bv.put12('[', 0); // end of an element_value of array type is similar to the end of an 'annotation' structure: an
return new AnnotationWriter(cw, false, bv, bv, bv.length - 2); // 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 @Override
public void visitEnd() { public void visitEnd() {
if (parent != null) { if (numElementValuePairsOffset != -1) {
byte[] data = parent.data; byte[] data = annotation.data;
data[offset] = (byte) (size >>> 8); data[numElementValuePairsOffset] = (byte) (numElementValuePairs >>> 8);
data[offset + 1] = (byte) size; data[numElementValuePairsOffset + 1] = (byte) numElementValuePairs;
} }
} }
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
// Utility methods // 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
* @return the size of this annotation writer list. * to the constant pool of the class (if not null).
*/ *
int getSize() { * @param attributeName one of "Runtime[In]Visible[Type]Annotations", or null.
int size = 0; * @return the size in bytes of a Runtime[In]Visible[Type]Annotations attribute containing this
AnnotationWriter aw = this; * annotation and all its predecessors. This includes the size of the attribute_name_index and
while (aw != null) { * attribute_length fields.
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 * Puts a Runtime[In]Visible[Type]Annotations attribute containing this annotations and all its
* vector. * <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").
void put(final ByteVector out) { * @param output where the attribute must be put.
int n = 0; */
int size = 2; void putAnnotations(final int attributeNameIndex, final ByteVector output) {
AnnotationWriter aw = this; int attributeLength = 2; // For num_annotations.
AnnotationWriter last = null; int numAnnotations = 0;
while (aw != null) { AnnotationWriter annotationWriter = this;
++n; AnnotationWriter firstAnnotation = null;
size += aw.bv.length; while (annotationWriter != null) {
aw.visitEnd(); // in case user forgot to call visitEnd // In case the user forgot to call visitEnd().
aw.prev = last; annotationWriter.visitEnd();
last = aw; attributeLength += annotationWriter.annotation.length;
aw = aw.next; numAnnotations++;
firstAnnotation = annotationWriter;
annotationWriter = annotationWriter.previousAnnotation;
} }
out.putInt(size); output.putShort(attributeNameIndex);
out.putShort(n); output.putInt(attributeLength);
aw = last; output.putShort(numAnnotations);
while (aw != null) { annotationWriter = firstAnnotation;
out.putByteArray(aw.bv.data, 0, aw.bv.length); while (annotationWriter != null) {
aw = aw.prev; 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
* @param panns * constant pool of the class.
* an array of annotation writer lists. *
* @param off * @param attributeName one of "Runtime[In]VisibleParameterAnnotations".
* index of the first annotation to be written. * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
* @param out * element).
* where the annotations must be put. * @param annotableParameterCount the number of elements in annotationWriters to take into account
*/ * (elements [0..annotableParameterCount[ are taken into account).
static void put(final AnnotationWriter[] panns, final int off, * @return the size in bytes of a Runtime[In]VisibleParameterAnnotations attribute corresponding
final ByteVector out) { * to the given sub-array of AnnotationWriter lists. This includes the size of the
int size = 1 + 2 * (panns.length - off); * attribute_name_index and attribute_length fields.
for (int i = off; i < panns.length; ++i) { */
size += panns[i] == null ? 0 : panns[i].getSize(); 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;
} }
out.putInt(size).putByte(panns.length - off); return attributeSize;
for (int i = off; i < panns.length; ++i) { }
AnnotationWriter aw = panns[i];
AnnotationWriter last = null; /**
int n = 0; * Puts a Runtime[In]VisibleParameterAnnotations attribute containing all the annotation lists
while (aw != null) { * from the given AnnotationWriter sub-array in the given ByteVector.
++n; *
aw.visitEnd(); // in case user forgot to call visitEnd * @param attributeNameIndex constant pool index of the attribute name (one of
aw.prev = last; * Runtime[In]VisibleParameterAnnotations).
last = aw; * @param annotationWriters an array of AnnotationWriter lists (designated by their <i>last</i>
aw = aw.next; * element).
* @param annotableParameterCount the number of elements in annotationWriters to put (elements
* [0..annotableParameterCount[ are put).
* @param output where the attribute must be put.
*/
static void putParameterAnnotations(
final int attributeNameIndex,
final AnnotationWriter[] annotationWriters,
final int annotableParameterCount,
final ByteVector output) {
// The num_parameters field uses 1 byte, and each element of the parameter_annotations array
// uses 2 bytes for its num_annotations field.
int attributeLength = 1 + 2 * annotableParameterCount;
for (int i = 0; i < annotableParameterCount; ++i) {
AnnotationWriter annotationWriter = annotationWriters[i];
attributeLength +=
annotationWriter == null ? 0 : annotationWriter.computeAnnotationsSize(null) - 8;
}
output.putShort(attributeNameIndex);
output.putInt(attributeLength);
output.putByte(annotableParameterCount);
for (int i = 0; i < annotableParameterCount; ++i) {
AnnotationWriter annotationWriter = annotationWriters[i];
AnnotationWriter firstAnnotation = null;
int numAnnotations = 0;
while (annotationWriter != null) {
// In case user the forgot to call visitEnd().
annotationWriter.visitEnd();
numAnnotations++;
firstAnnotation = annotationWriter;
annotationWriter = annotationWriter.previousAnnotation;
} }
out.putShort(n); output.putShort(numAnnotations);
aw = last; annotationWriter = firstAnnotation;
while (aw != null) { while (annotationWriter != null) {
out.putByteArray(aw.bv.data, 0, aw.bv.length); output.putByteArray(
aw = aw.prev; annotationWriter.annotation.data, 0, annotationWriter.annotation.length);
annotationWriter = annotationWriter.nextAnnotation;
} }
} }
} }
/**
* Puts the given type reference and type path into the given bytevector.
* LOCAL_VARIABLE and RESOURCE_VARIABLE target types are not supported.
*
* @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.
*/
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;
}
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,297 +58,299 @@
*/ */
package jdk.internal.org.objectweb.asm; 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 Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
public class Attribute { public class Attribute {
/** /** The type of this attribute, also called its name in the JVMS. */
* The type of this attribute.
*/
public final String type; 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>
byte[] value; * included.
*/
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. * Constructs a new empty attribute.
* *
* @param type * @param type the type of the attribute.
* the type of the attribute. */
*/
protected Attribute(final String type) { protected Attribute(final String type) {
this.type = type; this.type = type;
} }
/** /**
* Returns <tt>true</tt> if this type of attribute is unknown. The default * Returns {@literal true} if this type of attribute is unknown. This means that the attribute
* implementation of this method always returns <tt>true</tt>. * 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
* @return <tt>true</tt> if this type of attribute is unknown. * invalid attributes, if the content actually contains constant pool references, labels, or other
*/ * symbolic references that need to be updated when there are changes to the constant pool, the
* method bytecode, etc. The default implementation of this method always returns {@literal true}.
*
* @return {@literal true} if this type of attribute is unknown.
*/
public boolean isUnknown() { public boolean isUnknown() {
return true; 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() { public boolean isCodeAttribute() {
return false; return false;
} }
/** /**
* Returns the labels corresponding to this attribute. * Returns the labels corresponding to this attribute.
* *
* @return the labels corresponding to this attribute, or <tt>null</tt> if * @return the labels corresponding to this attribute, or {@literal null} if this attribute is not
* this attribute is not a code attribute that contains labels. * a code attribute that contains labels.
*/ */
protected Label[] getLabels() { protected Label[] getLabels() {
return null; return new Label[0];
} }
/** /**
* Reads a {@link #type type} attribute. This method must return a * Reads a {@link #type} attribute. This method must return a <i>new</i> {@link Attribute} object,
* <i>new</i> {@link Attribute} object, of type {@link #type type}, * of type {@link #type}, corresponding to the 'length' bytes starting at 'offset', in the given
* corresponding to the <tt>len</tt> bytes starting at the given offset, in * ClassReader.
* the given class reader. *
* * @param classReader the class that contains the attribute to be read.
* @param cr * @param offset index of the first byte of the attribute's content in {@link ClassReader#b}. The
* the class that contains the attribute to be read. * 6 attribute header bytes (attribute_name_index and attribute_length) are not taken into
* @param off * account here.
* index of the first byte of the attribute's content in * @param length the length of the attribute's content (excluding the 6 attribute header bytes).
* {@link ClassReader#b cr.b}. The 6 attribute header bytes, * @param charBuffer the buffer to be used to call the ClassReader methods requiring a
* containing the type and the length of the attribute, are not * 'charBuffer' parameter.
* taken into account here. * @param codeAttributeOffset index of the first byte of content of the enclosing Code attribute
* @param len * in {@link ClassReader#b}, or -1 if the attribute to be read is not a code attribute. The 6
* the length of the attribute's content. * attribute header bytes (attribute_name_index and attribute_length) are not taken into
* @param buf * account here.
* buffer to be used to call {@link ClassReader#readUTF8 * @param labels the labels of the method's code, or {@literal null} if the attribute to be read
* readUTF8}, {@link ClassReader#readClass(int,char[]) readClass} * is not a code attribute.
* or {@link ClassReader#readConst readConst}. * @return a <i>new</i> {@link Attribute} object corresponding to the specified bytes.
* @param codeOff */
* index of the first byte of code's attribute content in protected Attribute read(
* {@link ClassReader#b cr.b}, or -1 if the attribute to be read final ClassReader classReader,
* is not a code attribute. The 6 attribute header bytes, final int offset,
* containing the type and the length of the attribute, are not final int length,
* taken into account here. final char[] charBuffer,
* @param labels final int codeAttributeOffset,
* 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) { final Label[] labels) {
Attribute attr = new Attribute(type); Attribute attribute = new Attribute(type);
attr.value = new byte[len]; attribute.content = new byte[length];
System.arraycopy(cr.b, off, attr.value, 0, len); System.arraycopy(classReader.b, offset, attribute.content, 0, length);
return attr; return attribute;
} }
/** /**
* Returns the byte array form of this 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
* @param cw * ByteVector.
* the class to which this attribute must be added. This *
* parameter can be used to add to the constant pool of this * @param classWriter the class to which this attribute must be added. This parameter can be used
* class the items that corresponds to this attribute. * to add the items that corresponds to this attribute to the constant pool of this class.
* @param code * @param code the bytecode of the method corresponding to this code attribute, or {@literal null}
* the bytecode of the method corresponding to this code * if this attribute is not a code attribute. Corresponds to the 'code' field of the Code
* attribute, or <tt>null</tt> if this attribute is not a code * attribute.
* attributes. * @param codeLength the length of the bytecode of the method corresponding to this code
* @param len * attribute, or 0 if this attribute is not a code attribute. Corresponds to the 'code_length'
* the length of the bytecode of the method corresponding to this * field of the Code attribute.
* code attribute, or <tt>null</tt> if this attribute is not a * @param maxStack the maximum stack size of the method corresponding to this code attribute, or
* code attribute. * -1 if this attribute is not a code attribute.
* @param maxStack * @param maxLocals the maximum number of local variables of the method corresponding to this code
* the maximum stack size of the method corresponding to this * attribute, or -1 if this attribute is not a code attribute.
* code attribute, or -1 if this attribute is not a code * @return the byte array form of this attribute.
* attribute. */
* @param maxLocals protected ByteVector write(
* the maximum number of local variables of the method final ClassWriter classWriter,
* corresponding to this code attribute, or -1 if this attribute final byte[] code,
* is not a code attribute. final int codeLength,
* @return the byte array form of this attribute. final int maxStack,
*/ final int maxLocals) {
protected ByteVector write(final ClassWriter cw, final byte[] code, return new ByteVector(content);
final int len, final int maxStack, final int maxLocals) {
ByteVector v = new ByteVector();
v.data = value;
v.length = value.length;
return v;
} }
/** /**
* 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; int count = 0;
Attribute attr = this; Attribute attribute = this;
while (attr != null) { while (attribute != null) {
count += 1; count += 1;
attr = attr.next; attribute = attribute.nextAttribute;
} }
return count; 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
* @param cw * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
* the class writer to be used to convert the attributes into *
* byte arrays, with the {@link #write write} method. * @param symbolTable where the constants used in the attributes must be stored.
* @param code * @return the size of all the attributes in this attribute list. This size includes the size of
* the bytecode of the method corresponding to these code * the attribute headers.
* attributes, or <tt>null</tt> if these attributes are not code */
* attributes. final int computeAttributesSize(final SymbolTable symbolTable) {
* @param len final byte[] code = null;
* the length of the bytecode of the method corresponding to final int codeLength = 0;
* these code attributes, or <tt>null</tt> if these attributes final int maxStack = -1;
* are not code attributes. final int maxLocals = -1;
* @param maxStack return computeAttributesSize(symbolTable, code, codeLength, maxStack, maxLocals);
* the maximum stack size of the method corresponding to these }
* code attributes, or -1 if these attributes are not code
* attributes. /**
* @param maxLocals * Returns the total size in bytes of all the attributes in the attribute list that begins with
* the maximum number of local variables of the method * this attribute. This size includes the 6 header bytes (attribute_name_index and
* corresponding to these code attributes, or -1 if these * attribute_length) per attribute. Also adds the attribute type names to the constant pool.
* attributes are not code attributes. *
* @return the size of all the attributes in this attribute list. This size * @param symbolTable where the constants used in the attributes must be stored.
* includes the size of the attribute headers. * @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
final int getSize(final ClassWriter cw, final byte[] code, final int len, * attribute.
final int maxStack, final int maxLocals) { * @param codeLength the length of the bytecode of the method corresponding to these code
Attribute attr = this; * 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; int size = 0;
while (attr != null) { Attribute attribute = this;
cw.newUTF8(attr.type); while (attribute != null) {
size += attr.write(cw, code, len, maxStack, maxLocals).length + 6; symbolTable.addConstantUtf8(attribute.type);
attr = attr.next; size += 6 + attribute.write(classWriter, code, codeLength, maxStack, maxLocals).length;
attribute = attribute.nextAttribute;
} }
return size; return size;
} }
/** /**
* Writes all the attributes of this attribute list in the given byte * Puts all the attributes of the attribute list that begins with this attribute, in the given
* vector. * 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 * @param symbolTable where the constants used in the attributes must be stored.
* byte arrays, with the {@link #write write} method. * @param output where the attributes must be written.
* @param code */
* the bytecode of the method corresponding to these code final void putAttributes(final SymbolTable symbolTable, final ByteVector output) {
* attributes, or <tt>null</tt> if these attributes are not code final byte[] code = null;
* attributes. final int codeLength = 0;
* @param len final int maxStack = -1;
* the length of the bytecode of the method corresponding to final int maxLocals = -1;
* these code attributes, or <tt>null</tt> if these attributes putAttributes(symbolTable, code, codeLength, maxStack, maxLocals, output);
* 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 * Puts all the attributes of the attribute list that begins with this attribute, in the given
* attributes. * byte vector. This includes the 6 header bytes (attribute_name_index and attribute_length) per
* @param maxLocals * attribute.
* the maximum number of local variables of the method *
* corresponding to these code attributes, or -1 if these * @param symbolTable where the constants used in the attributes must be stored.
* attributes are not code attributes. * @param code the bytecode of the method corresponding to these code attributes, or {@literal
* @param out * null} if they are not code attributes. Corresponds to the 'code' field of the Code
* where the attributes must be written. * attribute.
*/ * @param codeLength the length of the bytecode of the method corresponding to these code
final void put(final ClassWriter cw, final byte[] code, final int len, * attributes, or 0 if they are not code attributes. Corresponds to the 'code_length' field of
final int maxStack, final int maxLocals, final ByteVector out) { * the Code attribute.
Attribute attr = this; * @param maxStack the maximum stack size of the method corresponding to these code attributes, or
while (attr != null) { * -1 if they are not code attributes.
ByteVector b = attr.write(cw, code, len, maxStack, maxLocals); * @param maxLocals the maximum number of local variables of the method corresponding to these
out.putShort(cw.newUTF8(attr.type)).putInt(b.length); * code attributes, or -1 if they are not code attribute.
out.putByteArray(b.data, 0, b.length); * @param output where the attributes must be written.
attr = attr.next; */
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. /** A set of attribute prototypes (attributes with the same type are considered equal). */
//see also changes in ClassReader.accept. static final class Set {
public static class NestMembers extends Attribute { private static final int SIZE_INCREMENT = 6;
public NestMembers() {
super("NestMembers");
}
byte[] bytes; private int size;
String[] classes; private Attribute[] data = new Attribute[SIZE_INCREMENT];
@Override void addAttributes(final Attribute attributeList) {
protected Attribute read(ClassReader cr, int off, int len, char[] buf, int codeOff, Label[] labels) { Attribute attribute = attributeList;
int offset = off; while (attribute != null) {
NestMembers a = new NestMembers(); if (!contains(attribute)) {
int size = cr.readShort(off); add(attribute);
a.classes = new String[size]; }
off += 2; attribute = attribute.nextAttribute;
for (int i = 0; i < size ; i++) {
a.classes[i] = cr.readClass(off, buf);
off += 2;
} }
a.bytes = Arrays.copyOfRange(cr.b, offset, offset + len);
return a;
} }
@Override Attribute[] toArray() {
protected ByteVector write(ClassWriter cw, byte[] code, int len, int maxStack, int maxLocals) { Attribute[] result = new Attribute[size];
ByteVector v = new ByteVector(bytes.length); System.arraycopy(data, 0, result, 0, size);
v.putShort(classes.length); return result;
for (String s : classes) { }
v.putShort(cw.newClass(s));
private boolean contains(final Attribute attribute) {
for (int i = 0; i < size; ++i) {
if (data[i].type.equals(attribute.type)) {
return true;
}
} }
return v; return false;
}
private void add(final Attribute attribute) {
if (size >= data.length) {
Attribute[] newData = new Attribute[data.length + SIZE_INCREMENT];
System.arraycopy(data, 0, newData, 0, size);
data = newData;
}
data[size++] = attribute;
} }
} }
public static class NestHost extends Attribute {
byte[] bytes;
String clazz;
public NestHost() {
super("NestHost");
}
@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;
}
@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;
}
}
static final Attribute[] DEFAULT_ATTRIBUTE_PROTOS = new Attribute[] {
new NestMembers(),
new NestHost()
};
} }

View file

@ -59,309 +59,333 @@
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* A dynamically extensible vector of bytes. This class is roughly equivalent to * A dynamically extensible vector of bytes. This class is roughly equivalent to a DataOutputStream
* a DataOutputStream on top of a ByteArrayOutputStream, but is more efficient. * on top of a ByteArrayOutputStream, but is more efficient.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public class ByteVector { public class ByteVector {
/** /** The content of this vector. Only the first {@link #length} bytes contain real data. */
* The content of this vector.
*/
byte[] data; byte[] data;
/** /** The actual number of bytes in this vector. */
* Actual number of bytes in this vector.
*/
int length; int length;
/** /** Constructs a new {@link ByteVector} with a default initial capacity. */
* Constructs a new {@link ByteVector ByteVector} with a default initial
* size.
*/
public ByteVector() { public ByteVector() {
data = new byte[64]; data = new byte[64];
} }
/** /**
* Constructs a new {@link ByteVector ByteVector} with the given initial * Constructs a new {@link ByteVector} with the given initial capacity.
* size. *
* * @param initialCapacity the initial capacity of the byte vector to be constructed.
* @param initialSize */
* the initial size of the byte vector to be constructed. public ByteVector(final int initialCapacity) {
*/ data = new byte[initialCapacity];
public ByteVector(final int initialSize) {
data = new byte[initialSize];
} }
/** /**
* Puts a byte into this byte vector. The byte vector is automatically * Constructs a new {@link ByteVector} from the given initial data.
* enlarged if necessary. *
* * @param data the initial data of the new byte vector.
* @param b */
* a byte. ByteVector(final byte[] data) {
* @return this byte vector. this.data = data;
*/ this.length = data.length;
public ByteVector putByte(final int b) { }
int length = this.length;
if (length + 1 > data.length) { /**
* Puts a byte into this byte vector. The byte vector is automatically enlarged if necessary.
*
* @param byteValue a byte.
* @return this byte vector.
*/
public ByteVector putByte(final int byteValue) {
int currentLength = length;
if (currentLength + 1 > data.length) {
enlarge(1); enlarge(1);
} }
data[length++] = (byte) b; data[currentLength++] = (byte) byteValue;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts two bytes into this byte vector. The byte vector is automatically * Puts two bytes into this byte vector. The byte vector is automatically enlarged if necessary.
* enlarged if necessary. *
* * @param byteValue1 a byte.
* @param b1 * @param byteValue2 another byte.
* a byte. * @return this byte vector.
* @param b2 */
* another byte. final ByteVector put11(final int byteValue1, final int byteValue2) {
* @return this byte vector. int currentLength = length;
*/ if (currentLength + 2 > data.length) {
ByteVector put11(final int b1, final int b2) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2); enlarge(2);
} }
byte[] data = this.data; byte[] currentData = data;
data[length++] = (byte) b1; currentData[currentLength++] = (byte) byteValue1;
data[length++] = (byte) b2; currentData[currentLength++] = (byte) byteValue2;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts a short into this byte vector. The byte vector is automatically * Puts a short into this byte vector. The byte vector is automatically enlarged if necessary.
* enlarged if necessary. *
* * @param shortValue a short.
* @param s * @return this byte vector.
* a short. */
* @return this byte vector. public ByteVector putShort(final int shortValue) {
*/ int currentLength = length;
public ByteVector putShort(final int s) { if (currentLength + 2 > data.length) {
int length = this.length;
if (length + 2 > data.length) {
enlarge(2); enlarge(2);
} }
byte[] data = this.data; byte[] currentData = data;
data[length++] = (byte) (s >>> 8); currentData[currentLength++] = (byte) (shortValue >>> 8);
data[length++] = (byte) s; currentData[currentLength++] = (byte) shortValue;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts a byte and a short into this byte vector. The byte vector is * Puts a byte and a short into this byte vector. The byte vector is automatically enlarged if
* automatically enlarged if necessary. * necessary.
* *
* @param b * @param byteValue a byte.
* a byte. * @param shortValue a short.
* @param s * @return this byte vector.
* a short. */
* @return this byte vector. final ByteVector put12(final int byteValue, final int shortValue) {
*/ int currentLength = length;
ByteVector put12(final int b, final int s) { if (currentLength + 3 > data.length) {
int length = this.length;
if (length + 3 > data.length) {
enlarge(3); enlarge(3);
} }
byte[] data = this.data; byte[] currentData = data;
data[length++] = (byte) b; currentData[currentLength++] = (byte) byteValue;
data[length++] = (byte) (s >>> 8); currentData[currentLength++] = (byte) (shortValue >>> 8);
data[length++] = (byte) s; currentData[currentLength++] = (byte) shortValue;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts an int into this byte vector. The byte vector is automatically * Puts two bytes and a short into this byte vector. The byte vector is automatically enlarged if
* enlarged if necessary. * necessary.
* *
* @param i * @param byteValue1 a byte.
* an int. * @param byteValue2 another byte.
* @return this byte vector. * @param shortValue a short.
*/ * @return this byte vector.
public ByteVector putInt(final int i) { */
int length = this.length; final ByteVector put112(final int byteValue1, final int byteValue2, final int shortValue) {
if (length + 4 > data.length) { int currentLength = length;
if (currentLength + 4 > data.length) {
enlarge(4); enlarge(4);
} }
byte[] data = this.data; byte[] currentData = data;
data[length++] = (byte) (i >>> 24); currentData[currentLength++] = (byte) byteValue1;
data[length++] = (byte) (i >>> 16); currentData[currentLength++] = (byte) byteValue2;
data[length++] = (byte) (i >>> 8); currentData[currentLength++] = (byte) (shortValue >>> 8);
data[length++] = (byte) i; currentData[currentLength++] = (byte) shortValue;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts a long into this byte vector. The byte vector is automatically * Puts an int into this byte vector. The byte vector is automatically enlarged if necessary.
* enlarged if necessary. *
* * @param intValue an int.
* @param l * @return this byte vector.
* a long. */
* @return this byte vector. public ByteVector putInt(final int intValue) {
*/ int currentLength = length;
public ByteVector putLong(final long l) { if (currentLength + 4 > data.length) {
int length = this.length; enlarge(4);
if (length + 8 > data.length) { }
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); enlarge(8);
} }
byte[] data = this.data; byte[] currentData = data;
int i = (int) (l >>> 32); int intValue = (int) (longValue >>> 32);
data[length++] = (byte) (i >>> 24); currentData[currentLength++] = (byte) (intValue >>> 24);
data[length++] = (byte) (i >>> 16); currentData[currentLength++] = (byte) (intValue >>> 16);
data[length++] = (byte) (i >>> 8); currentData[currentLength++] = (byte) (intValue >>> 8);
data[length++] = (byte) i; currentData[currentLength++] = (byte) intValue;
i = (int) l; intValue = (int) longValue;
data[length++] = (byte) (i >>> 24); currentData[currentLength++] = (byte) (intValue >>> 24);
data[length++] = (byte) (i >>> 16); currentData[currentLength++] = (byte) (intValue >>> 16);
data[length++] = (byte) (i >>> 8); currentData[currentLength++] = (byte) (intValue >>> 8);
data[length++] = (byte) i; currentData[currentLength++] = (byte) intValue;
this.length = length; length = currentLength;
return this; return this;
} }
/** /**
* Puts an UTF8 string into this byte vector. The byte vector is * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
* automatically enlarged if necessary. * necessary.
* *
* @param s * @param stringValue a String whose UTF8 encoded length must be less than 65536.
* a String whose UTF8 encoded length must be less than 65536. * @return this byte vector.
* @return this byte vector. */
*/ // DontCheck(AbbreviationAsWordInName): can't be renamed (for backward binary compatibility).
public ByteVector putUTF8(final String s) { public ByteVector putUTF8(final String stringValue) {
int charLength = s.length(); int charLength = stringValue.length();
if (charLength > 65535) { if (charLength > 65535) {
throw new IllegalArgumentException(); throw new IllegalArgumentException("UTF8 string too large");
} }
int len = length; int currentLength = length;
if (len + 2 + charLength > data.length) { if (currentLength + 2 + charLength > data.length) {
enlarge(2 + charLength); enlarge(2 + charLength);
} }
byte[] data = this.data; byte[] currentData = data;
// optimistic algorithm: instead of computing the byte length and then // Optimistic algorithm: instead of computing the byte length and then serializing the string
// serializing the string (which requires two loops), we assume the byte // (which requires two loops), we assume the byte length is equal to char length (which is the
// length is equal to char length (which is the most frequent case), and // most frequent case), and we start serializing the string right away. During the
// we start serializing the string right away. During the serialization, // serialization, if we find that this assumption is wrong, we continue with the general method.
// if we find that this assumption is wrong, we continue with the currentData[currentLength++] = (byte) (charLength >>> 8);
// general method. currentData[currentLength++] = (byte) charLength;
data[len++] = (byte) (charLength >>> 8);
data[len++] = (byte) charLength;
for (int i = 0; i < charLength; ++i) { for (int i = 0; i < charLength; ++i) {
char c = s.charAt(i); char charValue = stringValue.charAt(i);
if (c >= '\001' && c <= '\177') { if (charValue >= '\u0001' && charValue <= '\u007F') {
data[len++] = (byte) c; currentData[currentLength++] = (byte) charValue;
} else { } else {
length = len; length = currentLength;
return encodeUTF8(s, i, 65535); return encodeUtf8(stringValue, i, 65535);
} }
} }
length = len; length = currentLength;
return this; return this;
} }
/** /**
* Puts an UTF8 string into this byte vector. The byte vector is * Puts an UTF8 string into this byte vector. The byte vector is automatically enlarged if
* automatically enlarged if necessary. The string length is encoded in two * necessary. The string length is encoded in two bytes before the encoded characters, if there is
* bytes before the encoded characters, if there is space for that (i.e. if * space for that (i.e. if this.length - offset - 2 &gt;= 0).
* this.length - i - 2 >= 0). *
* * @param stringValue the String to encode.
* @param s * @param offset the index of the first character to encode. The previous characters are supposed
* the String to encode. * to have already been encoded, using only one byte per character.
* @param i * @param maxByteLength the maximum byte length of the encoded string, including the already
* the index of the first character to encode. The previous * encoded characters.
* characters are supposed to have already been encoded, using * @return this byte vector.
* only one byte per character. */
* @param maxByteLength final ByteVector encodeUtf8(final String stringValue, final int offset, final int maxByteLength) {
* the maximum byte length of the encoded string, including the int charLength = stringValue.length();
* already encoded characters. int byteLength = offset;
* @return this byte vector. for (int i = offset; i < charLength; ++i) {
*/ char charValue = stringValue.charAt(i);
ByteVector encodeUTF8(final String s, int i, int maxByteLength) { if (charValue >= 0x0001 && charValue <= 0x007F) {
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') {
byteLength++; byteLength++;
} else if (c > '\u07FF') { } else if (charValue <= 0x07FF) {
byteLength += 3;
} else {
byteLength += 2; byteLength += 2;
} else {
byteLength += 3;
} }
} }
if (byteLength > maxByteLength) { if (byteLength > maxByteLength) {
throw new IllegalArgumentException(); throw new IllegalArgumentException("UTF8 string too large");
} }
int start = length - i - 2; // Compute where 'byteLength' must be stored in 'data', and store it at this location.
if (start >= 0) { int byteLengthOffset = length - offset - 2;
data[start] = (byte) (byteLength >>> 8); if (byteLengthOffset >= 0) {
data[start + 1] = (byte) byteLength; data[byteLengthOffset] = (byte) (byteLength >>> 8);
data[byteLengthOffset + 1] = (byte) byteLength;
} }
if (length + byteLength - i > data.length) { if (length + byteLength - offset > data.length) {
enlarge(byteLength - i); enlarge(byteLength - offset);
} }
int len = length; int currentLength = length;
for (int j = i; j < charLength; ++j) { for (int i = offset; i < charLength; ++i) {
c = s.charAt(j); char charValue = stringValue.charAt(i);
if (c >= '\001' && c <= '\177') { if (charValue >= 0x0001 && charValue <= 0x007F) {
data[len++] = (byte) c; data[currentLength++] = (byte) charValue;
} else if (c > '\u07FF') { } else if (charValue <= 0x07FF) {
data[len++] = (byte) (0xE0 | c >> 12 & 0xF); data[currentLength++] = (byte) (0xC0 | charValue >> 6 & 0x1F);
data[len++] = (byte) (0x80 | c >> 6 & 0x3F); data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
data[len++] = (byte) (0x80 | c & 0x3F);
} else { } else {
data[len++] = (byte) (0xC0 | c >> 6 & 0x1F); data[currentLength++] = (byte) (0xE0 | charValue >> 12 & 0xF);
data[len++] = (byte) (0x80 | c & 0x3F); data[currentLength++] = (byte) (0x80 | charValue >> 6 & 0x3F);
data[currentLength++] = (byte) (0x80 | charValue & 0x3F);
} }
} }
length = len; length = currentLength;
return this; return this;
} }
/** /**
* Puts an array of bytes into this byte vector. The byte vector is * Puts an array of bytes into this byte vector. The byte vector is automatically enlarged if
* automatically enlarged if necessary. * necessary.
* *
* @param b * @param byteArrayValue an array of bytes. May be {@literal null} to put {@code byteLength} null
* an array of bytes. May be <tt>null</tt> to put <tt>len</tt> * bytes into this byte vector.
* null bytes into this byte vector. * @param byteOffset index of the first byte of byteArrayValue that must be copied.
* @param off * @param byteLength number of bytes of byteArrayValue that must be copied.
* index of the fist byte of b that must be copied. * @return this byte vector.
* @param len */
* number of bytes of b that must be copied. public ByteVector putByteArray(
* @return this byte vector. final byte[] byteArrayValue, final int byteOffset, final int byteLength) {
*/ if (length + byteLength > data.length) {
public ByteVector putByteArray(final byte[] b, final int off, final int len) { enlarge(byteLength);
if (length + len > data.length) {
enlarge(len);
} }
if (b != null) { if (byteArrayValue != null) {
System.arraycopy(b, off, data, length, len); System.arraycopy(byteArrayValue, byteOffset, data, length, byteLength);
} }
length += len; length += byteLength;
return this; 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 * @param size number of additional bytes that this byte vector should be able to receive.
* number of additional bytes that this byte vector should be */
* able to receive.
*/
private void enlarge(final int size) { private void enlarge(final int size) {
int length1 = 2 * data.length; int doubleCapacity = 2 * data.length;
int length2 = length + size; int minimalCapacity = length + size;
byte[] newData = new byte[length1 > length2 ? length1 : length2]; byte[] newData = new byte[doubleCapacity > minimalCapacity ? doubleCapacity : minimalCapacity];
System.arraycopy(data, 0, newData, 0, length); System.arraycopy(data, 0, newData, 0, length);
data = newData; 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,122 +59,106 @@
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* A visitor to visit a Java class. The methods of this class must be called in * A visitor to visit a Java class. The methods of this class must be called in the following order:
* the following order: <tt>visit</tt> [ <tt>visitSource</tt> ] [ * {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* <tt>visitModule</tt> ][ <tt>visitOuterClass</tt> ] ( <tt>visitAnnotation</tt> | * visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
* <tt>visitTypeAnnotation</tt> | <tt>visitAttribute</tt> )* ( * visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
* <tt>visitInnerClass</tt> | <tt>visitField</tt> | <tt>visitMethod</tt> )* * {@code visitMethod} )* {@code visitEnd}.
* <tt>visitEnd</tt>.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public abstract class ClassVisitor { public abstract class ClassVisitor {
/** /**
* The ASM API version implemented by this visitor. The value of this field * The ASM API version implemented by this visitor. The value of this field must be one of {@link
* must be one of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
*/ */
protected final int api; protected final int api;
/** /** The class visitor to which this visitor must delegate method calls. May be null. */
* The class visitor to which this visitor must delegate method calls. May
* be null.
*/
protected ClassVisitor cv; protected ClassVisitor cv;
/** /**
* Constructs a new {@link ClassVisitor}. * Constructs a new {@link ClassVisitor}.
* *
* @param api * @param api the ASM API version implemented by this visitor. Must be one of {@link
* the ASM API version implemented by this visitor. Must be one * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */
*/
public ClassVisitor(final int api) { public ClassVisitor(final int api) {
this(api, null); this(api, null);
} }
/** /**
* Constructs a new {@link ClassVisitor}. * Constructs a new {@link ClassVisitor}.
* *
* @param api * @param api the ASM API version implemented by this visitor. Must be one of {@link
* the ASM API version implemented by this visitor. Must be one * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* @param cv * null.
* the class visitor to which this visitor must delegate method */
* calls. May be null. public ClassVisitor(final int api, final ClassVisitor classVisitor) {
*/ if (api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4 && api != Opcodes.ASM7) {
public ClassVisitor(final int api, final ClassVisitor cv) {
if (api < Opcodes.ASM4 || api > Opcodes.ASM6) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;
this.cv = cv; this.cv = classVisitor;
} }
/** /**
* Visits the header of the class. * Visits the header of the class.
* *
* @param version * @param version the class version. The minor version is stored in the 16 most significant bits,
* the class version. * and the major version in the 16 least significant bits.
* @param access * @param access the class's access flags (see {@link Opcodes}). This parameter also indicates if
* the class's access flags (see {@link Opcodes}). This parameter * the class is deprecated.
* also indicates if the class is deprecated. * @param name the internal name of the class (see {@link Type#getInternalName()}).
* @param name * @param signature the signature of this class. May be {@literal null} if the class is not a
* the internal name of the class (see * generic one, and does not extend or implement generic classes or interfaces.
* {@link Type#getInternalName() getInternalName}). * @param superName the internal of name of the super class (see {@link Type#getInternalName()}).
* @param signature * For interfaces, the super class is {@link Object}. May be {@literal null}, but only for the
* the signature of this class. May be <tt>null</tt> if the class * {@link Object} class.
* is not a generic one, and does not extend or implement generic * @param interfaces the internal names of the class's interfaces (see {@link
* classes or interfaces. * Type#getInternalName()}). May be {@literal null}.
* @param superName */
* the internal of name of the super class (see public void visit(
* {@link Type#getInternalName() getInternalName}). For final int version,
* interfaces, the super class is {@link Object}. May be final int access,
* <tt>null</tt>, but only for the {@link Object} class. final String name,
* @param interfaces final String signature,
* the internal names of the class's interfaces (see final String superName,
* {@link Type#getInternalName() getInternalName}). May be final String[] interfaces) {
* <tt>null</tt>.
*/
public void visit(int version, int access, String name, String signature,
String superName, String[] interfaces) {
if (cv != null) { if (cv != null) {
cv.visit(version, access, name, signature, superName, interfaces); cv.visit(version, access, name, signature, superName, interfaces);
} }
} }
/** /**
* Visits the source of the class. * Visits the source of the class.
* *
* @param source * @param source the name of the source file from which the class was compiled. May be {@literal
* the name of the source file from which the class was compiled. * null}.
* May be <tt>null</tt>. * @param debug additional debug information to compute the correspondence between source and
* @param debug * compiled elements of the class. May be {@literal null}.
* additional debug information to compute the correspondance */
* between source and compiled elements of the class. May be public void visitSource(final String source, final String debug) {
* <tt>null</tt>.
*/
public void visitSource(String source, String debug) {
if (cv != null) { if (cv != null) {
cv.visitSource(source, debug); cv.visitSource(source, debug);
} }
} }
/** /**
* Visit the module corresponding to the class. * Visit the module corresponding to the class.
* @param name *
* module name * @param name the fully qualified name (using dots) of the module.
* @param access * @param access the module access flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} and {@code
* module flags, among {@code ACC_OPEN}, {@code ACC_SYNTHETIC} * ACC_MANDATED}.
* and {@code ACC_MANDATED}. * @param version the module version, or {@literal null}.
* @param version * @return a visitor to visit the module values, or {@literal null} if this visitor is not
* module version or null. * interested in visiting this module.
* @return a visitor to visit the module values, or <tt>null</tt> if */
* this visitor is not interested in visiting this module. public ModuleVisitor visitModule(final String name, final int access, final String version) {
*/
public ModuleVisitor visitModule(String name, int access, String version) {
if (api < Opcodes.ASM6) { if (api < Opcodes.ASM6) {
throw new RuntimeException(); throw new UnsupportedOperationException("This feature requires ASM6");
} }
if (cv != null) { if (cv != null) {
return cv.visitModule(name, access, version); return cv.visitModule(name, access, version);
@ -183,186 +167,191 @@ public abstract class ClassVisitor {
} }
/** /**
* Visits the enclosing class of the class. This method must be called only * Visits the nest host class of the class. A nest is a set of classes of the same package that
* if the class has an enclosing class. * 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
* @param owner * called only once and only if the visited class is a non-host member of a nest. A class is
* internal name of the enclosing class of the class. * implicitly its own nest, so it's invalid to call this method with the visited class name as
* @param name * argument.
* the name of the method that contains the class, or *
* <tt>null</tt> if the class is not enclosed in a method of its * @param nestHost the internal name of the host class of the nest.
* enclosing class. */
* @param desc public void visitNestHost(final String nestHost) {
* the descriptor of the method that contains the class, or if (api < Opcodes.ASM7) {
* <tt>null</tt> if the class is not enclosed in a method of its throw new UnsupportedOperationException("This feature requires ASM7");
* enclosing class. }
*/
public void visitOuterClass(String owner, String name, String desc) {
if (cv != null) { if (cv != null) {
cv.visitOuterClass(owner, name, desc); cv.visitNestHost(nestHost);
} }
} }
/** /**
* Visits an annotation of the class. * Visits the enclosing class of the class. This method must be called only if the class has an
* * enclosing class.
* @param desc *
* the class descriptor of the annotation class. * @param owner internal name of the enclosing class of the class.
* @param visible * @param name the name of the method that contains the class, or {@literal null} if the class is
* <tt>true</tt> if the annotation is visible at runtime. * not enclosed in a method of its enclosing class.
* @return a visitor to visit the annotation values, or <tt>null</tt> if * @param descriptor the descriptor of the method that contains the class, or {@literal null} if
* this visitor is not interested in visiting this annotation. * the class is not enclosed in a method of its enclosing class.
*/ */
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public void visitOuterClass(final String owner, final String name, final String descriptor) {
if (cv != null) { if (cv != null) {
return cv.visitAnnotation(desc, visible); cv.visitOuterClass(owner, name, descriptor);
}
}
/**
* Visits an annotation of the class.
*
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (cv != null) {
return cv.visitAnnotation(descriptor, visible);
} }
return null; return null;
} }
/** /**
* Visits an annotation on a type in the class signature. * Visits an annotation on a type in the class signature.
* *
* @param typeRef * @param typeRef a reference to the annotated type. The sort of this type reference must be
* a reference to the annotated type. The sort of this type * {@link TypeReference#CLASS_TYPE_PARAMETER}, {@link
* reference must be {@link TypeReference#CLASS_TYPE_PARAMETER * TypeReference#CLASS_TYPE_PARAMETER_BOUND} or {@link TypeReference#CLASS_EXTENDS}. See
* CLASS_TYPE_PARAMETER}, * {@link TypeReference}.
* {@link TypeReference#CLASS_TYPE_PARAMETER_BOUND * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* CLASS_TYPE_PARAMETER_BOUND} or * static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* {@link TypeReference#CLASS_EXTENDS CLASS_EXTENDS}. See * 'typeRef' as a whole.
* {@link TypeReference}. * @param descriptor the class descriptor of the annotation class.
* @param typePath * @param visible {@literal true} if the annotation is visible at runtime.
* the path to the annotated type argument, wildcard bound, array * @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* element type, or static inner type within 'typeRef'. May be * interested in visiting this annotation.
* <tt>null</tt> if the annotation targets 'typeRef' as a whole. */
* @param desc public AnnotationVisitor visitTypeAnnotation(
* the class descriptor of the annotation class. final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
* @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.
*/
public AnnotationVisitor visitTypeAnnotation(int typeRef,
TypePath typePath, String desc, boolean visible) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5) {
throw new RuntimeException(); throw new UnsupportedOperationException("This feature requires ASM5");
} }
if (cv != null) { if (cv != null) {
return cv.visitTypeAnnotation(typeRef, typePath, desc, visible); return cv.visitTypeAnnotation(typeRef, typePath, descriptor, visible);
} }
return null; return null;
} }
/** /**
* Visits a non standard attribute of the class. * Visits a non standard attribute of the class.
* *
* @param attr * @param attribute an attribute.
* an attribute. */
*/ public void visitAttribute(final Attribute attribute) {
public void visitAttribute(Attribute attr) {
if (cv != null) { if (cv != null) {
cv.visitAttribute(attr); cv.visitAttribute(attribute);
} }
} }
/** /**
* Visits information about an inner class. This inner class is not * Visits a member of the nest. A nest is a set of classes of the same package that share access
* necessarily a member of the class being visited. * 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
* @param name * the visited class is the host of a nest. A nest host is implicitly a member of its own nest, so
* the internal name of an inner class (see * it's invalid to call this method with the visited class name as argument.
* {@link Type#getInternalName() getInternalName}). *
* @param outerName * @param nestMember the internal name of a nest member.
* the internal name of the class to which the inner class */
* belongs (see {@link Type#getInternalName() getInternalName}). public void visitNestMember(final String nestMember) {
* May be <tt>null</tt> for not member classes. if (api < Opcodes.ASM7) {
* @param innerName throw new UnsupportedOperationException("This feature requires ASM7");
* the (simple) name of the inner class inside its enclosing }
* class. May be <tt>null</tt> for anonymous inner classes. if (cv != null) {
* @param access cv.visitNestMember(nestMember);
* the access flags of the inner class as originally declared in }
* the enclosing class. }
*/
public void visitInnerClass(String name, String outerName, /**
String innerName, int access) { * 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) { if (cv != null) {
cv.visitInnerClass(name, outerName, innerName, access); cv.visitInnerClass(name, outerName, innerName, access);
} }
} }
/** /**
* Visits a field of the class. * Visits a field of the class.
* *
* @param access * @param access the field's access flags (see {@link Opcodes}). This parameter also indicates if
* the field's access flags (see {@link Opcodes}). This parameter * the field is synthetic and/or deprecated.
* also indicates if the field is synthetic and/or deprecated. * @param name the field's name.
* @param name * @param descriptor the field's descriptor (see {@link Type}).
* the field's name. * @param signature the field's signature. May be {@literal null} if the field's type does not use
* @param desc * generic types.
* the field's descriptor (see {@link Type Type}). * @param value the field's initial value. This parameter, which may be {@literal null} if the
* @param signature * field does not have an initial value, must be an {@link Integer}, a {@link Float}, a {@link
* the field's signature. May be <tt>null</tt> if the field's * Long}, a {@link Double} or a {@link String} (for {@code int}, {@code float}, {@code long}
* type does not use generic types. * or {@code String} fields respectively). <i>This parameter is only used for static
* @param value * fields</i>. Its value is ignored for non static fields, which must be initialized through
* the field's initial value. This parameter, which may be * bytecode instructions in constructors or methods.
* <tt>null</tt> if the field does not have an initial value, * @return a visitor to visit field annotations and attributes, or {@literal null} if this class
* must be an {@link Integer}, a {@link Float}, a {@link Long}, a * visitor is not interested in visiting these annotations and attributes.
* {@link Double} or a {@link String} (for <tt>int</tt>, */
* <tt>float</tt>, <tt>long</tt> or <tt>String</tt> fields public FieldVisitor visitField(
* respectively). <i>This parameter is only used for static final int access,
* fields</i>. Its value is ignored for non static fields, which final String name,
* must be initialized through bytecode instructions in final String descriptor,
* constructors or methods. final String signature,
* @return a visitor to visit field annotations and attributes, or final Object value) {
* <tt>null</tt> 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) {
if (cv != null) { if (cv != null) {
return cv.visitField(access, name, desc, signature, value); return cv.visitField(access, name, descriptor, signature, value);
} }
return null; return null;
} }
/** /**
* Visits a method of the class. This method <i>must</i> return a new * Visits a method of the class. This method <i>must</i> return a new {@link MethodVisitor}
* {@link MethodVisitor} instance (or <tt>null</tt>) each time it is called, * instance (or {@literal null}) each time it is called, i.e., it should not return a previously
* i.e., it should not return a previously returned visitor. * returned visitor.
* *
* @param access * @param access the method's access flags (see {@link Opcodes}). This parameter also indicates if
* the method's access flags (see {@link Opcodes}). This * the method is synthetic and/or deprecated.
* parameter also indicates if the method is synthetic and/or * @param name the method's name.
* deprecated. * @param descriptor the method's descriptor (see {@link Type}).
* @param name * @param signature the method's signature. May be {@literal null} if the method parameters,
* the method's name. * return type and exceptions do not use generic types.
* @param desc * @param exceptions the internal names of the method's exception classes (see {@link
* the method's descriptor (see {@link Type Type}). * Type#getInternalName()}). May be {@literal null}.
* @param signature * @return an object to visit the byte code of the method, or {@literal null} if this class
* the method's signature. May be <tt>null</tt> if the method * visitor is not interested in visiting the code of this method.
* parameters, return type and exceptions do not use generic */
* types. public MethodVisitor visitMethod(
* @param exceptions final int access,
* the internal names of the method's exception classes (see final String name,
* {@link Type#getInternalName() getInternalName}). May be final String descriptor,
* <tt>null</tt>. final String signature,
* @return an object to visit the byte code of the method, or <tt>null</tt> final String[] exceptions) {
* 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) {
if (cv != null) { if (cv != null) {
return cv.visitMethod(access, name, desc, signature, exceptions); return cv.visitMethod(access, name, descriptor, signature, exceptions);
} }
return null; return null;
} }
/** /**
* Visits the end of the class. This method, which is the last one to be * Visits the end of the class. This method, which is the last one to be called, is used to inform
* called, is used to inform the visitor that all the fields and methods of * the visitor that all the fields and methods of the class have been visited.
* the class have been visited. */
*/
public void visitEnd() { public void visitEnd() {
if (cv != null) { if (cv != null) {
cv.visitEnd(); cv.visitEnd();

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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
@ -64,111 +63,105 @@ package jdk.internal.org.objectweb.asm;
* *
* @author Eric Bruneton * @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
Attribute[] attrs; * {@link ClassReader#EXPAND_ASM_INSNS}.
*/
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
String desc; * variable types in this frame, minus the number of local variable types in the previous frame.
*/
int currentFrameLocalCountDelta;
/** /**
* The label objects, indexed by bytecode offset, of the method currently * The types of the local variables in the current stack map frame. Each type is represented with
* being parsed (only bytecode offsets for which a label is needed have a * a single array element (even long and double), using the format described in {@link
* non null associated Label object). * 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
TypePath typePath; * MethodVisitor#visitFrame}.
*/
/** Object[] currentFrameStackTypes;
* 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;
} }

View file

@ -56,30 +56,31 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* Information about the input stack map frame at the "current" instruction of a * Information about the input stack map frame at the "current" instruction of a method. This is
* method. This is implemented as a Frame subclass for a "basic block" * implemented as a Frame subclass for a "basic block" containing only one instruction.
* containing only one instruction.
* *
* @author Eric Bruneton * @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" * Sets this CurrentFrame to the input stack map frame of the next "current" instruction, i.e. the
* instruction, i.e. the instruction just after the given one. It is assumed * instruction just after the given one. It is assumed that the value of this object when this
* that the value of this object when this method is called is the stack map * method is called is the stack map frame status just before the given instruction is executed.
* frame status just before the given instruction is executed. */
*/
@Override @Override
void execute(int opcode, int arg, ClassWriter cw, Item item) { void execute(
super.execute(opcode, arg, cw, item); final int opcode, final int arg, final Symbol symbolArg, final SymbolTable symbolTable) {
Frame successor = new Frame(); super.execute(opcode, arg, symbolArg, symbolTable);
merge(cw, successor, 0); Frame successor = new Frame(null);
set(successor); merge(symbolTable, successor, 0);
owner.inputStackTop = 0; copyFrom(successor);
} }
} }

View file

@ -59,46 +59,64 @@
package jdk.internal.org.objectweb.asm; 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 * @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. * A control flow graph edge corresponding to an exception handler. Only used with {@link
* More precisely any {@link Edge} whose {@link #info} is strictly positive * ClassWriter#COMPUTE_MAXS}.
* 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.
*/
static final int EXCEPTION = 0x7FFFFFFF; static final int EXCEPTION = 0x7FFFFFFF;
/** /**
* Information about this control flow graph edge. If * Information about this control flow graph edge.
* {@link ClassWriter#COMPUTE_MAXS} is used this field is the (relative) *
* stack size in the basic block from which this edge originates. This size * <ul>
* is equal to the stack size at the "jump" instruction to which this edge * <li>If {@link ClassWriter#COMPUTE_MAXS} is used, this field contains either a stack size
* corresponds, relatively to the stack size at the beginning of the * delta (for an edge corresponding to a jump instruction), or the value EXCEPTION (for an
* originating basic block. If {@link ClassWriter#COMPUTE_FRAMES} is used, * edge corresponding to an exception handler). The stack size delta is the stack size just
* this field is the kind of this control flow graph edge (i.e. NORMAL or * after the jump instruction, minus the stack size at the beginning of the predecessor
* EXCEPTION). * 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
int info; * (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>
*/
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. * Constructs a new Edge.
* See {@link Label#successors successors}. *
*/ * @param info see {@link #info}.
Edge next; * @param successor see {@link #successor}.
* @param nextEdge see {@link #nextEdge}.
*/
Edge(final int info, final Label successor, final Edge nextEdge) {
this.info = info;
this.successor = successor;
this.nextEdge = nextEdge;
}
} }

View file

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

View file

@ -59,294 +59,319 @@
package jdk.internal.org.objectweb.asm; 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 * @author Eric Bruneton
*/ */
final class FieldWriter extends FieldVisitor { final class FieldWriter extends FieldVisitor {
/** /** Where the constants used in this FieldWriter must be stored. */
* The class writer to which this field must be added. private final SymbolTable symbolTable;
*/
private final ClassWriter cw; // 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
private final int access; * ClassFile structure.
*/
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 * The signature_index field of the Signature attribute of this field_info, or 0 if there is no
* method. * Signature attribute.
*/ */
private final int name; private int signatureIndex;
/** /**
* The index of the constant pool item that contains the descriptor of this * The constantvalue_index field of the ConstantValue attribute of this field_info, or 0 if there
* field. * is no ConstantValue attribute.
*/ */
private final int desc; private int constantValueIndex;
/** /**
* The index of the constant pool item that contains the signature of this * The last runtime visible annotation of this field. The previous ones can be accessed with the
* field. * {@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 * The last runtime invisible annotation of this field. The previous ones can be accessed with the
* this field. * {@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}.
private AnnotationWriter tanns; *
* <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 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 // Constructor
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
/** /**
* Constructs a new {@link FieldWriter}. * Constructs a new {@link FieldWriter}.
* *
* @param cw * @param symbolTable where the constants used in this FieldWriter must be stored.
* the class writer to which this field must be added. * @param access the field's access flags (see {@link Opcodes}).
* @param access * @param name the field's name.
* the field's access flags (see {@link Opcodes}). * @param descriptor the field's descriptor (see {@link Type}).
* @param name * @param signature the field's signature. May be {@literal null}.
* the field's name. * @param constantValue the field's constant value. May be {@literal null}.
* @param desc */
* the field's descriptor (see {@link Type}). FieldWriter(
* @param signature final SymbolTable symbolTable,
* the field's signature. May be <tt>null</tt>. final int access,
* @param value final String name,
* the field's constant value. May be <tt>null</tt>. final String descriptor,
*/ final String signature,
FieldWriter(final ClassWriter cw, final int access, final String name, final Object constantValue) {
final String desc, final String signature, final Object value) { super(Opcodes.ASM7);
super(Opcodes.ASM6); this.symbolTable = symbolTable;
if (cw.firstField == null) { this.accessFlags = access;
cw.firstField = this; this.nameIndex = symbolTable.addConstantUtf8(name);
} else { this.descriptorIndex = symbolTable.addConstantUtf8(descriptor);
cw.lastField.fv = this;
}
cw.lastField = this;
this.cw = cw;
this.access = access;
this.name = cw.newUTF8(name);
this.desc = cw.newUTF8(desc);
if (signature != null) { if (signature != null) {
this.signature = cw.newUTF8(signature); this.signatureIndex = symbolTable.addConstantUtf8(signature);
} }
if (value != null) { if (constantValue != null) {
this.value = cw.newConstItem(value).index; this.constantValueIndex = symbolTable.addConstant(constantValue).index;
} }
} }
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
// Implementation of the FieldVisitor abstract class // Implementation of the FieldVisitor abstract class
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
@Override @Override
public AnnotationVisitor visitAnnotation(final String desc, public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
final boolean visible) { // Create a ByteVector to hold an 'annotation' JVMS structure.
ByteVector bv = new ByteVector(); // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.16.
// write type, and reserve space for values count ByteVector annotation = new ByteVector();
bv.putShort(cw.newUTF8(desc)).putShort(0); // Write type_index and reserve space for num_element_value_pairs.
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, 2); annotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) { if (visible) {
aw.next = anns; return lastRuntimeVisibleAnnotation =
anns = aw; new AnnotationWriter(symbolTable, annotation, lastRuntimeVisibleAnnotation);
} else { } else {
aw.next = ianns; return lastRuntimeInvisibleAnnotation =
ianns = aw; new AnnotationWriter(symbolTable, annotation, lastRuntimeInvisibleAnnotation);
} }
return aw;
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(final int typeRef, public AnnotationVisitor visitTypeAnnotation(
final TypePath typePath, final String desc, final boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
ByteVector bv = new ByteVector(); // Create a ByteVector to hold a 'type_annotation' JVMS structure.
// write target_type and target_info // See https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.20.
AnnotationWriter.putTarget(typeRef, typePath, bv); ByteVector typeAnnotation = new ByteVector();
// write type, and reserve space for values count // Write target_type, target_info, and target_path.
bv.putShort(cw.newUTF8(desc)).putShort(0); TypeReference.putTarget(typeRef, typeAnnotation);
AnnotationWriter aw = new AnnotationWriter(cw, true, bv, bv, TypePath.put(typePath, typeAnnotation);
bv.length - 2); // Write type_index and reserve space for num_element_value_pairs.
typeAnnotation.putShort(symbolTable.addConstantUtf8(descriptor)).putShort(0);
if (visible) { if (visible) {
aw.next = tanns; return lastRuntimeVisibleTypeAnnotation =
tanns = aw; new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeVisibleTypeAnnotation);
} else { } else {
aw.next = itanns; return lastRuntimeInvisibleTypeAnnotation =
itanns = aw; new AnnotationWriter(symbolTable, typeAnnotation, lastRuntimeInvisibleTypeAnnotation);
} }
return aw;
} }
@Override @Override
public void visitAttribute(final Attribute attr) { public void visitAttribute(final Attribute attribute) {
attr.next = attrs; // Store the attributes in the <i>reverse</i> order of their visit by this method.
attrs = attr; attribute.nextAttribute = firstAttribute;
firstAttribute = attribute;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
// Nothing to do.
} }
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
// Utility methods // 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; int size = 8;
if (value != 0) { // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
cw.newUTF8("ConstantValue"); if (constantValueIndex != 0) {
// ConstantValue attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE);
size += 8; size += 8;
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { // Before Java 1.5, synthetic fields are represented with a Synthetic attribute.
if ((cw.version & 0xFFFF) < Opcodes.V1_5 if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) { && symbolTable.getMajorVersion() < Opcodes.V1_5) {
cw.newUTF8("Synthetic"); // Synthetic attributes always use 6 bytes.
size += 6; symbolTable.addConstantUtf8(Constants.SYNTHETIC);
}
}
if ((access & Opcodes.ACC_DEPRECATED) != 0) {
cw.newUTF8("Deprecated");
size += 6; size += 6;
} }
if (signature != 0) { if (signatureIndex != 0) {
cw.newUTF8("Signature"); // Signature attributes always use 8 bytes.
symbolTable.addConstantUtf8(Constants.SIGNATURE);
size += 8; size += 8;
} }
if (anns != null) { // ACC_DEPRECATED is ASM specific, the ClassFile format uses a Deprecated attribute instead.
cw.newUTF8("RuntimeVisibleAnnotations"); if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
size += 8 + anns.getSize(); // Deprecated attributes always use 6 bytes.
symbolTable.addConstantUtf8(Constants.DEPRECATED);
size += 6;
} }
if (ianns != null) { if (lastRuntimeVisibleAnnotation != null) {
cw.newUTF8("RuntimeInvisibleAnnotations"); size +=
size += 8 + ianns.getSize(); lastRuntimeVisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_ANNOTATIONS);
} }
if (tanns != null) { if (lastRuntimeInvisibleAnnotation != null) {
cw.newUTF8("RuntimeVisibleTypeAnnotations"); size +=
size += 8 + tanns.getSize(); lastRuntimeInvisibleAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_ANNOTATIONS);
} }
if (itanns != null) { if (lastRuntimeVisibleTypeAnnotation != null) {
cw.newUTF8("RuntimeInvisibleTypeAnnotations"); size +=
size += 8 + itanns.getSize(); lastRuntimeVisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS);
} }
if (attrs != null) { if (lastRuntimeInvisibleTypeAnnotation != null) {
size += attrs.getSize(cw, null, 0, -1, -1); size +=
lastRuntimeInvisibleTypeAnnotation.computeAnnotationsSize(
Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS);
}
if (firstAttribute != null) {
size += firstAttribute.computeAttributesSize(symbolTable);
} }
return size; 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) { void putFieldInfo(final ByteVector output) {
final int FACTOR = ClassWriter.TO_ACC_SYNTHETIC; boolean useSyntheticAttribute = symbolTable.getMajorVersion() < Opcodes.V1_5;
int mask = Opcodes.ACC_DEPRECATED | ClassWriter.ACC_SYNTHETIC_ATTRIBUTE // Put the access_flags, name_index and descriptor_index fields.
| ((access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) / FACTOR); int mask = useSyntheticAttribute ? Opcodes.ACC_SYNTHETIC : 0;
out.putShort(access & ~mask).putShort(name).putShort(desc); output.putShort(accessFlags & ~mask).putShort(nameIndex).putShort(descriptorIndex);
int attributeCount = 0; // Compute and put the attributes_count field.
if (value != 0) { // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
++attributeCount; int attributesCount = 0;
if (constantValueIndex != 0) {
++attributesCount;
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5 ++attributesCount;
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
++attributeCount;
}
} }
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if (signatureIndex != 0) {
++attributeCount; ++attributesCount;
} }
if (signature != 0) { if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
++attributeCount; ++attributesCount;
} }
if (anns != null) { if (lastRuntimeVisibleAnnotation != null) {
++attributeCount; ++attributesCount;
} }
if (ianns != null) { if (lastRuntimeInvisibleAnnotation != null) {
++attributeCount; ++attributesCount;
} }
if (tanns != null) { if (lastRuntimeVisibleTypeAnnotation != null) {
++attributeCount; ++attributesCount;
} }
if (itanns != null) { if (lastRuntimeInvisibleTypeAnnotation != null) {
++attributeCount; ++attributesCount;
} }
if (attrs != null) { if (firstAttribute != null) {
attributeCount += attrs.getCount(); attributesCount += firstAttribute.getAttributeCount();
} }
out.putShort(attributeCount); output.putShort(attributesCount);
if (value != 0) { // Put the field_info attributes.
out.putShort(cw.newUTF8("ConstantValue")); // For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
out.putInt(2).putShort(value); if (constantValueIndex != 0) {
output
.putShort(symbolTable.addConstantUtf8(Constants.CONSTANT_VALUE))
.putInt(2)
.putShort(constantValueIndex);
} }
if ((access & Opcodes.ACC_SYNTHETIC) != 0) { if ((accessFlags & Opcodes.ACC_SYNTHETIC) != 0 && useSyntheticAttribute) {
if ((cw.version & 0xFFFF) < Opcodes.V1_5 output.putShort(symbolTable.addConstantUtf8(Constants.SYNTHETIC)).putInt(0);
|| (access & ClassWriter.ACC_SYNTHETIC_ATTRIBUTE) != 0) {
out.putShort(cw.newUTF8("Synthetic")).putInt(0);
}
} }
if ((access & Opcodes.ACC_DEPRECATED) != 0) { if (signatureIndex != 0) {
out.putShort(cw.newUTF8("Deprecated")).putInt(0); output
.putShort(symbolTable.addConstantUtf8(Constants.SIGNATURE))
.putInt(2)
.putShort(signatureIndex);
} }
if (signature != 0) { if ((accessFlags & Opcodes.ACC_DEPRECATED) != 0) {
out.putShort(cw.newUTF8("Signature")); output.putShort(symbolTable.addConstantUtf8(Constants.DEPRECATED)).putInt(0);
out.putInt(2).putShort(signature);
} }
if (anns != null) { if (lastRuntimeVisibleAnnotation != null) {
out.putShort(cw.newUTF8("RuntimeVisibleAnnotations")); lastRuntimeVisibleAnnotation.putAnnotations(
anns.put(out); symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_ANNOTATIONS), output);
} }
if (ianns != null) { if (lastRuntimeInvisibleAnnotation != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleAnnotations")); lastRuntimeInvisibleAnnotation.putAnnotations(
ianns.put(out); symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_ANNOTATIONS), output);
} }
if (tanns != null) { if (lastRuntimeVisibleTypeAnnotation != null) {
out.putShort(cw.newUTF8("RuntimeVisibleTypeAnnotations")); lastRuntimeVisibleTypeAnnotation.putAnnotations(
tanns.put(out); symbolTable.addConstantUtf8(Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS), output);
} }
if (itanns != null) { if (lastRuntimeInvisibleTypeAnnotation != null) {
out.putShort(cw.newUTF8("RuntimeInvisibleTypeAnnotations")); lastRuntimeInvisibleTypeAnnotation.putAnnotations(
itanns.put(out); symbolTable.addConstantUtf8(Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS), output);
} }
if (attrs != null) { if (firstAttribute != null) {
attrs.put(cw, null, 0, -1, -1, out); firstAttribute.putAttributes(symbolTable, output);
} }
} }
/**
* 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
@ -68,184 +67,153 @@ package jdk.internal.org.objectweb.asm;
public final class Handle { public final class Handle {
/** /**
* The kind of field or method designated by this Handle. Should be * The kind of field or method designated by this Handle. Should be {@link Opcodes#H_GETFIELD},
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, * {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, {@link
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, * Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, * {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or */
* {@link Opcodes#H_INVOKEINTERFACE}. private final int tag;
*/
final int tag; /** 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. */
private final String name;
/** The descriptor of the field or method designated by this handle. */
private final String descriptor;
/** Whether the owner is an interface or not. */
private final boolean isInterface;
/** /**
* The internal name of the class that owns the field or method designated * Constructs a new field or method handle.
* by this handle. *
*/ * @param tag the kind of field or method designated by this Handle. Must be {@link
final String owner; * 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
* The name of the field or method designated by this handle. * Opcodes#H_INVOKEINTERFACE}.
*/ * @param owner the internal name of the class that owns the field or method designated by this
final String name; * handle.
* @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.
* 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)}.
final String desc; */
/**
* Indicate if the owner is an interface or not.
*/
final boolean itf;
/**
* 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
* handle.
*
* @deprecated this constructor has been superseded
* by {@link #Handle(int, String, String, String, boolean)}.
*/
@Deprecated @Deprecated
public Handle(int tag, String owner, String name, String desc) { public Handle(final int tag, final String owner, final String name, final String descriptor) {
this(tag, owner, name, desc, tag == Opcodes.H_INVOKEINTERFACE); this(tag, owner, name, descriptor, tag == Opcodes.H_INVOKEINTERFACE);
} }
/** /**
* Constructs a new field or method handle. * Constructs a new field or method handle.
* *
* @param tag * @param tag the kind of field or method designated by this Handle. Must be {@link
* the kind of field or method designated by this Handle. Must be * Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD}, {@link
* {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, * Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, * {@link Opcodes#H_INVOKESPECIAL}, {@link Opcodes#H_NEWINVOKESPECIAL} or {@link
* {@link Opcodes#H_INVOKEVIRTUAL}, * Opcodes#H_INVOKEINTERFACE}.
* {@link Opcodes#H_INVOKESTATIC}, * @param owner the internal name of the class that owns the field or method designated by this
* {@link Opcodes#H_INVOKESPECIAL}, * handle.
* {@link Opcodes#H_NEWINVOKESPECIAL} or * @param name the name of the field or method designated by this handle.
* {@link Opcodes#H_INVOKEINTERFACE}. * @param descriptor the descriptor of the field or method designated by this handle.
* @param owner * @param isInterface whether the owner is an interface or not.
* the internal name of the class that owns the field or method */
* designated by this handle. public Handle(
* @param name final int tag,
* the name of the field or method designated by this handle. final String owner,
* @param desc final String name,
* the descriptor of the field or method designated by this final String descriptor,
* handle. final boolean isInterface) {
* @param itf
* true if the owner is an interface.
*/
public Handle(int tag, String owner, String name, String desc, boolean itf) {
this.tag = tag; this.tag = tag;
this.owner = owner; this.owner = owner;
this.name = name; this.name = name;
this.desc = desc; this.descriptor = descriptor;
this.itf = itf; this.isInterface = isInterface;
} }
/** /**
* Returns the kind of field or method designated by this handle. * Returns the kind of field or method designated by this handle.
* *
* @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, * @return {@link Opcodes#H_GETFIELD}, {@link Opcodes#H_GETSTATIC}, {@link Opcodes#H_PUTFIELD},
* {@link Opcodes#H_PUTFIELD}, {@link Opcodes#H_PUTSTATIC}, * {@link Opcodes#H_PUTSTATIC}, {@link Opcodes#H_INVOKEVIRTUAL}, {@link
* {@link Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, * Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL}, {@link
* {@link Opcodes#H_INVOKESPECIAL}, * Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
* {@link Opcodes#H_NEWINVOKESPECIAL} or */
* {@link Opcodes#H_INVOKEINTERFACE}.
*/
public int getTag() { public int getTag() {
return tag; return tag;
} }
/** /**
* Returns the internal name of the class that owns the field or method * Returns the internal name of the class that owns the field or method designated by this handle.
* 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() { public String getOwner() {
return owner; return owner;
} }
/** /**
* Returns the name of the field or method designated by this handle. * Returns the name of the field or method designated by this handle.
* *
* @return the name of the field or method designated by this handle. * @return the name of the field or method designated by this handle.
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* Returns the descriptor of the field or method designated by this handle. * Returns the descriptor of the field or method designated by this handle.
* *
* @return the descriptor of the field or method designated by this handle. * @return the descriptor of the field or method designated by this handle.
*/ */
public String getDesc() { public String getDesc() {
return desc; return descriptor;
} }
/** /**
* Returns true if the owner of the field or method designated * Returns true if the owner of the field or method designated by this handle is an interface.
* 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() { public boolean isInterface() {
return itf; return isInterface;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(final Object object) {
if (obj == this) { if (object == this) {
return true; return true;
} }
if (!(obj instanceof Handle)) { if (!(object instanceof Handle)) {
return false; return false;
} }
Handle h = (Handle) obj; Handle handle = (Handle) object;
return tag == h.tag && itf == h.itf && owner.equals(h.owner) return tag == handle.tag
&& name.equals(h.name) && desc.equals(h.desc); && isInterface == handle.isInterface
&& owner.equals(handle.owner)
&& name.equals(handle.name)
&& descriptor.equals(handle.descriptor);
} }
@Override @Override
public int hashCode() { 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 * Returns the textual representation of this handle. The textual representation is:
* representation is: *
* * <ul>
* <pre> * <li>for a reference to a class: owner "." name descriptor " (" tag ")",
* for a reference to a class: * <li>for a reference to an interface: owner "." name descriptor " (" tag " itf)".
* owner '.' name desc ' ' '(' tag ')' * </ul>
* for a reference to an interface: */
* owner '.' name desc ' ' '(' tag ' ' itf ')'
* </pre>
*
* . As this format is unambiguous, it can be parsed if necessary.
*/
@Override @Override
public String toString() { 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; 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 * @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 * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the
* <tt>null</tt> to catch any exceptions. * 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 * The internal name of the type of exceptions handled by this handler, or {@literal null} to
* handled by this handler, or 0 to catch any exceptions. * catch any exceptions.
*/ */
int type; final String catchTypeDescriptor;
/** The next exception handler. */
Handler nextHandler;
/** /**
* Next exception handler block info. * Constructs a new Handler.
*/ *
Handler next; * @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;
}
/** /**
* Removes the range between start and end from the given exception * Constructs a new Handler from the given one, with a different scope.
* handlers. *
* * @param handler an existing Handler.
* @param h * @param startPc the start_pc field of this JVMS exception_table entry.
* an exception handler list. * @param endPc the end_pc field of this JVMS exception_table entry.
* @param start */
* the start of the range to be removed. Handler(final Handler handler, final Label startPc, final Label endPc) {
* @param end this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor);
* the end of the range to be removed. Maybe null. this.nextHandler = handler.nextHandler;
* @return the exception handler list with the start-end range removed. }
*/
static Handler remove(Handler h, Label start, Label end) { /**
if (h == null) { * 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 removeRange(final Handler firstHandler, final Label start, final Label end) {
if (firstHandler == null) {
return null; return null;
} else { } else {
h.next = remove(h.next, start, end); firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end);
} }
int hstart = h.start.position; int handlerStart = firstHandler.startPc.bytecodeOffset;
int hend = h.end.position; int handlerEnd = firstHandler.endPc.bytecodeOffset;
int s = start.position; int rangeStart = start.bytecodeOffset;
int e = end == null ? Integer.MAX_VALUE : end.position; int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset;
// if [hstart,hend[ and [s,e[ intervals intersect... // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect.
if (s < hend && e > hstart) { if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) {
if (s <= hstart) { return firstHandler;
if (e >= hend) { }
// [hstart,hend[ fully included in [s,e[, h removed if (rangeStart <= handlerStart) {
h = h.next; if (rangeEnd >= handlerEnd) {
} else { // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler.
// [hstart,hend[ minus [s,e[ = [e,hend[ return firstHandler.nextHandler;
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else { } else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[ // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[
Handler g = new Handler(); return new Handler(firstHandler, end, firstHandler.endPc);
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;
} }
} else if (rangeEnd >= handlerEnd) {
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[
return new Handler(firstHandler, firstHandler.startPc, start);
} else {
// [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ =
// [handlerStart,rangeStart[ + [rangeEnd,handerEnd[
firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc);
return new Handler(firstHandler, firstHandler.startPc, start);
}
}
/**
* 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;
} }
return h;
} }
} }

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

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

View file

@ -56,267 +56,229 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; 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 Remi Forax
* @author Eric Bruneton
*/ */
final class ModuleWriter extends ModuleVisitor { final class ModuleWriter extends ModuleVisitor {
/**
* The class writer to which this Module attribute must be added.
*/
private final ClassWriter cw;
/** /** Where the constants used in this AnnotationWriter must be stored. */
* size in byte of the Module attribute. private final SymbolTable symbolTable;
*/
int size;
/** /** The module_name_index field of the JVMS Module attribute. */
* Number of attributes associated with the current module private final int moduleNameIndex;
* (Version, ConcealPackages, etc)
*/
int attributeCount;
/** /** The module_flags field of the JVMS Module attribute. */
* Size in bytes of the attributes associated with the current module private final int moduleFlags;
*/
int attributesSize;
/** /** The module_version_index field of the JVMS Module attribute. */
* module name index in the constant pool private final int moduleVersionIndex;
*/
private final int name;
/** /** The requires_count field of the JVMS Module attribute. */
* module access flags private int requiresCount;
*/
private final int access;
/** /** The binary content of the 'requires' array of the JVMS Module attribute. */
* module version index in the constant pool or 0 private final ByteVector requires;
*/
private final int version;
/** /** The exports_count field of the JVMS Module attribute. */
* module main class index in the constant pool or 0 private int exportsCount;
*/
private int mainClass;
/** /** The binary content of the 'exports' array of the JVMS Module attribute. */
* number of packages 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; private int packageCount;
/** /** The binary content of the 'package_index' array of the JVMS ModulePackages attribute. */
* The packages in bytecode form. This byte vector only contains private final ByteVector packageIndex;
* the items themselves, the number of items is store in packageCount
*/
private ByteVector packages;
/** /** The main_class_index field of the JVMS ModuleMainClass attribute, or 0. */
* number of requires items private int mainClassIndex;
*/
private int requireCount;
/** ModuleWriter(final SymbolTable symbolTable, final int name, final int access, final int version) {
* The requires items in bytecode form. This byte vector only contains super(Opcodes.ASM7);
* the items themselves, the number of items is store in requireCount this.symbolTable = symbolTable;
*/ this.moduleNameIndex = name;
private ByteVector requires; this.moduleFlags = access;
this.moduleVersionIndex = version;
/** this.requires = new ByteVector();
* number of exports items this.exports = new ByteVector();
*/ this.opens = new ByteVector();
private int exportCount; this.usesIndex = new ByteVector();
this.provides = new ByteVector();
/** this.packageIndex = new ByteVector();
* 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;
} }
@Override @Override
public void visitMainClass(String mainClass) { public void visitMainClass(final String mainClass) {
if (this.mainClass == 0) { // protect against several calls to visitMainClass this.mainClassIndex = symbolTable.addConstantClass(mainClass).index;
cw.newUTF8("ModuleMainClass");
attributeCount++;
attributesSize += 8;
}
this.mainClass = cw.newClass(mainClass);
} }
@Override @Override
public void visitPackage(String packaze) { public void visitPackage(final String packaze) {
if (packages == null) { packageIndex.putShort(symbolTable.addConstantPackage(packaze).index);
// protect against several calls to visitPackage
cw.newUTF8("ModulePackages");
packages = new ByteVector();
attributeCount++;
attributesSize += 8;
}
packages.putShort(cw.newPackage(packaze));
packageCount++; packageCount++;
attributesSize += 2;
} }
@Override @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
requires = new ByteVector(); .putShort(symbolTable.addConstantModule(module).index)
}
requires.putShort(cw.newModule(module))
.putShort(access) .putShort(access)
.putShort(version == null? 0: cw.newUTF8(version)); .putShort(version == null ? 0 : symbolTable.addConstantUtf8(version));
requireCount++; requiresCount++;
size += 6;
} }
@Override @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.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
exports = new ByteVector();
}
exports.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) { if (modules == null) {
exports.putShort(0); exports.putShort(0);
size += 6;
} else { } else {
exports.putShort(modules.length); exports.putShort(modules.length);
for(String module: modules) { for (String module : modules) {
exports.putShort(cw.newModule(module)); exports.putShort(symbolTable.addConstantModule(module).index);
} }
size += 6 + 2 * modules.length;
} }
exportCount++; exportsCount++;
} }
@Override @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.putShort(symbolTable.addConstantPackage(packaze).index).putShort(access);
opens = new ByteVector();
}
opens.putShort(cw.newPackage(packaze)).putShort(access);
if (modules == null) { if (modules == null) {
opens.putShort(0); opens.putShort(0);
size += 6;
} else { } else {
opens.putShort(modules.length); opens.putShort(modules.length);
for(String module: modules) { for (String module : modules) {
opens.putShort(cw.newModule(module)); opens.putShort(symbolTable.addConstantModule(module).index);
} }
size += 6 + 2 * modules.length;
} }
openCount++; opensCount++;
} }
@Override @Override
public void visitUse(String service) { public void visitUse(final String service) {
if (uses == null) { usesIndex.putShort(symbolTable.addConstantClass(service).index);
uses = new ByteVector(); usesCount++;
}
uses.putShort(cw.newClass(service));
useCount++;
size += 2;
} }
@Override @Override
public void visitProvide(String service, String... providers) { public void visitProvide(final String service, final String... providers) {
if (provides == null) { provides.putShort(symbolTable.addConstantClass(service).index);
provides = new ByteVector();
}
provides.putShort(cw.newClass(service));
provides.putShort(providers.length); provides.putShort(providers.length);
for(String provider: providers) { for (String provider : providers) {
provides.putShort(cw.newClass(provider)); provides.putShort(symbolTable.addConstantClass(provider).index);
} }
provideCount++; providesCount++;
size += 4 + 2 * providers.length;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
// empty // Nothing to do.
} }
void putAttributes(ByteVector out) { /**
if (mainClass != 0) { * Returns the number of Module, ModulePackages and ModuleMainClass attributes generated by this
out.putShort(cw.newUTF8("ModuleMainClass")).putInt(2).putShort(mainClass); * ModuleWriter.
} *
if (packages != null) { * @return the number of Module, ModulePackages and ModuleMainClass attributes (between 1 and 3).
out.putShort(cw.newUTF8("ModulePackages")) */
.putInt(2 + 2 * packageCount) int getAttributeCount() {
.putShort(packageCount) return 1 + (packageCount > 0 ? 1 : 0) + (mainClassIndex > 0 ? 1 : 0);
.putByteArray(packages.data, 0, packages.length);
}
} }
void put(ByteVector out) { /**
out.putInt(size); * Returns the size of the Module, ModulePackages and ModuleMainClass attributes generated by this
out.putShort(name).putShort(access).putShort(version); * ModuleWriter. Also add the names of these attributes in the constant pool.
out.putShort(requireCount); *
if (requires != null) { * @return the size in bytes of the Module, ModulePackages and ModuleMainClass attributes.
out.putByteArray(requires.data, 0, requires.length); */
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;
} }
out.putShort(exportCount); if (mainClassIndex > 0) {
if (exports != null) { symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS);
out.putByteArray(exports.data, 0, exports.length); // 6 attribute header bytes, and 2 bytes for main_class_index.
size += 8;
} }
out.putShort(openCount); return size;
if (opens != null) { }
out.putByteArray(opens.data, 0, opens.length);
/**
* 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(packageIndex.data, 0, packageIndex.length);
} }
out.putShort(useCount); if (mainClassIndex > 0) {
if (uses != null) { output
out.putByteArray(uses.data, 0, uses.length); .putShort(symbolTable.addConstantUtf8(Constants.MODULE_MAIN_CLASS))
} .putInt(2)
out.putShort(provideCount); .putShort(mainClassIndex);
if (provides != null) {
out.putByteArray(provides.data, 0, provides.length);
} }
} }
} }

View file

@ -59,26 +59,29 @@
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* Defines the JVM opcodes, access flags and array type codes. This interface * The JVM opcodes, access flags and array type codes. This interface does not define all the JVM
* does not define all the JVM opcodes because some opcodes are automatically * opcodes because some opcodes are automatically handled. For example, the xLOAD and xSTORE opcodes
* handled. For example, the xLOAD and xSTORE opcodes are automatically replaced * are automatically replaced by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and
* by xLOAD_n and xSTORE_n opcodes when possible. The xLOAD_n and xSTORE_n * xSTORE_n opcodes are therefore not defined in this interface. Likewise for LDC, automatically
* opcodes are therefore not defined in this interface. Likewise for LDC, * replaced by LDC_W or LDC2_W when necessary, WIDE, GOTO_W and JSR_W.
* 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 Eric Bruneton
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
// DontCheck(InterfaceIsType): can't be fixed (for backward binary compatibility).
public interface Opcodes { public interface Opcodes {
// ASM API versions // ASM API versions.
int ASM4 = 4 << 16 | 0 << 8 | 0; int ASM4 = 4 << 16 | 0 << 8;
int ASM5 = 5 << 16 | 0 << 8 | 0; int ASM5 = 5 << 16 | 0 << 8;
int ASM6 = 6 << 16 | 0 << 8 | 0; 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_1 = 3 << 16 | 45;
int V1_2 = 0 << 16 | 46; int V1_2 = 0 << 16 | 46;
@ -93,7 +96,19 @@ public interface Opcodes {
int V11 = 0 << 16 | 55; int V11 = 0 << 16 | 55;
int V12 = 0 << 16 | 56; 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_PUBLIC = 0x0001; // class, field, method
int ACC_PRIVATE = 0x0002; // 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_MANDATED = 0x8000; // parameter, module, module *
int ACC_MODULE = 0x8000; // class int ACC_MODULE = 0x8000; // class
// ASM specific access flags.
// ASM specific pseudo 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 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_BOOLEAN = 4;
int T_CHAR = 5; int T_CHAR = 5;
@ -135,7 +153,8 @@ public interface Opcodes {
int T_INT = 10; int T_INT = 10;
int T_LONG = 11; 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_GETFIELD = 1;
int H_GETSTATIC = 2; int H_GETSTATIC = 2;
@ -147,57 +166,50 @@ public interface Opcodes {
int H_NEWINVOKESPECIAL = 8; int H_NEWINVOKESPECIAL = 8;
int H_INVOKEINTERFACE = 9; int H_INVOKEINTERFACE = 9;
// stack map frame types // ASM specific stack map frame types, used in {@link ClassVisitor#visitFrame}.
/** /** An expanded frame. See {@link ClassReader#EXPAND_FRAMES}. */
* Represents an expanded frame. See {@link ClassReader#EXPAND_FRAMES}.
*/
int F_NEW = -1; int F_NEW = -1;
/** /** A compressed frame with complete frame data. */
* Represents a compressed frame with complete frame data.
*/
int F_FULL = 0; int F_FULL = 0;
/** /**
* Represents a compressed frame where locals are the same as the locals in * A compressed frame where locals are the same as the locals in the previous frame, except that
* the previous frame, except that additional 1-3 locals are defined, and * additional 1-3 locals are defined, and with an empty stack.
* with an empty stack. */
*/
int F_APPEND = 1; int F_APPEND = 1;
/** /**
* Represents a compressed frame where locals are the same as the locals in * A compressed frame where locals are the same as the locals in the previous frame, except that
* the previous frame, except that the last 1-3 locals are absent and with * the last 1-3 locals are absent and with an empty stack.
* an empty stack. */
*/
int F_CHOP = 2; int F_CHOP = 2;
/** /**
* Represents a compressed frame with exactly the same locals as the * A compressed frame with exactly the same locals as the previous frame and with an empty stack.
* previous frame and with an empty stack. */
*/
int F_SAME = 3; int F_SAME = 3;
/** /**
* Represents a compressed frame with exactly the same locals as the * A compressed frame with exactly the same locals as the previous frame and with a single value
* previous frame and with a single value on the stack. * on the stack.
*/ */
int F_SAME1 = 4; int F_SAME1 = 4;
// Do not try to change the following code to use auto-boxing, // Standard stack map frame element types, used in {@link ClassVisitor#visitFrame}.
// 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);
// 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 NOP = 0; // visitInsn
int ACONST_NULL = 1; // - int ACONST_NULL = 1; // -
@ -218,33 +230,11 @@ public interface Opcodes {
int BIPUSH = 16; // visitIntInsn int BIPUSH = 16; // visitIntInsn
int SIPUSH = 17; // - int SIPUSH = 17; // -
int LDC = 18; // visitLdcInsn int LDC = 18; // visitLdcInsn
// int LDC_W = 19; // -
// int LDC2_W = 20; // -
int ILOAD = 21; // visitVarInsn int ILOAD = 21; // visitVarInsn
int LLOAD = 22; // - int LLOAD = 22; // -
int FLOAD = 23; // - int FLOAD = 23; // -
int DLOAD = 24; // - int DLOAD = 24; // -
int ALOAD = 25; // - 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 IALOAD = 46; // visitInsn
int LALOAD = 47; // - int LALOAD = 47; // -
int FALOAD = 48; // - int FALOAD = 48; // -
@ -258,26 +248,6 @@ public interface Opcodes {
int FSTORE = 56; // - int FSTORE = 56; // -
int DSTORE = 57; // - int DSTORE = 57; // -
int ASTORE = 58; // - 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 IASTORE = 79; // visitInsn
int LASTORE = 80; // - int LASTORE = 80; // -
int FASTORE = 81; // - int FASTORE = 81; // -
@ -395,10 +365,7 @@ public interface Opcodes {
int INSTANCEOF = 193; // - int INSTANCEOF = 193; // -
int MONITORENTER = 194; // visitInsn int MONITORENTER = 194; // visitInsn
int MONITOREXIT = 195; // - int MONITOREXIT = 195; // -
// int WIDE = 196; // NOT VISITED
int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn int MULTIANEWARRAY = 197; // visitMultiANewArrayInsn
int IFNULL = 198; // visitJumpInsn int IFNULL = 198; // visitJumpInsn
int IFNONNULL = 199; // - 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: * file:
* *
* ASM: a very small and fast Java bytecode manipulation framework * 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -56,170 +56,176 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* The path to a type argument, wildcard bound, array element type, or static * The path to a type argument, wildcard bound, array element type, or static inner type within an
* inner type within an enclosing type. * enclosing type.
* *
* @author Eric Bruneton * @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 * The byte array where the 'type_path' structure - as defined in the Java Virtual Machine
* {@link #getStep getStep}. * Specification (JVMS) - corresponding to this TypePath is stored. The first byte of the
*/ * structure in this array is given by {@link #typePathOffset}.
public final static int ARRAY_ELEMENT = 0; *
* @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>
*/
private final byte[] typePathContainer;
/** The offset of the first byte of the type_path JVMS structure in {@link #typePathContainer}. */
private final int typePathOffset;
/** /**
* A type path step that steps into the nested type of a class type. See * Constructs a new TypePath.
* {@link #getStep getStep}. *
*/ * @param typePathContainer a byte array containing a type_path JVMS structure.
public final static int INNER_TYPE = 1; * @param typePathOffset the offset of the first byte of the type_path structure in
* typePathContainer.
/** */
* A type path step that steps into the bound of a wildcard type. See TypePath(final byte[] typePathContainer, final int typePathOffset) {
* {@link #getStep getStep}. this.typePathContainer = typePathContainer;
*/ this.typePathOffset = typePathOffset;
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.
*
* @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'.
*/
TypePath(byte[] b, int offset) {
this.b = b;
this.offset = offset;
} }
/** /**
* Returns the length of this path. * Returns the length of this path, i.e. its number of steps.
* *
* @return the length of this path. * @return the length of this path.
*/ */
public int getLength() { 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. * Returns the value of the given step of this path.
* *
* @param index * @param index an index between 0 and {@link #getLength()}, exclusive.
* an index between 0 and {@link #getLength()}, exclusive. * @return one of {@link #ARRAY_ELEMENT}, {@link #INNER_TYPE}, {@link #WILDCARD_BOUND}, or {@link
* @return {@link #ARRAY_ELEMENT ARRAY_ELEMENT}, {@link #INNER_TYPE * #TYPE_ARGUMENT}.
* INNER_TYPE}, {@link #WILDCARD_BOUND WILDCARD_BOUND}, or */
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. public int getStep(final int index) {
*/ // Returns the type_path_kind of the path element of the given index.
public int getStep(int index) { return typePathContainer[typePathOffset + 2 * index + 1];
return b[offset + 2 * index + 1];
} }
/** /**
* Returns the index of the type argument that the given step is stepping * Returns the index of the type argument that the given step is stepping into. This method should
* into. This method should only be used for steps whose value is * only be used for steps whose value is {@link #TYPE_ARGUMENT}.
* {@link #TYPE_ARGUMENT TYPE_ARGUMENT}. *
* * @param index an index between 0 and {@link #getLength()}, exclusive.
* @param index * @return the index of the type argument that the given step is stepping into.
* an index between 0 and {@link #getLength()}, exclusive. */
* @return the index of the type argument that the given step is stepping public int getStepArgument(final int index) {
* into. // Returns the type_argument_index of the path element of the given index.
*/ return typePathContainer[typePathOffset + 2 * index + 2];
public int getStepArgument(int index) {
return b[offset + 2 * index + 2];
} }
/** /**
* Converts a type path in string form, in the format used by * Converts a type path in string form, in the format used by {@link #toString()}, into a TypePath
* {@link #toString()}, into a TypePath object. * object.
* *
* @param typePath * @param typePath a type path in string form, in the format used by {@link #toString()}. May be
* a type path in string form, in the format used by * {@literal null} or empty.
* {@link #toString()}. May be null or empty. * @return the corresponding TypePath object, or {@literal null} if the path is empty.
* @return the corresponding TypePath object, or null if the path is empty. */
*/
public static TypePath fromString(final String typePath) { public static TypePath fromString(final String typePath) {
if (typePath == null || typePath.length() == 0) { if (typePath == null || typePath.length() == 0) {
return null; return null;
} }
int n = typePath.length(); int typePathLength = typePath.length();
ByteVector out = new ByteVector(n); ByteVector output = new ByteVector(typePathLength);
out.putByte(0); output.putByte(0);
for (int i = 0; i < n;) { int typePathIndex = 0;
char c = typePath.charAt(i++); while (typePathIndex < typePathLength) {
char c = typePath.charAt(typePathIndex++);
if (c == '[') { if (c == '[') {
out.put11(ARRAY_ELEMENT, 0); output.put11(ARRAY_ELEMENT, 0);
} else if (c == '.') { } else if (c == '.') {
out.put11(INNER_TYPE, 0); output.put11(INNER_TYPE, 0);
} else if (c == '*') { } else if (c == '*') {
out.put11(WILDCARD_BOUND, 0); output.put11(WILDCARD_BOUND, 0);
} else if (c >= '0' && c <= '9') { } else if (c >= '0' && c <= '9') {
int typeArg = c - '0'; int typeArg = c - '0';
while (i < n && (c = typePath.charAt(i)) >= '0' && c <= '9') { while (typePathIndex < typePathLength) {
typeArg = typeArg * 10 + c - '0'; c = typePath.charAt(typePathIndex++);
i += 1; if (c >= '0' && c <= '9') {
typeArg = typeArg * 10 + c - '0';
} else if (c == ';') {
break;
} else {
throw new IllegalArgumentException();
}
} }
if (i < n && typePath.charAt(i) == ';') { output.put11(TYPE_ARGUMENT, typeArg);
i += 1; } else {
} throw new IllegalArgumentException();
out.put11(TYPE_ARGUMENT, typeArg);
} }
} }
out.data[0] = (byte) (out.length / 2); output.data[0] = (byte) (output.length / 2);
return new TypePath(out.data, 0); return new TypePath(output.data, 0);
} }
/** /**
* Returns a string representation of this type path. {@link #ARRAY_ELEMENT * Returns a string representation of this type path. {@link #ARRAY_ELEMENT} steps are represented
* ARRAY_ELEMENT} steps are represented with '[', {@link #INNER_TYPE * with '[', {@link #INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND} steps with '*' and {@link
* INNER_TYPE} steps with '.', {@link #WILDCARD_BOUND WILDCARD_BOUND} steps * #TYPE_ARGUMENT} steps with their type argument index in decimal form followed by ';'.
* with '*' and {@link #TYPE_ARGUMENT TYPE_ARGUMENT} steps with their type */
* argument index in decimal form followed by ';'.
*/
@Override @Override
public String toString() { public String toString() {
int length = getLength(); int length = getLength();
StringBuilder result = new StringBuilder(length * 2); StringBuilder result = new StringBuilder(length * 2);
for (int i = 0; i < length; ++i) { for (int i = 0; i < length; ++i) {
switch (getStep(i)) { switch (getStep(i)) {
case ARRAY_ELEMENT: case ARRAY_ELEMENT:
result.append('['); result.append('[');
break; break;
case INNER_TYPE: case INNER_TYPE:
result.append('.'); result.append('.');
break; break;
case WILDCARD_BOUND: case WILDCARD_BOUND:
result.append('*'); result.append('*');
break; break;
case TYPE_ARGUMENT: case TYPE_ARGUMENT:
result.append(getStepArgument(i)).append(';'); result.append(getStepArgument(i)).append(';');
break; break;
default: default:
result.append('_'); throw new AssertionError();
} }
} }
return result.toString(); 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: * file:
* *
* ASM: a very small and fast Java bytecode manipulation framework * 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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm; package jdk.internal.org.objectweb.asm;
/** /**
* A reference to a type appearing in a class, field or method declaration, or * A reference to a type appearing in a class, field or method declaration, or on an instruction.
* on an instruction. Such a reference designates the part of the class where * Such a reference designates the part of the class where the referenced type is appearing (e.g. an
* the referenced type is appearing (e.g. an 'extends', 'implements' or 'throws' * 'extends', 'implements' or 'throws' clause, a 'new' instruction, a 'catch' clause, a type cast, a
* clause, a 'new' instruction, a 'catch' clause, a type cast, a local variable * local variable declaration, etc).
* declaration, etc).
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public class TypeReference { public class TypeReference {
/** /**
* The sort of type references that target a type parameter of a generic * The sort of type references that target a type parameter of a generic class. See {@link
* class. See {@link #getSort getSort}. * #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 * The sort of type references that target a type parameter of a generic method. See {@link
* method. See {@link #getSort getSort}. * #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 * The sort of type references that target the super class of a class or one of the interfaces it
* of the interfaces it implements. See {@link #getSort getSort}. * 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 * The sort of type references that target a bound of a type parameter of a generic class. See
* generic class. See {@link #getSort getSort}. * {@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 * The sort of type references that target a bound of a type parameter of a generic method. See
* generic method. See {@link #getSort getSort}. * {@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 * The sort of type references that target the receiver type of a method. See {@link #getSort}.
* {@link #getSort getSort}. */
*/ public static final int METHOD_RECEIVER = 0x15;
public final static int FIELD = 0x13;
/** /**
* The sort of type references that target the return type of a method. See * The sort of type references that target the type of a formal parameter of a method. See {@link
* {@link #getSort getSort}. * #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. * The sort of type references that target the type of an exception declared in the throws clause
* See {@link #getSort getSort}. * 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 * The sort of type references that target the type of a local variable in a method. See {@link
* a method. See {@link #getSort getSort}. * #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 * The sort of type references that target the type of a resource variable in a method. See {@link
* in the throws clause of a method. See {@link #getSort getSort}. * #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 * The sort of type references that target the type of the exception of a 'catch' clause in a
* method. See {@link #getSort getSort}. * 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 * The sort of type references that target the type declared in an 'instanceof' instruction. See
* in a method. See {@link #getSort getSort}. * {@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 * The sort of type references that target the type of the object created by a 'new' instruction.
* 'catch' clause in a method. See {@link #getSort getSort}. * 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 * The sort of type references that target the receiver type of a constructor reference. See
* 'instanceof' instruction. See {@link #getSort getSort}. * {@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 * The sort of type references that target the receiver type of a method reference. See {@link
* a 'new' instruction. See {@link #getSort getSort}. * #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 * The sort of type references that target the type declared in an explicit or implicit cast
* constructor reference. See {@link #getSort getSort}. * 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 * The sort of type references that target a type parameter of a generic constructor in a
* reference. See {@link #getSort getSort}. * 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 * The sort of type references that target a type parameter of a generic method in a method call.
* or implicit cast instruction. See {@link #getSort getSort}. * 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 * The sort of type references that target a type parameter of a generic constructor in a
* constructor in a constructor call. See {@link #getSort getSort}. * 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 * The sort of type references that target a type parameter of a generic method in a method
* method in a method call. See {@link #getSort getSort}. * 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 * The target_type and target_info structures - as defined in the Java Virtual Machine
* constructor in a constructor reference. See {@link #getSort getSort}. * 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
public final static int CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; * specific method {@link MethodVisitor#visitLocalVariableAnnotation}). Thus, both structures can
* be stored in an int.
*
* <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>
*/
private final int targetTypeAndInfo;
/** /**
* The sort of type references that target a type parameter of a generic * Constructs a new TypeReference.
* method in a method reference. See {@link #getSort getSort}. *
*/ * @param typeRef the int encoded value of the type reference, as received in a visit method
public final static int METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; * related to type annotations, such as {@link ClassVisitor#visitTypeAnnotation}.
*/
/** public TypeReference(final int typeRef) {
* The type reference value in Java class file format. this.targetTypeAndInfo = typeRef;
*/
private int value;
/**
* Creates a new TypeReference.
*
* @param typeRef
* the int encoded value of the type reference, as received in a
* visit method related to type annotations, like
* visitTypeAnnotation.
*/
public TypeReference(int typeRef) {
this.value = typeRef;
} }
/** /**
* Returns a type reference of the given sort. * Returns a type reference of the given sort.
* *
* @param sort * @param sort one of {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, * #LOCAL_VARIABLE}, {@link #RESOURCE_VARIABLE}, {@link #INSTANCEOF}, {@link #NEW}, {@link
* {@link #METHOD_RECEIVER METHOD_RECEIVER}, * #CONSTRUCTOR_REFERENCE}, or {@link #METHOD_REFERENCE}.
* {@link #LOCAL_VARIABLE LOCAL_VARIABLE}, * @return a type reference of the given sort.
* {@link #RESOURCE_VARIABLE RESOURCE_VARIABLE}, */
* {@link #INSTANCEOF INSTANCEOF}, {@link #NEW NEW}, public static TypeReference newTypeReference(final int sort) {
* {@link #CONSTRUCTOR_REFERENCE CONSTRUCTOR_REFERENCE}, or
* {@link #METHOD_REFERENCE METHOD_REFERENCE}.
* @return a type reference of the given sort.
*/
public static TypeReference newTypeReference(int sort) {
return new TypeReference(sort << 24); return new TypeReference(sort << 24);
} }
/** /**
* Returns a reference to a type parameter of a generic class or method. * Returns a reference to a type parameter of a generic class or method.
* *
* @param sort * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or * @param paramIndex the type parameter index.
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. * @return a reference to the given generic class or method type parameter.
* @param paramIndex */
* the type parameter index. public static TypeReference newTypeParameterReference(final int sort, final int paramIndex) {
* @return a reference to the given generic class or method type parameter.
*/
public static TypeReference newTypeParameterReference(int sort,
int paramIndex) {
return new TypeReference((sort << 24) | (paramIndex << 16)); return new TypeReference((sort << 24) | (paramIndex << 16));
} }
/** /**
* Returns a reference to a type parameter bound of a generic class or * Returns a reference to a type parameter bound of a generic class or method.
* method. *
* * @param sort one of {@link #CLASS_TYPE_PARAMETER} or {@link #METHOD_TYPE_PARAMETER}.
* @param sort * @param paramIndex the type parameter index.
* {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER} or * @param boundIndex the type bound index within the above type parameters.
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. * @return a reference to the given generic class or method type parameter bound.
* @param paramIndex */
* the type parameter index. public static TypeReference newTypeParameterBoundReference(
* @param boundIndex final int sort, final int paramIndex, final int boundIndex) {
* the type bound index within the above type parameters. return new TypeReference((sort << 24) | (paramIndex << 16) | (boundIndex << 8));
* @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));
} }
/** /**
* Returns a reference to the super class or to an interface of the * Returns a reference to the super class or to an interface of the 'implements' clause of a
* 'implements' clause of a class. * class.
* *
* @param itfIndex * @param itfIndex the index of an interface in the 'implements' clause of a class, or -1 to
* the index of an interface in the 'implements' clause of a * reference the super class of the class.
* class, or -1 to reference the super class of the class. * @return a reference to the given super type of a class.
* @return a reference to the given super type of a class. */
*/ public static TypeReference newSuperTypeReference(final int itfIndex) {
public static TypeReference newSuperTypeReference(int itfIndex) { return new TypeReference((CLASS_EXTENDS << 24) | ((itfIndex & 0xFFFF) << 8));
itfIndex &= 0xFFFF;
return new TypeReference((CLASS_EXTENDS << 24) | (itfIndex << 8));
} }
/** /**
* Returns a reference to the type of a formal parameter of a method. * Returns a reference to the type of a formal parameter of a method.
* *
* @param paramIndex * @param paramIndex the formal parameter index.
* the formal parameter index. * @return a reference to the type of the given method formal parameter.
* */
* @return a reference to the type of the given method formal parameter. public static TypeReference newFormalParameterReference(final int paramIndex) {
*/ return new TypeReference((METHOD_FORMAL_PARAMETER << 24) | (paramIndex << 16));
public static TypeReference newFormalParameterReference(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 * Returns a reference to the type of an exception, in a 'throws' clause of a method.
* a method. *
* * @param exceptionIndex the index of an exception in a 'throws' clause of a method.
* @param exceptionIndex * @return a reference to the type of the given exception.
* the index of an exception in a 'throws' clause of a method. */
* public static TypeReference newExceptionReference(final int exceptionIndex) {
* @return a reference to the type of the given exception.
*/
public static TypeReference newExceptionReference(int exceptionIndex) {
return new TypeReference((THROWS << 24) | (exceptionIndex << 8)); return new TypeReference((THROWS << 24) | (exceptionIndex << 8));
} }
/** /**
* Returns a reference to the type of the exception declared in a 'catch' * Returns a reference to the type of the exception declared in a 'catch' clause of a method.
* clause of a method. *
* * @param tryCatchBlockIndex the index of a try catch block (using the order in which they are
* @param tryCatchBlockIndex * visited with visitTryCatchBlock).
* the index of a try catch block (using the order in which they * @return a reference to the type of the given exception.
* are visited with visitTryCatchBlock). */
* public static TypeReference newTryCatchReference(final int tryCatchBlockIndex) {
* @return a reference to the type of the given exception. return new TypeReference((EXCEPTION_PARAMETER << 24) | (tryCatchBlockIndex << 8));
*/
public static TypeReference newTryCatchReference(int tryCatchBlockIndex) {
return new TypeReference((EXCEPTION_PARAMETER << 24)
| (tryCatchBlockIndex << 8));
} }
/** /**
* Returns a reference to the type of a type argument in a constructor or * Returns a reference to the type of a type argument in a constructor or method call or
* method call or reference. * reference.
* *
* @param sort * @param sort one of {@link #CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link
* {@link #CAST CAST}, * #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link
* {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT * #METHOD_REFERENCE_TYPE_ARGUMENT}.
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, * @param argIndex the type argument index.
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT * @return a reference to the type of the given type argument.
* METHOD_INVOCATION_TYPE_ARGUMENT}, */
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT public static TypeReference newTypeArgumentReference(final int sort, final int argIndex) {
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT
* 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) {
return new TypeReference((sort << 24) | argIndex); return new TypeReference((sort << 24) | argIndex);
} }
/** /**
* Returns the sort of this type reference. * Returns the sort of this type reference.
* *
* @return {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, * @return one of {@link #CLASS_TYPE_PARAMETER}, {@link #METHOD_TYPE_PARAMETER}, {@link
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, * #CLASS_EXTENDS}, {@link #CLASS_TYPE_PARAMETER_BOUND}, {@link #METHOD_TYPE_PARAMETER_BOUND},
* {@link #CLASS_EXTENDS CLASS_EXTENDS}, * {@link #FIELD}, {@link #METHOD_RETURN}, {@link #METHOD_RECEIVER}, {@link
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND}, * #METHOD_FORMAL_PARAMETER}, {@link #THROWS}, {@link #LOCAL_VARIABLE}, {@link
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}, * #RESOURCE_VARIABLE}, {@link #EXCEPTION_PARAMETER}, {@link #INSTANCEOF}, {@link #NEW},
* {@link #FIELD FIELD}, {@link #METHOD_RETURN METHOD_RETURN}, * {@link #CONSTRUCTOR_REFERENCE}, {@link #METHOD_REFERENCE}, {@link #CAST}, {@link
* {@link #METHOD_RECEIVER METHOD_RECEIVER}, * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
* {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}, * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
* {@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}.
*/
public int getSort() { public int getSort() {
return value >>> 24; return targetTypeAndInfo >>> 24;
} }
/** /**
* Returns the index of the type parameter referenced by this type * Returns the index of the type parameter referenced by this type reference. This method must
* reference. This method must only be used for type references whose sort * only be used for type references whose sort is {@link #CLASS_TYPE_PARAMETER}, {@link
* is {@link #CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}, * #METHOD_TYPE_PARAMETER}, {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
* {@link #METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}, * #METHOD_TYPE_PARAMETER_BOUND}.
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or *
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. * @return a type parameter index.
* */
* @return a type parameter index.
*/
public int getTypeParameterIndex() { public int getTypeParameterIndex() {
return (value & 0x00FF0000) >> 16; return (targetTypeAndInfo & 0x00FF0000) >> 16;
} }
/** /**
* Returns the index of the type parameter bound, within the type parameter * Returns the index of the type parameter bound, within the type parameter {@link
* {@link #getTypeParameterIndex}, referenced by this type reference. This * #getTypeParameterIndex}, referenced by this type reference. This method must only be used for
* method must only be used for type references whose sort is * type references whose sort is {@link #CLASS_TYPE_PARAMETER_BOUND} or {@link
* {@link #CLASS_TYPE_PARAMETER_BOUND CLASS_TYPE_PARAMETER_BOUND} or * #METHOD_TYPE_PARAMETER_BOUND}.
* {@link #METHOD_TYPE_PARAMETER_BOUND METHOD_TYPE_PARAMETER_BOUND}. *
* * @return a type parameter bound index.
* @return a type parameter bound index. */
*/
public int getTypeParameterBoundIndex() { 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 * Returns the index of the "super type" of a class that is referenced by this type reference.
* this type reference. This method must only be used for type references * This method must only be used for type references whose sort is {@link #CLASS_EXTENDS}.
* whose sort is {@link #CLASS_EXTENDS CLASS_EXTENDS}. *
* * @return the index of an interface in the 'implements' clause of a class, or -1 if this type
* @return the index of an interface in the 'implements' clause of a class, * reference references the type of the super class.
* or -1 if this type reference references the type of the super */
* class.
*/
public int getSuperTypeIndex() { 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 * Returns the index of the formal parameter whose type is referenced by this type reference. This
* this type reference. This method must only be used for type references * method must only be used for type references whose sort is {@link #METHOD_FORMAL_PARAMETER}.
* whose sort is {@link #METHOD_FORMAL_PARAMETER METHOD_FORMAL_PARAMETER}. *
* * @return a formal parameter index.
* @return a formal parameter index. */
*/
public int getFormalParameterIndex() { public int getFormalParameterIndex() {
return (value & 0x00FF0000) >> 16; return (targetTypeAndInfo & 0x00FF0000) >> 16;
} }
/** /**
* Returns the index of the exception, in a 'throws' clause of a method, * Returns the index of the exception, in a 'throws' clause of a method, whose type is referenced
* whose type is referenced by this type reference. This method must only be * by this type reference. This method must only be used for type references whose sort is {@link
* used for type references whose sort is {@link #THROWS THROWS}. * #THROWS}.
* *
* @return the index of an exception in the 'throws' clause of a method. * @return the index of an exception in the 'throws' clause of a method.
*/ */
public int getExceptionIndex() { 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 * Returns the index of the try catch block (using the order in which they are visited with
* are visited with visitTryCatchBlock), whose 'catch' type is referenced by * visitTryCatchBlock), whose 'catch' type is referenced by this type reference. This method must
* this type reference. This method must only be used for type references * only be used for type references whose sort is {@link #EXCEPTION_PARAMETER} .
* whose sort is {@link #EXCEPTION_PARAMETER EXCEPTION_PARAMETER} . *
* * @return the index of an exception in the 'throws' clause of a method.
* @return the index of an exception in the 'throws' clause of a method. */
*/
public int getTryCatchBlockIndex() { public int getTryCatchBlockIndex() {
return (value & 0x00FFFF00) >> 8; return (targetTypeAndInfo & 0x00FFFF00) >> 8;
} }
/** /**
* Returns the index of the type argument referenced by this type reference. * Returns the index of the type argument referenced by this type reference. This method must only
* This method must only be used for type references whose sort is * be used for type references whose sort is {@link #CAST}, {@link
* {@link #CAST CAST}, {@link #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT * #CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, {@link #METHOD_INVOCATION_TYPE_ARGUMENT}, {@link
* CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}, * #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or {@link #METHOD_REFERENCE_TYPE_ARGUMENT}.
* {@link #METHOD_INVOCATION_TYPE_ARGUMENT METHOD_INVOCATION_TYPE_ARGUMENT}, *
* {@link #CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT * @return a type parameter index.
* CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}, or */
* {@link #METHOD_REFERENCE_TYPE_ARGUMENT METHOD_REFERENCE_TYPE_ARGUMENT}.
*
* @return a type parameter index.
*/
public int getTypeArgumentIndex() { public int getTypeArgumentIndex() {
return value & 0xFF; return targetTypeAndInfo & 0xFF;
} }
/** /**
* Returns the int encoded value of this type reference, suitable for use in * Returns the int encoded value of this type reference, suitable for use in visit methods related
* visit methods related to type annotations, like visitTypeAnnotation. * to type annotations, like visitTypeAnnotation.
* *
* @return the int encoded value of this type reference. * @return the int encoded value of this type reference.
*/ */
public int getValue() { 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

@ -56,53 +56,78 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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 * @author Eugene Kuleshov
*/ */
public class AnnotationRemapper extends AnnotationVisitor { public class AnnotationRemapper extends AnnotationVisitor {
/** The remapper used to remap the types in the visited annotation. */
protected final Remapper remapper; protected final Remapper remapper;
public AnnotationRemapper(final AnnotationVisitor av, /**
final Remapper remapper) { * Constructs a new {@link AnnotationRemapper}. <i>Subclasses must not use this constructor</i>.
this(Opcodes.ASM6, av, remapper); * 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) { * Constructs a new {@link AnnotationRemapper}.
super(api, av); *
* @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; this.remapper = remapper;
} }
@Override @Override
public void visit(String name, Object value) { public void visit(final String name, final Object value) {
av.visit(name, remapper.mapValue(value)); super.visit(name, remapper.mapValue(value));
} }
@Override @Override
public void visitEnum(String name, String desc, String value) { public void visitEnum(final String name, final String descriptor, final String value) {
av.visitEnum(name, remapper.mapDesc(desc), value); super.visitEnum(name, remapper.mapDesc(descriptor), value);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String name, String desc) { public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); AnnotationVisitor annotationVisitor = super.visitAnnotation(name, remapper.mapDesc(descriptor));
return v == null ? null : (v == av ? this : new AnnotationRemapper(v, if (annotationVisitor == null) {
remapper)); return null;
} else {
return annotationVisitor == av
? this
: new AnnotationRemapper(api, annotationVisitor, remapper);
}
} }
@Override @Override
public AnnotationVisitor visitArray(String name) { public AnnotationVisitor visitArray(final String name) {
AnnotationVisitor v = av.visitArray(name); AnnotationVisitor annotationVisitor = super.visitArray(name);
return v == null ? null : (v == av ? this : new AnnotationRemapper(v, if (annotationVisitor == null) {
remapper)); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import java.util.List; import java.util.List;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ClassVisitor; 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; 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 * @author Eugene Kuleshov
*/ */
public class ClassRemapper extends ClassVisitor { public class ClassRemapper extends ClassVisitor {
/** The remapper used to remap the types in the visited class. */
protected final Remapper remapper; protected final Remapper remapper;
/** The internal name of the visited class. */
protected String className; 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) { * Constructs a new {@link ClassRemapper}.
super(api, cv); *
* @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; this.remapper = remapper;
} }
@Override @Override
public void visit(int version, int access, String name, String signature, public void visit(
String superName, String[] interfaces) { final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name; this.className = name;
super.visit(version, access, remapper.mapType(name), remapper super.visit(
.mapSignature(signature, false), remapper.mapType(superName), version,
access,
remapper.mapType(name),
remapper.mapSignature(signature, false),
remapper.mapType(superName),
interfaces == null ? null : remapper.mapTypes(interfaces)); interfaces == null ? null : remapper.mapTypes(interfaces));
} }
@Override @Override
public ModuleVisitor visitModule(String name, int flags, String version) { public ModuleVisitor visitModule(final String name, final int flags, final String version) {
ModuleVisitor mv = super.visitModule(remapper.mapModuleName(name), flags, version); ModuleVisitor moduleVisitor = super.visitModule(remapper.mapModuleName(name), flags, version);
return mv == null ? null : createModuleRemapper(mv); return moduleVisitor == null ? null : createModuleRemapper(moduleVisitor);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor =
visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return av == null ? null : createAnnotationRemapper(av); return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? null : createAnnotationRemapper(av); return annotationVisitor == null ? null : createAnnotationRemapper(annotationVisitor);
} }
@Override @Override
public void visitAttribute(Attribute attr) { public void visitAttribute(final Attribute attribute) {
if (attr instanceof ModuleHashesAttribute) { if (attribute instanceof ModuleHashesAttribute) {
ModuleHashesAttribute hashesAttr = new ModuleHashesAttribute(); ModuleHashesAttribute moduleHashesAttribute = (ModuleHashesAttribute) attribute;
List<String> modules = hashesAttr.modules; List<String> modules = moduleHashesAttribute.modules;
for(int i = 0; i < modules.size(); i++) { for (int i = 0; i < modules.size(); ++i) {
modules.set(i, remapper.mapModuleName(modules.get(i))); modules.set(i, remapper.mapModuleName(modules.get(i)));
} }
} }
super.visitAttribute(attr); super.visitAttribute(attribute);
} }
@Override @Override
public FieldVisitor visitField(int access, String name, String desc, public FieldVisitor visitField(
String signature, Object value) { final int access,
FieldVisitor fv = super.visitField(access, final String name,
remapper.mapFieldName(className, name, desc), final String descriptor,
remapper.mapDesc(desc), remapper.mapSignature(signature, true), final String signature,
remapper.mapValue(value)); final Object value) {
return fv == null ? null : createFieldRemapper(fv); 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 @Override
public MethodVisitor visitMethod(int access, String name, String desc, public MethodVisitor visitMethod(
String signature, String[] exceptions) { final int access,
String newDesc = remapper.mapMethodDesc(desc); final String name,
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( final String descriptor,
className, name, desc), newDesc, remapper.mapSignature( final String signature,
signature, false), final String[] exceptions) {
exceptions == null ? null : remapper.mapTypes(exceptions)); String remappedDescriptor = remapper.mapMethodDesc(descriptor);
return mv == null ? null : createMethodRemapper(mv); MethodVisitor methodVisitor =
super.visitMethod(
access,
remapper.mapMethodName(className, name, descriptor),
remappedDescriptor,
remapper.mapSignature(signature, false),
exceptions == null ? null : remapper.mapTypes(exceptions));
return methodVisitor == null ? null : createMethodRemapper(methodVisitor);
} }
@Override @Override
public void visitInnerClass(String name, String outerName, public void visitInnerClass(
String innerName, int access) { final String name, final String outerName, final String innerName, final int access) {
// TODO should innerName be changed? super.visitInnerClass(
super.visitInnerClass(remapper.mapType(name), outerName == null ? null remapper.mapType(name),
: remapper.mapType(outerName), innerName, access); outerName == null ? null : remapper.mapType(outerName),
innerName == null ? null : remapper.mapInnerClassName(name, outerName, innerName),
access);
} }
@Override @Override
public void visitOuterClass(String owner, String name, String desc) { public void visitOuterClass(final String owner, final String name, final String descriptor) {
super.visitOuterClass(remapper.mapType(owner), name == null ? null super.visitOuterClass(
: remapper.mapMethodName(owner, name, desc), remapper.mapType(owner),
desc == null ? null : remapper.mapMethodDesc(desc)); name == null ? null : remapper.mapMethodName(owner, name, descriptor),
descriptor == null ? null : remapper.mapMethodDesc(descriptor));
} }
protected FieldVisitor createFieldRemapper(FieldVisitor fv) { @Override
return new FieldRemapper(fv, remapper); public void visitNestHost(final String nestHost) {
super.visitNestHost(remapper.mapType(nestHost));
} }
protected MethodVisitor createMethodRemapper(MethodVisitor mv) { @Override
return new MethodRemapper(mv, remapper); 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; 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.Handle;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; 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 * @author Eugene Kuleshov
*/ */
public class CodeSizeEvaluator extends MethodVisitor implements Opcodes { public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
/** The minimum size in bytes of the visited method. */
private int minSize; private int minSize;
/** The maximum size in bytes of the visited method. */
private int maxSize; private int maxSize;
public CodeSizeEvaluator(final MethodVisitor mv) { public CodeSizeEvaluator(final MethodVisitor methodVisitor) {
this(Opcodes.ASM6, mv); this(Opcodes.ASM7, methodVisitor);
} }
protected CodeSizeEvaluator(final int api, final MethodVisitor mv) { protected CodeSizeEvaluator(final int api, final MethodVisitor methodVisitor) {
super(api, mv); super(api, methodVisitor);
} }
public int getMinSize() { public int getMinSize() {
@ -94,9 +97,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
public void visitInsn(final int opcode) { public void visitInsn(final int opcode) {
minSize += 1; minSize += 1;
maxSize += 1; maxSize += 1;
if (mv != null) { super.visitInsn(opcode);
mv.visitInsn(opcode);
}
} }
@Override @Override
@ -108,9 +109,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2; minSize += 2;
maxSize += 2; maxSize += 2;
} }
if (mv != null) { super.visitIntInsn(opcode, operand);
mv.visitIntInsn(opcode, operand);
}
} }
@Override @Override
@ -125,54 +124,60 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2; minSize += 2;
maxSize += 2; maxSize += 2;
} }
if (mv != null) { super.visitVarInsn(opcode, var);
mv.visitVarInsn(opcode, var);
}
} }
@Override @Override
public void visitTypeInsn(final int opcode, final String type) { public void visitTypeInsn(final int opcode, final String type) {
minSize += 3; minSize += 3;
maxSize += 3; maxSize += 3;
if (mv != null) { super.visitTypeInsn(opcode, type);
mv.visitTypeInsn(opcode, type);
}
} }
@Override @Override
public void visitFieldInsn(final int opcode, final String owner, public void visitFieldInsn(
final String name, final String desc) { final int opcode, final String owner, final String name, final String descriptor) {
minSize += 3; minSize += 3;
maxSize += 3; maxSize += 3;
if (mv != null) { super.visitFieldInsn(opcode, owner, name, descriptor);
mv.visitFieldInsn(opcode, owner, name, desc);
}
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated @Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc) { final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) { if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc); super.visitMethodInsn(opcode, owner, name, descriptor);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
opcode == Opcodes.INVOKEINTERFACE);
} }
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc, final boolean itf) { final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf); super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, itf); doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
} }
private void doVisitMethodInsn(int opcode, final String owner, private void doVisitMethodInsn(
final String name, final String desc, final boolean itf) { final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (opcode == INVOKEINTERFACE) { if (opcode == INVOKEINTERFACE) {
minSize += 5; minSize += 5;
maxSize += 5; maxSize += 5;
@ -181,18 +186,19 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
maxSize += 3; maxSize += 3;
} }
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, owner, name, desc, itf); mv.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
} }
} }
@Override @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, public void visitInvokeDynamicInsn(
Object... bsmArgs) { final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
minSize += 5; minSize += 5;
maxSize += 5; maxSize += 5;
if (mv != null) { super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
} }
@Override @Override
@ -203,23 +209,21 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
} else { } else {
maxSize += 8; maxSize += 8;
} }
if (mv != null) { super.visitJumpInsn(opcode, label);
mv.visitJumpInsn(opcode, label);
}
} }
@Override @Override
public void visitLdcInsn(final Object cst) { public void visitLdcInsn(final Object value) {
if (cst instanceof Long || cst instanceof Double) { if (value instanceof Long
|| value instanceof Double
|| (value instanceof ConstantDynamic && ((ConstantDynamic) value).getSize() == 2)) {
minSize += 3; minSize += 3;
maxSize += 3; maxSize += 3;
} else { } else {
minSize += 2; minSize += 2;
maxSize += 3; maxSize += 3;
} }
if (mv != null) { super.visitLdcInsn(value);
mv.visitLdcInsn(cst);
}
} }
@Override @Override
@ -231,37 +235,28 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 3; minSize += 3;
maxSize += 3; maxSize += 3;
} }
if (mv != null) { super.visitIincInsn(var, increment);
mv.visitIincInsn(var, increment);
}
} }
@Override @Override
public void visitTableSwitchInsn(final int min, final int max, public void visitTableSwitchInsn(
final Label dflt, final Label... labels) { final int min, final int max, final Label dflt, final Label... labels) {
minSize += 13 + labels.length * 4; minSize += 13 + labels.length * 4;
maxSize += 16 + labels.length * 4; maxSize += 16 + labels.length * 4;
if (mv != null) { super.visitTableSwitchInsn(min, max, dflt, labels);
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
} }
@Override @Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
final Label[] labels) {
minSize += 9 + keys.length * 8; minSize += 9 + keys.length * 8;
maxSize += 12 + keys.length * 8; maxSize += 12 + keys.length * 8;
if (mv != null) { super.visitLookupSwitchInsn(dflt, keys, labels);
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
} }
@Override @Override
public void visitMultiANewArrayInsn(final String desc, final int dims) { public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
minSize += 4; minSize += 4;
maxSize += 4; maxSize += 4;
if (mv != null) { super.visitMultiANewArrayInsn(descriptor, numDimensions);
mv.visitMultiANewArrayInsn(desc, dims);
}
} }
} }

View file

@ -56,7 +56,6 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; 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; 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 * @author Eugene Kuleshov
*/ */
public class FieldRemapper extends FieldVisitor { 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) { * Constructs a new {@link FieldRemapper}.
super(api, fv); *
* @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; this.remapper = remapper;
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor =
visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return av == null ? null : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? null
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? null : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? null
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
} }

View file

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

View file

@ -60,7 +60,6 @@ package jdk.internal.org.objectweb.asm.commons;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
/** /**
@ -72,240 +71,223 @@ import jdk.internal.org.objectweb.asm.Type;
*/ */
public class Method { public class Method {
/** /** The method name. */
* The method name.
*/
private final String name; private final String name;
/** /** The method descriptor. */
* The method descriptor. private final String descriptor;
*/
private final String desc;
/** /** The descriptors of the primitive Java types (plus void). */
* Maps primitive Java type names to their descriptors. private static final Map<String, String> PRIMITIVE_TYPE_DESCRIPTORS;
*/
private static final Map<String, String> DESCRIPTORS;
static { static {
DESCRIPTORS = new HashMap<String, String>(); HashMap<String, String> descriptors = new HashMap<String, String>();
DESCRIPTORS.put("void", "V"); descriptors.put("void", "V");
DESCRIPTORS.put("byte", "B"); descriptors.put("byte", "B");
DESCRIPTORS.put("char", "C"); descriptors.put("char", "C");
DESCRIPTORS.put("double", "D"); descriptors.put("double", "D");
DESCRIPTORS.put("float", "F"); descriptors.put("float", "F");
DESCRIPTORS.put("int", "I"); descriptors.put("int", "I");
DESCRIPTORS.put("long", "J"); descriptors.put("long", "J");
DESCRIPTORS.put("short", "S"); descriptors.put("short", "S");
DESCRIPTORS.put("boolean", "Z"); descriptors.put("boolean", "Z");
PRIMITIVE_TYPE_DESCRIPTORS = descriptors;
} }
/** /**
* Creates a new {@link Method}. * Constructs a new {@link Method}.
* *
* @param name * @param name the method's name.
* the method's name. * @param descriptor the method's descriptor.
* @param desc */
* the method's descriptor. public Method(final String name, final String descriptor) {
*/
public Method(final String name, final String desc) {
this.name = name; this.name = name;
this.desc = desc; this.descriptor = descriptor;
} }
/** /**
* Creates a new {@link Method}. * Constructs a new {@link Method}.
* *
* @param name * @param name the method's name.
* the method's name. * @param returnType the method's return type.
* @param returnType * @param argumentTypes the method's argument types.
* the method's return type. */
* @param argumentTypes public Method(final String name, final Type returnType, final Type[] argumentTypes) {
* the method's argument types.
*/
public Method(final String name, final Type returnType,
final Type[] argumentTypes) {
this(name, Type.getMethodDescriptor(returnType, argumentTypes)); this(name, Type.getMethodDescriptor(returnType, argumentTypes));
} }
/** /**
* Creates a new {@link Method}. * Creates a new {@link Method}.
* *
* @param m * @param method a java.lang.reflect method descriptor
* a java.lang.reflect method descriptor * @return a {@link Method} corresponding to the given Java method declaration.
* @return a {@link Method} corresponding to the given Java method */
* declaration. public static Method getMethod(final java.lang.reflect.Method method) {
*/ return new Method(method.getName(), Type.getMethodDescriptor(method));
public static Method getMethod(java.lang.reflect.Method m) {
return new Method(m.getName(), Type.getMethodDescriptor(m));
} }
/** /**
* Creates a new {@link Method}. * Creates a new {@link Method}.
* *
* @param c * @param constructor a java.lang.reflect constructor descriptor
* a java.lang.reflect constructor descriptor * @return a {@link Method} corresponding to the given Java constructor declaration.
* @return a {@link Method} corresponding to the given Java constructor */
* declaration. public static Method getMethod(final java.lang.reflect.Constructor<?> constructor) {
*/ return new Method("<init>", Type.getConstructorDescriptor(constructor));
public static Method getMethod(java.lang.reflect.Constructor<?> c) {
return new Method("<init>", Type.getConstructorDescriptor(c));
} }
/** /**
* Returns a {@link Method} corresponding to the given Java method * Returns a {@link Method} corresponding to the given Java method declaration.
* declaration. *
* * @param method a Java method declaration, without argument names, of the form "returnType name
* @param method * (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
* a Java method declaration, without argument names, of the form * "float", "java.util.List", ...). Classes of the java.lang package can be specified by their
* "returnType name (argumentType1, ... argumentTypeN)", where * unqualified name; all other classes names must be fully qualified.
* the types are in plain Java (e.g. "int", "float", * @return a {@link Method} corresponding to the given Java method declaration.
* "java.util.List", ...). Classes of the java.lang package can * @throws IllegalArgumentException if <code>method</code> could not get parsed.
* be specified by their unqualified name; all other classes */
* names must be fully qualified. public static Method getMethod(final String method) {
* @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 {
return getMethod(method, false); return getMethod(method, false);
} }
/** /**
* Returns a {@link Method} corresponding to the given Java method * Returns a {@link Method} corresponding to the given Java method declaration.
* declaration. *
* * @param method a Java method declaration, without argument names, of the form "returnType name
* @param method * (argumentType1, ... argumentTypeN)", where the types are in plain Java (e.g. "int",
* a Java method declaration, without argument names, of the form * "float", "java.util.List", ...). Classes of the java.lang package may be specified by their
* "returnType name (argumentType1, ... argumentTypeN)", where * unqualified name, depending on the defaultPackage argument; all other classes names must be
* the types are in plain Java (e.g. "int", "float", * fully qualified.
* "java.util.List", ...). Classes of the java.lang package may * @param defaultPackage true if unqualified class names belong to the default package, or false
* be specified by their unqualified name, depending on the * if they correspond to java.lang classes. For instance "Object" means "Object" if this
* defaultPackage argument; all other classes names must be fully * option is true, or "java.lang.Object" otherwise.
* qualified. * @return a {@link Method} corresponding to the given Java method declaration.
* @param defaultPackage * @throws IllegalArgumentException if <code>method</code> could not get parsed.
* true if unqualified class names belong to the default package, */
* or false if they correspond to java.lang classes. For instance public static Method getMethod(final String method, final boolean defaultPackage) {
* "Object" means "Object" if this option is true, or final int spaceIndex = method.indexOf(' ');
* "java.lang.Object" otherwise. int currentArgumentStartIndex = method.indexOf('(', spaceIndex) + 1;
* @return a {@link Method} corresponding to the given Java method final int endIndex = method.indexOf(')', currentArgumentStartIndex);
* declaration. if (spaceIndex == -1 || currentArgumentStartIndex == 0 || endIndex == -1) {
* @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) {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
String returnType = method.substring(0, space); final String returnType = method.substring(0, spaceIndex);
String methodName = method.substring(space + 1, start - 1).trim(); final String methodName =
StringBuilder sb = new StringBuilder(); method.substring(spaceIndex + 1, currentArgumentStartIndex - 1).trim();
sb.append('('); StringBuilder stringBuilder = new StringBuilder();
int p; stringBuilder.append('(');
int currentArgumentEndIndex;
do { do {
String s; String argumentDescriptor;
p = method.indexOf(',', start); currentArgumentEndIndex = method.indexOf(',', currentArgumentStartIndex);
if (p == -1) { if (currentArgumentEndIndex == -1) {
s = map(method.substring(start, end).trim(), defaultPackage); argumentDescriptor =
getDescriptorInternal(
method.substring(currentArgumentStartIndex, endIndex).trim(), defaultPackage);
} else { } else {
s = map(method.substring(start, p).trim(), defaultPackage); argumentDescriptor =
start = p + 1; getDescriptorInternal(
method.substring(currentArgumentStartIndex, currentArgumentEndIndex).trim(),
defaultPackage);
currentArgumentStartIndex = currentArgumentEndIndex + 1;
} }
sb.append(s); stringBuilder.append(argumentDescriptor);
} while (p != -1); } while (currentArgumentEndIndex != -1);
sb.append(')'); stringBuilder.append(')').append(getDescriptorInternal(returnType, defaultPackage));
sb.append(map(returnType, defaultPackage)); return new Method(methodName, stringBuilder.toString());
return new Method(methodName, sb.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)) { if ("".equals(type)) {
return type; return type;
} }
StringBuilder sb = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
int index = 0; int arrayBracketsIndex = 0;
while ((index = type.indexOf("[]", index) + 1) > 0) { while ((arrayBracketsIndex = type.indexOf("[]", arrayBracketsIndex) + 1) > 0) {
sb.append('['); stringBuilder.append('[');
} }
String t = type.substring(0, type.length() - sb.length() * 2); String elementType = type.substring(0, type.length() - stringBuilder.length() * 2);
String desc = DESCRIPTORS.get(t); String descriptor = PRIMITIVE_TYPE_DESCRIPTORS.get(elementType);
if (desc != null) { if (descriptor != null) {
sb.append(desc); stringBuilder.append(descriptor);
} else { } else {
sb.append('L'); stringBuilder.append('L');
if (t.indexOf('.') < 0) { if (elementType.indexOf('.') < 0) {
if (!defaultPackage) { if (!defaultPackage) {
sb.append("java/lang/"); stringBuilder.append("java/lang/");
} }
sb.append(t); stringBuilder.append(elementType);
} else { } else {
sb.append(t.replace('.', '/')); stringBuilder.append(elementType.replace('.', '/'));
} }
sb.append(';'); stringBuilder.append(';');
} }
return sb.toString(); return stringBuilder.toString();
} }
/** /**
* Returns the name of the method described by this object. * Returns the name of the method described by this object.
* *
* @return the name of the method described by this object. * @return the name of the method described by this object.
*/ */
public String getName() { public String getName() {
return name; return name;
} }
/** /**
* Returns the descriptor of the method described by this object. * Returns the descriptor of the method described by this object.
* *
* @return the descriptor of the method described by this object. * @return the descriptor of the method described by this object.
*/ */
public String getDescriptor() { public String getDescriptor() {
return desc; return descriptor;
} }
/** /**
* Returns the return type of the method described by this object. * Returns the return type of the method described by this object.
* *
* @return the return type of the method described by this object. * @return the return type of the method described by this object.
*/ */
public Type getReturnType() { public Type getReturnType() {
return Type.getReturnType(desc); return Type.getReturnType(descriptor);
} }
/** /**
* Returns the argument types of the method described by this object. * Returns the argument types of the method described by this object.
* *
* @return the argument types of the method described by this object. * @return the argument types of the method described by this object.
*/ */
public Type[] getArgumentTypes() { public Type[] getArgumentTypes() {
return Type.getArgumentTypes(desc); return Type.getArgumentTypes(descriptor);
} }
@Override @Override
public String toString() { public String toString() {
return name + desc; return name + descriptor;
} }
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object other) {
if (!(o instanceof Method)) { if (!(other instanceof Method)) {
return false; return false;
} }
Method other = (Method) o; Method otherMethod = (Method) other;
return name.equals(other.name) && desc.equals(other.desc); return name.equals(otherMethod.name) && descriptor.equals(otherMethod.descriptor);
} }
@Override @Override
public int hashCode() { 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; 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; 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 * @author Eugene Kuleshov
*/ */
public class MethodRemapper extends MethodVisitor { public class MethodRemapper extends MethodVisitor {
/** The remapper used to remap the types in the visited field. */
protected final Remapper remapper; 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) { * Constructs a new {@link MethodRemapper}.
super(api, mv); *
* @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; this.remapper = remapper;
} }
@Override @Override
public AnnotationVisitor visitAnnotationDefault() { public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor av = super.visitAnnotationDefault(); AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor =
visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitParameterAnnotation(int parameter, public AnnotationVisitor visitParameterAnnotation(
String desc, boolean visible) { final int parameter, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitParameterAnnotation(parameter, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack, public void visitFrame(
Object[] stack) { final int type,
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, final int numLocal,
remapEntries(nStack, stack)); 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) { private Object[] remapFrameTypes(final int numTypes, final Object[] frameTypes) {
if (entries != null) { if (frameTypes == null) {
for (int i = 0; i < n; i++) { return frameTypes;
if (entries[i] instanceof String) { }
Object[] newEntries = new Object[n]; Object[] remappedFrameTypes = null;
if (i > 0) { for (int i = 0; i < numTypes; ++i) {
System.arraycopy(entries, 0, newEntries, 0, i); if (frameTypes[i] instanceof String) {
} if (remappedFrameTypes == null) {
do { remappedFrameTypes = new Object[numTypes];
Object t = entries[i]; System.arraycopy(frameTypes, 0, remappedFrameTypes, 0, numTypes);
newEntries[i++] = t instanceof String ? remapper
.mapType((String) t) : t;
} while (i < n);
return newEntries;
} }
remappedFrameTypes[i] = remapper.mapType((String) frameTypes[i]);
} }
} }
return entries; return remappedFrameTypes == null ? frameTypes : remappedFrameTypes;
} }
@Override @Override
public void visitFieldInsn(int opcode, String owner, String name, public void visitFieldInsn(
String desc) { final int opcode, final String owner, final String name, final String descriptor) {
super.visitFieldInsn(opcode, remapper.mapType(owner), super.visitFieldInsn(
remapper.mapFieldName(owner, name, desc), opcode,
remapper.mapDesc(desc)); remapper.mapType(owner),
remapper.mapFieldName(owner, name, descriptor),
remapper.mapDesc(descriptor));
} }
/**
* Deprecated.
*
* @deprecated use {@link #visitMethodInsn(int, String, String, String, boolean)} instead.
*/
@Deprecated @Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc) { final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) { if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc); super.visitMethodInsn(opcode, owner, name, descriptor);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
opcode == Opcodes.INVOKEINTERFACE);
} }
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc, final boolean itf) { final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf); super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, itf); doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
} }
private void doVisitMethodInsn(int opcode, String owner, String name, private void doVisitMethodInsn(
String desc, boolean itf) { final int opcode,
// Calling super.visitMethodInsn requires to call the correct version final String owner,
// depending on this.api (otherwise infinite loops can occur). To final String name,
// simplify and to make it easier to automatically remove the backward final String descriptor,
// compatibility code, we inline the code of the overridden method here. final boolean isInterface) {
// IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN // Calling super.visitMethodInsn requires to call the correct version depending on this.api
// LocalVariableSorter. // (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) { if (mv != null) {
mv.visitMethodInsn(opcode, remapper.mapType(owner), mv.visitMethodInsn(
remapper.mapMethodName(owner, name, desc), opcode,
remapper.mapMethodDesc(desc), itf); remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
} }
} }
@Override @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, public void visitInvokeDynamicInsn(
Object... bsmArgs) { final String name,
for (int i = 0; i < bsmArgs.length; i++) { final String descriptor,
bsmArgs[i] = remapper.mapValue(bsmArgs[i]); 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( super.visitInvokeDynamicInsn(
remapper.mapInvokeDynamicMethodName(name, desc), remapper.mapInvokeDynamicMethodName(name, descriptor),
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), remapper.mapMethodDesc(descriptor),
bsmArgs); (Handle) remapper.mapValue(bootstrapMethodHandle),
remappedBootstrapMethodArguments);
} }
@Override @Override
public void visitTypeInsn(int opcode, String type) { public void visitTypeInsn(final int opcode, final String type) {
super.visitTypeInsn(opcode, remapper.mapType(type)); super.visitTypeInsn(opcode, remapper.mapType(type));
} }
@Override @Override
public void visitLdcInsn(Object cst) { public void visitLdcInsn(final Object value) {
super.visitLdcInsn(remapper.mapValue(cst)); super.visitLdcInsn(remapper.mapValue(value));
} }
@Override @Override
public void visitMultiANewArrayInsn(String desc, int dims) { public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
} }
@Override @Override
public AnnotationVisitor visitInsnAnnotation(int typeRef, public AnnotationVisitor visitInsnAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public void visitTryCatchBlock(Label start, Label end, Label handler, public void visitTryCatchBlock(
String type) { final Label start, final Label end, final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
: remapper.mapType(type));
} }
@Override @Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, public AnnotationVisitor visitTryCatchAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new AnnotationRemapper(av, remapper); return annotationVisitor == null
? annotationVisitor
: new AnnotationRemapper(api, annotationVisitor, remapper);
} }
@Override @Override
public void visitLocalVariable(String name, String desc, String signature, public void visitLocalVariable(
Label start, Label end, int index) { final String name,
super.visitLocalVariable(name, remapper.mapDesc(desc), final String descriptor,
remapper.mapSignature(signature, true), start, end, index); 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 @Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, public AnnotationVisitor visitLocalVariableAnnotation(
TypePath typePath, Label[] start, Label[] end, int[] index, final int typeRef,
String desc, boolean visible) { final TypePath typePath,
AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, final Label[] start,
typePath, start, end, index, remapper.mapDesc(desc), visible); final Label[] end,
return av == null ? av : new AnnotationRemapper(av, remapper); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
import jdk.internal.org.objectweb.asm.ByteVector; import jdk.internal.org.objectweb.asm.ByteVector;
import jdk.internal.org.objectweb.asm.ClassReader; 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; import jdk.internal.org.objectweb.asm.Label;
/** /**
* ModuleHashes attribute. * A ModuleHashes attribute. This attribute is specific to the OpenJDK and may change in the future.
* This attribute is specific to the OpenJDK and may change in the future.
* *
* @author Remi Forax * @author Remi Forax
*/ */
public final class ModuleHashesAttribute extends Attribute { public final class ModuleHashesAttribute extends Attribute {
/** The name of the hashing algorithm. */
public String algorithm; public String algorithm;
/** A list of module names. */
public List<String> modules; public List<String> modules;
/** The hash of the modules in {@link #modules}. The two lists must have the same size. */
public List<byte[]> hashes; public List<byte[]> hashes;
/** /**
* Creates an attribute with a hashing algorithm, a list of module names, * Constructs a new {@link ModuleHashesAttribute}.
* and a list of the same length of hashes. *
* @param algorithm the hashing algorithm name. * @param algorithm the name of the hashing algorithm.
* @param modules a list of module name * @param modules a list of module names.
* @param hashes a list of hash, one for each module name. * @param hashes the hash of the modules in 'modules'. The two lists must have the same size.
*/ */
public ModuleHashesAttribute(final String algorithm, public ModuleHashesAttribute(
final List<String> modules, final List<byte[]> hashes) { final String algorithm, final List<String> modules, final List<byte[]> hashes) {
super("ModuleHashes"); super("ModuleHashes");
this.algorithm = algorithm; this.algorithm = algorithm;
this.modules = modules; this.modules = modules;
@ -95,61 +98,72 @@ public final class ModuleHashesAttribute extends Attribute {
} }
/** /**
* Creates an empty attribute that can be used as prototype * Constructs an empty {@link ModuleHashesAttribute}. This object can be passed as a prototype to
* to be passed as argument of the method * the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. */
*/
public ModuleHashesAttribute() { public ModuleHashesAttribute() {
this(null, null, null); this(null, null, null);
} }
@Override @Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, protected Attribute read(
int codeOff, Label[] labels) { final ClassReader classReader,
String hashAlgorithm = cr.readUTF8(off, buf); final int offset,
final int length,
final char[] charBuffer,
final int codeAttributeOffset,
final Label[] labels) {
int currentOffset = offset;
int count = cr.readUnsignedShort(off + 2); String hashAlgorithm = classReader.readUTF8(currentOffset, charBuffer);
ArrayList<String> modules = new ArrayList<String>(count); currentOffset += 2;
ArrayList<byte[]> hashes = new ArrayList<byte[]>(count);
off += 4;
for (int i = 0; i < count; i++) { int numModules = classReader.readUnsignedShort(currentOffset);
String module = cr.readModule(off, buf); currentOffset += 2;
int hashLength = cr.readUnsignedShort(off + 2);
off += 4;
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]; byte[] hash = new byte[hashLength];
for (int j = 0; j < hashLength; j++) { for (int j = 0; j < hashLength; ++j) {
hash[j] = (byte) (cr.readByte(off + j) & 0xff); hash[j] = (byte) (classReader.readByte(currentOffset) & 0xFF);
currentOffset += 1;
} }
off += hashLength; hashList.add(hash);
modules.add(module);
hashes.add(hash);
} }
return new ModuleHashesAttribute(hashAlgorithm, modules, hashes); return new ModuleHashesAttribute(hashAlgorithm, moduleList, hashList);
} }
@Override @Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, protected ByteVector write(
int maxStack, int maxLocals) { final ClassWriter classWriter,
ByteVector v = new ByteVector(); final byte[] code,
int index = cw.newUTF8(algorithm); final int codeLength,
v.putShort(index); final int maxStack,
final int maxLocals) {
int count = (modules == null)? 0: modules.size(); ByteVector byteVector = new ByteVector();
v.putShort(count); byteVector.putShort(classWriter.newUTF8(algorithm));
if (modules == null) {
for(int i = 0; i < count; i++) { byteVector.putShort(0);
String module = modules.get(i); } else {
v.putShort(cw.newModule(module)); int numModules = modules.size();
byteVector.putShort(numModules);
byte[] hash = hashes.get(i); for (int i = 0; i < numModules; ++i) {
v.putShort(hash.length); String module = modules.get(i);
for(byte b: hash) { byte[] hash = hashes.get(i);
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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.ModuleVisitor; import jdk.internal.org.objectweb.asm.ModuleVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
/** /**
* A {@link ModuleVisitor} adapter for type remapping. * A {@link ModuleVisitor} that remaps types with a {@link Remapper}.
* *
* @author Remi Forax * @author Remi Forax
*/ */
public class ModuleRemapper extends ModuleVisitor { public class ModuleRemapper extends ModuleVisitor {
private final Remapper remapper;
public ModuleRemapper(final ModuleVisitor mv, final Remapper remapper) { /** The remapper used to remap the types in the visited module. */
this(Opcodes.ASM6, mv, remapper); 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) { * Constructs a new {@link ModuleRemapper}.
super(api, mv); *
* @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; this.remapper = remapper;
} }
@Override @Override
public void visitMainClass(String mainClass) { public void visitMainClass(final String mainClass) {
super.visitMainClass(remapper.mapType(mainClass)); super.visitMainClass(remapper.mapType(mainClass));
} }
@Override @Override
public void visitPackage(String packaze) { public void visitPackage(final String packaze) {
super.visitPackage(remapper.mapPackageName(packaze)); super.visitPackage(remapper.mapPackageName(packaze));
} }
@Override @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); super.visitRequire(remapper.mapModuleName(module), access, version);
} }
@Override @Override
public void visitExport(String packaze, int access, String... modules) { public void visitExport(final String packaze, final int access, final String... modules) {
String[] newModules = null; String[] remappedModules = null;
if (modules != null) { if (modules != null) {
newModules = new String[modules.length]; remappedModules = new String[modules.length];
for (int i = 0 ; i < modules.length; i++) { for (int i = 0; i < modules.length; ++i) {
newModules[i] = remapper.mapModuleName(modules[i]); remappedModules[i] = remapper.mapModuleName(modules[i]);
} }
} }
super.visitExport(remapper.mapPackageName(packaze), access, newModules); super.visitExport(remapper.mapPackageName(packaze), access, remappedModules);
} }
@Override @Override
public void visitOpen(String packaze, int access, String... modules) { public void visitOpen(final String packaze, final int access, final String... modules) {
String[] newModules = null; String[] remappedModules = null;
if (modules != null) { if (modules != null) {
newModules = new String[modules.length]; remappedModules = new String[modules.length];
for (int i = 0 ; i < modules.length; i++) { for (int i = 0; i < modules.length; ++i) {
newModules[i] = remapper.mapModuleName(modules[i]); remappedModules[i] = remapper.mapModuleName(modules[i]);
} }
} }
super.visitOpen(remapper.mapPackageName(packaze), access, newModules); super.visitOpen(remapper.mapPackageName(packaze), access, remappedModules);
} }
@Override @Override
public void visitUse(String service) { public void visitUse(final String service) {
super.visitUse(remapper.mapType(service)); super.visitUse(remapper.mapType(service));
} }
@Override @Override
public void visitProvide(String service, String... providers) { public void visitProvide(final String service, final String... providers) {
String[] newProviders = new String[providers.length]; String[] remappedProviders = new String[providers.length];
for (int i = 0 ; i < providers.length; i++) { for (int i = 0; i < providers.length; ++i) {
newProviders[i] = remapper.mapType(providers[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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
@ -66,70 +65,79 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
/** /**
* ModuleResolution_attribute. * A ModuleResolution attribute. This attribute is specific to the OpenJDK and may change in the
* This attribute is specific to the OpenJDK and may change in the future. * future.
* *
* @author Remi Forax * @author Remi Forax
*/ */
public final class ModuleResolutionAttribute extends Attribute { public final class ModuleResolutionAttribute extends Attribute {
/** /**
* Resolution state of a module meaning that the module is not available * The resolution state of a module meaning that the module is not available from the class-path
* from the class-path by default. * by default.
*/ */
public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1; public static final int RESOLUTION_DO_NOT_RESOLVE_BY_DEFAULT = 1;
/** /** The resolution state of a module meaning the module is marked as deprecated. */
* Resolution state of a module meaning the module is marked as deprecated.
*/
public static final int RESOLUTION_WARN_DEPRECATED = 2; public static final int RESOLUTION_WARN_DEPRECATED = 2;
/** /**
* 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 and will be removed
* and will be removed in a future release. * in a future release.
*/ */
public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4; public static final int RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL = 4;
/** /**
* Resolution state of a module meaning the module is not yet standardized, * The resolution state of a module meaning the module is not yet standardized, so in incubating
* so in incubating mode. * mode.
*/ */
public static final int RESOLUTION_WARN_INCUBATING = 8; 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; public int resolution;
/** /**
* Creates an attribute with a resolution state value. * Constructs a new {@link ModuleResolutionAttribute}.
* @param resolution the resolution state among *
* {@link #RESOLUTION_WARN_DEPRECATED}, * @param resolution the resolution state of the module. Must be one of {@link
* {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and * #RESOLUTION_WARN_DEPRECATED}, {@link #RESOLUTION_WARN_DEPRECATED_FOR_REMOVAL}, and {@link
* {@link #RESOLUTION_WARN_INCUBATING}. * #RESOLUTION_WARN_INCUBATING}.
*/ */
public ModuleResolutionAttribute(final int resolution) { public ModuleResolutionAttribute(final int resolution) {
super("ModuleResolution"); super("ModuleResolution");
this.resolution = resolution; this.resolution = resolution;
} }
/** /**
* Creates an empty attribute that can be used as prototype * Constructs an empty {@link ModuleResolutionAttribute}. This object can be passed as a prototype
* to be passed as argument of the method * to the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. */
*/
public ModuleResolutionAttribute() { public ModuleResolutionAttribute() {
this(0); this(0);
} }
@Override @Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, protected Attribute read(
int codeOff, Label[] labels) { final ClassReader classReader,
int resolution = cr.readUnsignedShort(off); final int offset,
return new ModuleResolutionAttribute(resolution); final int length,
final char[] charBuffer,
final int codeOffset,
final Label[] labels) {
return new ModuleResolutionAttribute(classReader.readUnsignedShort(offset));
} }
@Override @Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, protected ByteVector write(
int maxStack, int maxLocals) { final ClassWriter classWriter,
ByteVector v = new ByteVector(); final byte[] code,
v.putShort(resolution); final int codeLength,
return v; 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.Attribute; import jdk.internal.org.objectweb.asm.Attribute;
@ -66,45 +65,53 @@ import jdk.internal.org.objectweb.asm.ClassWriter;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
/** /**
* ModuleTarget attribute. * A ModuleTarget attribute. This attribute is specific to the OpenJDK and may change in the future.
* This attribute is specific to the OpenJDK and may change in the future.
* *
* @author Remi Forax * @author Remi Forax
*/ */
public final class ModuleTargetAttribute extends Attribute { public final class ModuleTargetAttribute extends Attribute {
/** The name of the platform on which the module can run. */
public String platform; public String platform;
/** /**
* Creates an attribute with a platform name. * Constructs a new {@link ModuleTargetAttribute}.
* @param platform the platform name on which the module can run. *
*/ * @param platform the name of the platform on which the module can run.
*/
public ModuleTargetAttribute(final String platform) { public ModuleTargetAttribute(final String platform) {
super("ModuleTarget"); super("ModuleTarget");
this.platform = platform; this.platform = platform;
} }
/** /**
* Creates an empty attribute that can be used as prototype * Constructs an empty {@link ModuleTargetAttribute}. This object can be passed as a prototype to
* to be passed as argument of the method * the {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)} method.
* {@link ClassReader#accept(org.objectweb.asm.ClassVisitor, Attribute[], int)}. */
*/
public ModuleTargetAttribute() { public ModuleTargetAttribute() {
this(null); this(null);
} }
@Override @Override
protected Attribute read(ClassReader cr, int off, int len, char[] buf, protected Attribute read(
int codeOff, Label[] labels) { final ClassReader classReader,
String platform = cr.readUTF8(off, buf); final int offset,
return new ModuleTargetAttribute(platform); final int length,
final char[] charBuffer,
final int codeOffset,
final Label[] labels) {
return new ModuleTargetAttribute(classReader.readUTF8(offset, charBuffer));
} }
@Override @Override
protected ByteVector write(ClassWriter cw, byte[] code, int len, protected ByteVector write(
int maxStack, int maxLocals) { final ClassWriter classWriter,
ByteVector v = new ByteVector(); final byte[] code,
int index = (platform == null)? 0: cw.newUTF8(platform); final int codeLength,
v.putShort(index); final int maxStack,
return v; 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; 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.Handle;
import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.Type; import jdk.internal.org.objectweb.asm.Type;
import jdk.internal.org.objectweb.asm.signature.SignatureReader; import jdk.internal.org.objectweb.asm.signature.SignatureReader;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
import jdk.internal.org.objectweb.asm.signature.SignatureWriter; import jdk.internal.org.objectweb.asm.signature.SignatureWriter;
/** /**
* A class responsible for remapping types and names. Subclasses can override * A class responsible for remapping types and names.
* 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>
* *
* @author Eugene Kuleshov * @author Eugene Kuleshov
*/ */
public abstract class Remapper { public abstract class Remapper {
public String mapDesc(String desc) { /**
Type t = Type.getType(desc); * Returns the given descriptor, remapped with {@link #map(String)}.
switch (t.getSort()) { *
case Type.ARRAY: * @param descriptor a type descriptor.
String s = mapDesc(t.getElementType().getDescriptor()); * @return the given descriptor, with its [array element type] internal name remapped with {@link
for (int i = 0; i < t.getDimensions(); ++i) { * #map(String)} (if the descriptor corresponds to an array or object type, otherwise the
s = '[' + s; * descriptor is returned as is).
} */
return s; public String mapDesc(final String descriptor) {
case Type.OBJECT: return mapType(Type.getType(descriptor)).getDescriptor();
String newType = map(t.getInternalName());
if (newType != null) {
return 'L' + newType + ';';
}
}
return desc;
} }
private Type mapType(Type t) { /**
switch (t.getSort()) { * Returns the given {@link Type}, remapped with {@link #map(String)} or {@link
case Type.ARRAY: * #mapMethodDesc(String)}.
String s = mapDesc(t.getElementType().getDescriptor()); *
for (int i = 0; i < t.getDimensions(); ++i) { * @param type a type, which can be a method type.
s = '[' + s; * @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
return Type.getType(s); * is) or, of the type is a method type, with its descriptor remapped with {@link
case Type.OBJECT: * #mapMethodDesc(String)}.
s = map(t.getInternalName()); */
return s != null ? Type.getObjectType(s) : t; private Type mapType(final Type type) {
case Type.METHOD: switch (type.getSort()) {
return Type.getMethodType(mapMethodDesc(t.getDescriptor())); case Type.ARRAY:
StringBuilder remappedDescriptor = new StringBuilder();
for (int i = 0; i < type.getDimensions(); ++i) {
remappedDescriptor.append('[');
}
remappedDescriptor.append(mapType(type.getElementType()).getDescriptor());
return Type.getType(remappedDescriptor.toString());
case Type.OBJECT:
String remappedInternalName = map(type.getInternalName());
return remappedInternalName != null ? Type.getObjectType(remappedInternalName) : type;
case Type.METHOD:
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 null;
} }
return mapType(Type.getObjectType(type)).getInternalName(); return mapType(Type.getObjectType(internalName)).getInternalName();
} }
public String[] mapTypes(String[] types) { /**
String[] newTypes = null; * Returns the given internal names, remapped with {@link #map(String)}.
boolean needMapping = false; *
for (int i = 0; i < types.length; i++) { * @param internalNames the internal names (or array type descriptors) of some (array) classes.
String type = types[i]; * @return the given internal name, remapped with {@link #map(String)}.
String newType = map(type); */
if (newType != null && newTypes == null) { public String[] mapTypes(final String[] internalNames) {
newTypes = new String[types.length]; String[] remappedInternalNames = null;
if (i > 0) { for (int i = 0; i < internalNames.length; ++i) {
System.arraycopy(types, 0, newTypes, 0, 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; remappedInternalNames[i] = remappedInternalName;
}
if (needMapping) {
newTypes[i] = newType == null ? type : newType;
} }
} }
return needMapping ? newTypes : types; return remappedInternalNames != null ? remappedInternalNames : internalNames;
} }
public String mapMethodDesc(String desc) { /**
if ("()V".equals(desc)) { * Returns the given method descriptor, with its argument and return type descriptors remapped
return desc; * 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 stringBuilder = new StringBuilder("(");
StringBuilder sb = new StringBuilder("("); for (Type argumentType : Type.getArgumentTypes(methodDescriptor)) {
for (int i = 0; i < args.length; i++) { stringBuilder.append(mapType(argumentType).getDescriptor());
sb.append(mapDesc(args[i].getDescriptor()));
} }
Type returnType = Type.getReturnType(desc); Type returnType = Type.getReturnType(methodDescriptor);
if (returnType == Type.VOID_TYPE) { if (returnType == Type.VOID_TYPE) {
sb.append(")V"); stringBuilder.append(")V");
return sb.toString(); } else {
stringBuilder.append(')').append(mapType(returnType).getDescriptor());
} }
sb.append(')').append(mapDesc(returnType.getDescriptor())); return stringBuilder.toString();
return sb.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) { if (value instanceof Type) {
return mapType((Type) value); return mapType((Type) value);
} }
if (value instanceof Handle) { if (value instanceof Handle) {
Handle h = (Handle) value; Handle handle = (Handle) value;
return new Handle(h.getTag(), mapType(h.getOwner()), mapMethodName( return new Handle(
h.getOwner(), h.getName(), h.getDesc()), handle.getTag(),
mapMethodDesc(h.getDesc()), h.isInterface()); 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; return value;
} }
/** /**
* @param signature * Returns the given signature, remapped with the {@link SignatureVisitor} returned by {@link
* signature for mapper * #createSignatureRemapper(SignatureVisitor)}.
* @param typeSignature *
* true if signature is a FieldTypeSignature, such as the * @param signature a <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
* signature parameter of the ClassVisitor.visitField or * @param typeSignature whether the given signature is a <i>JavaTypeSignature</i>.
* MethodVisitor.visitLocalVariable methods * @return signature the given signature, remapped with the {@link SignatureVisitor} returned by
* @return signature rewritten as a string * {@link #createSignatureRemapper(SignatureVisitor)}.
*/ */
public String mapSignature(String signature, boolean typeSignature) { public String mapSignature(final String signature, final boolean typeSignature) {
if (signature == null) { if (signature == null) {
return null; return null;
} }
SignatureReader r = new SignatureReader(signature); SignatureReader signatureReader = new SignatureReader(signature);
SignatureWriter w = new SignatureWriter(); SignatureWriter signatureWriter = new SignatureWriter();
SignatureVisitor a = createSignatureRemapper(w); SignatureVisitor signatureRemapper = createSignatureRemapper(signatureWriter);
if (typeSignature) { if (typeSignature) {
r.acceptType(a); signatureReader.acceptType(signatureRemapper);
} else { } else {
r.accept(a); signatureReader.accept(signatureRemapper);
} }
return w.toString(); return signatureWriter.toString();
} }
/** /**
* @deprecated use {@link #createSignatureRemapper} instead. * 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 @Deprecated
protected SignatureVisitor createRemappingSignatureAdapter( protected SignatureVisitor createRemappingSignatureAdapter(
SignatureVisitor v) { final SignatureVisitor signatureVisitor) {
return new SignatureRemapper(v, this); return createSignatureRemapper(signatureVisitor);
}
protected SignatureVisitor createSignatureRemapper(
SignatureVisitor v) {
return createRemappingSignatureAdapter(v);
} }
/** /**
* 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 signatureVisitor the SignatureVisitor the remapper must delegate to.
* @param name * @return the newly created remapper.
* name of the method. */
* @param desc protected SignatureVisitor createSignatureRemapper(final SignatureVisitor signatureVisitor) {
* descriptor of the method. return new SignatureRemapper(signatureVisitor, this);
* @return new name of the method }
*/
public String mapMethodName(String owner, String name, String desc) { /**
* 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; 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 name the name of the method.
* @param desc * @param descriptor the descriptor of the method.
* descriptor of the invokedynamic. * @return the new name of the method.
* @return new invokdynamic name. */
*/ public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
public String mapInvokeDynamicMethodName(String name, String desc) {
return name; 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 owner the internal name of the owner class of the field.
* @param name * @param name the name of the field.
* name of the field * @param descriptor the descriptor of the field.
* @param desc * @return the new name of the field.
* descriptor of the field */
* @return new name of the field. public String mapFieldName(final String owner, final String name, final String descriptor) {
*/
public String mapFieldName(String owner, String name, String desc) {
return name; 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"); public String mapPackageName(final String name) {
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) {
return 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 * @param name the fully qualified name (using dots) of a module.
* @return new name, default implementation is the identity. * @return the new name of the module.
*/ */
public String map(String typeName) { public String mapModuleName(final String name) {
return typeName; 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
@ -73,38 +72,44 @@ public class RemappingAnnotationAdapter extends AnnotationVisitor {
protected final Remapper remapper; protected final Remapper remapper;
public RemappingAnnotationAdapter(final AnnotationVisitor av, public RemappingAnnotationAdapter(
final Remapper remapper) { final AnnotationVisitor annotationVisitor, final Remapper remapper) {
this(Opcodes.ASM6, av, remapper); this(Opcodes.ASM6, annotationVisitor, remapper);
} }
protected RemappingAnnotationAdapter(final int api, protected RemappingAnnotationAdapter(
final AnnotationVisitor av, final Remapper remapper) { final int api, final AnnotationVisitor annotationVisitor, final Remapper remapper) {
super(api, av); super(api, annotationVisitor);
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public void visit(String name, Object value) { public void visit(final String name, final Object value) {
av.visit(name, remapper.mapValue(value)); av.visit(name, remapper.mapValue(value));
} }
@Override @Override
public void visitEnum(String name, String desc, String value) { public void visitEnum(final String name, final String descriptor, final String value) {
av.visitEnum(name, remapper.mapDesc(desc), value); av.visitEnum(name, remapper.mapDesc(descriptor), value);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String name, String desc) { public AnnotationVisitor visitAnnotation(final String name, final String descriptor) {
AnnotationVisitor v = av.visitAnnotation(name, remapper.mapDesc(desc)); AnnotationVisitor annotationVisitor = av.visitAnnotation(name, remapper.mapDesc(descriptor));
return v == null ? null : (v == av ? this return annotationVisitor == null
: new RemappingAnnotationAdapter(v, remapper)); ? null
: (annotationVisitor == av
? this
: new RemappingAnnotationAdapter(annotationVisitor, remapper));
} }
@Override @Override
public AnnotationVisitor visitArray(String name) { public AnnotationVisitor visitArray(final String name) {
AnnotationVisitor v = av.visitArray(name); AnnotationVisitor annotationVisitor = av.visitArray(name);
return v == null ? null : (v == av ? this return annotationVisitor == null
: new RemappingAnnotationAdapter(v, remapper)); ? 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
@ -80,93 +79,119 @@ public class RemappingClassAdapter extends ClassVisitor {
protected String className; protected String className;
public RemappingClassAdapter(final ClassVisitor cv, final Remapper remapper) { public RemappingClassAdapter(final ClassVisitor classVisitor, final Remapper remapper) {
this(Opcodes.ASM6, cv, remapper); this(Opcodes.ASM6, classVisitor, remapper);
} }
protected RemappingClassAdapter(final int api, final ClassVisitor cv, protected RemappingClassAdapter(
final Remapper remapper) { final int api, final ClassVisitor classVisitor, final Remapper remapper) {
super(api, cv); super(api, classVisitor);
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public void visit(int version, int access, String name, String signature, public void visit(
String superName, String[] interfaces) { final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
this.className = name; this.className = name;
super.visit(version, access, remapper.mapType(name), remapper super.visit(
.mapSignature(signature, false), remapper.mapType(superName), version,
access,
remapper.mapType(name),
remapper.mapSignature(signature, false),
remapper.mapType(superName),
interfaces == null ? null : remapper.mapTypes(interfaces)); interfaces == null ? null : remapper.mapTypes(interfaces));
} }
@Override @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"); throw new RuntimeException("RemappingClassAdapter is deprecated, use ClassRemapper instead");
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor =
visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return av == null ? null : createRemappingAnnotationAdapter(av); return annotationVisitor == null ? null : createRemappingAnnotationAdapter(annotationVisitor);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? null : createRemappingAnnotationAdapter(av); return annotationVisitor == null ? null : createRemappingAnnotationAdapter(annotationVisitor);
} }
@Override @Override
public FieldVisitor visitField(int access, String name, String desc, public FieldVisitor visitField(
String signature, Object value) { final int access,
FieldVisitor fv = super.visitField(access, final String name,
remapper.mapFieldName(className, name, desc), final String descriptor,
remapper.mapDesc(desc), remapper.mapSignature(signature, true), final String signature,
remapper.mapValue(value)); final Object value) {
return fv == null ? null : createRemappingFieldAdapter(fv); FieldVisitor fieldVisitor =
super.visitField(
access,
remapper.mapFieldName(className, name, descriptor),
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
remapper.mapValue(value));
return fieldVisitor == null ? null : createRemappingFieldAdapter(fieldVisitor);
} }
@Override @Override
public MethodVisitor visitMethod(int access, String name, String desc, public MethodVisitor visitMethod(
String signature, String[] exceptions) { final int access,
String newDesc = remapper.mapMethodDesc(desc); final String name,
MethodVisitor mv = super.visitMethod(access, remapper.mapMethodName( final String descriptor,
className, name, desc), newDesc, remapper.mapSignature( final String signature,
signature, false), final String[] exceptions) {
exceptions == null ? null : remapper.mapTypes(exceptions)); String newDescriptor = remapper.mapMethodDesc(descriptor);
return mv == null ? null : createRemappingMethodAdapter(access, MethodVisitor methodVisitor =
newDesc, mv); super.visitMethod(
access,
remapper.mapMethodName(className, name, descriptor),
newDescriptor,
remapper.mapSignature(signature, false),
exceptions == null ? null : remapper.mapTypes(exceptions));
return methodVisitor == null
? null
: createRemappingMethodAdapter(access, newDescriptor, methodVisitor);
} }
@Override @Override
public void visitInnerClass(String name, String outerName, public void visitInnerClass(
String innerName, int access) { final String name, final String outerName, final String innerName, final int access) {
// TODO should innerName be changed? super.visitInnerClass(
super.visitInnerClass(remapper.mapType(name), outerName == null ? null remapper.mapType(name),
: remapper.mapType(outerName), innerName, access); outerName == null ? null : remapper.mapType(outerName),
innerName,
access);
} }
@Override @Override
public void visitOuterClass(String owner, String name, String desc) { public void visitOuterClass(final String owner, final String name, final String descriptor) {
super.visitOuterClass(remapper.mapType(owner), name == null ? null super.visitOuterClass(
: remapper.mapMethodName(owner, name, desc), remapper.mapType(owner),
desc == null ? null : remapper.mapMethodDesc(desc)); name == null ? null : remapper.mapMethodName(owner, name, descriptor),
descriptor == null ? null : remapper.mapMethodDesc(descriptor));
} }
protected FieldVisitor createRemappingFieldAdapter(FieldVisitor fv) { protected FieldVisitor createRemappingFieldAdapter(final FieldVisitor fieldVisitor) {
return new RemappingFieldAdapter(fv, remapper); return new RemappingFieldAdapter(fieldVisitor, remapper);
} }
protected MethodVisitor createRemappingMethodAdapter(int access, protected MethodVisitor createRemappingMethodAdapter(
String newDesc, MethodVisitor mv) { final int access, final String newDescriptor, final MethodVisitor methodVisitior) {
return new RemappingMethodAdapter(access, newDesc, mv, remapper); return new RemappingMethodAdapter(access, newDescriptor, methodVisitior, remapper);
} }
protected AnnotationVisitor createRemappingAnnotationAdapter( protected AnnotationVisitor createRemappingAnnotationAdapter(final AnnotationVisitor av) {
AnnotationVisitor av) {
return new RemappingAnnotationAdapter(av, remapper); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
@ -75,28 +74,31 @@ public class RemappingFieldAdapter extends FieldVisitor {
private final Remapper remapper; private final Remapper remapper;
public RemappingFieldAdapter(final FieldVisitor fv, final Remapper remapper) { public RemappingFieldAdapter(final FieldVisitor fieldVisitor, final Remapper remapper) {
this(Opcodes.ASM6, fv, remapper); this(Opcodes.ASM6, fieldVisitor, remapper);
} }
protected RemappingFieldAdapter(final int api, final FieldVisitor fv, protected RemappingFieldAdapter(
final Remapper remapper) { final int api, final FieldVisitor fieldVisitor, final Remapper remapper) {
super(api, fv); super(api, fieldVisitor);
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = fv.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor = fv.visitAnnotation(remapper.mapDesc(descriptor), visible);
visible); return annotationVisitor == null
return av == null ? null : new RemappingAnnotationAdapter(av, remapper); ? null
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? null : new RemappingAnnotationAdapter(av, remapper); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.AnnotationVisitor; import jdk.internal.org.objectweb.asm.AnnotationVisitor;
@ -77,105 +76,130 @@ public class RemappingMethodAdapter extends LocalVariablesSorter {
protected final Remapper remapper; protected final Remapper remapper;
public RemappingMethodAdapter(final int access, final String desc, public RemappingMethodAdapter(
final MethodVisitor mv, final Remapper remapper) { final int access,
this(Opcodes.ASM6, access, desc, mv, remapper); final String descriptor,
final MethodVisitor methodVisitor,
final Remapper remapper) {
this(Opcodes.ASM6, access, descriptor, methodVisitor, remapper);
} }
protected RemappingMethodAdapter(final int api, final int access, protected RemappingMethodAdapter(
final String desc, final MethodVisitor mv, final Remapper remapper) { final int api,
super(api, access, desc, mv); final int access,
final String descriptor,
final MethodVisitor methodVisitor,
final Remapper remapper) {
super(api, access, descriptor, methodVisitor);
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public AnnotationVisitor visitAnnotationDefault() { public AnnotationVisitor visitAnnotationDefault() {
AnnotationVisitor av = super.visitAnnotationDefault(); AnnotationVisitor annotationVisitor = super.visitAnnotationDefault();
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) { public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitAnnotation(remapper.mapDesc(desc), AnnotationVisitor annotationVisitor =
visible); super.visitAnnotation(remapper.mapDesc(descriptor), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitTypeAnnotation(int typeRef, public AnnotationVisitor visitTypeAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTypeAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTypeAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public AnnotationVisitor visitParameterAnnotation(int parameter, public AnnotationVisitor visitParameterAnnotation(
String desc, boolean visible) { final int parameter, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitParameterAnnotation(parameter, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitParameterAnnotation(parameter, remapper.mapDesc(descriptor), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public void visitFrame(int type, int nLocal, Object[] local, int nStack, public void visitFrame(
Object[] stack) { final int type,
super.visitFrame(type, nLocal, remapEntries(nLocal, local), nStack, final int numLocal,
remapEntries(nStack, stack)); 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) { private Object[] remapEntries(final int numTypes, final Object[] entries) {
if (entries != null) { if (entries == null) {
for (int i = 0; i < n; i++) { return entries;
if (entries[i] instanceof String) { }
Object[] newEntries = new Object[n]; Object[] remappedEntries = null;
if (i > 0) { for (int i = 0; i < numTypes; ++i) {
System.arraycopy(entries, 0, newEntries, 0, i); if (entries[i] instanceof String) {
} if (remappedEntries == null) {
do { remappedEntries = new Object[numTypes];
Object t = entries[i]; System.arraycopy(entries, 0, remappedEntries, 0, numTypes);
newEntries[i++] = t instanceof String ? remapper
.mapType((String) t) : t;
} while (i < n);
return newEntries;
} }
remappedEntries[i] = remapper.mapType((String) entries[i]);
} }
} }
return entries; return remappedEntries == null ? entries : remappedEntries;
} }
@Override @Override
public void visitFieldInsn(int opcode, String owner, String name, public void visitFieldInsn(
String desc) { final int opcode, final String owner, final String name, final String descriptor) {
super.visitFieldInsn(opcode, remapper.mapType(owner), super.visitFieldInsn(
remapper.mapFieldName(owner, name, desc), opcode,
remapper.mapDesc(desc)); remapper.mapType(owner),
remapper.mapFieldName(owner, name, descriptor),
remapper.mapDesc(descriptor));
} }
@Deprecated @Deprecated
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc) { final int opcode, final String owner, final String name, final String descriptor) {
if (api >= Opcodes.ASM5) { if (api >= Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc); super.visitMethodInsn(opcode, owner, name, descriptor);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, doVisitMethodInsn(opcode, owner, name, descriptor, opcode == Opcodes.INVOKEINTERFACE);
opcode == Opcodes.INVOKEINTERFACE);
} }
@Override @Override
public void visitMethodInsn(final int opcode, final String owner, public void visitMethodInsn(
final String name, final String desc, final boolean itf) { final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
if (api < Opcodes.ASM5) { if (api < Opcodes.ASM5) {
super.visitMethodInsn(opcode, owner, name, desc, itf); super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
return; return;
} }
doVisitMethodInsn(opcode, owner, name, desc, itf); doVisitMethodInsn(opcode, owner, name, descriptor, isInterface);
} }
private void doVisitMethodInsn(int opcode, String owner, String name, private void doVisitMethodInsn(
String desc, boolean itf) { final int opcode,
final String owner,
final String name,
final String descriptor,
final boolean isInterface) {
// Calling super.visitMethodInsn requires to call the correct version // Calling super.visitMethodInsn requires to call the correct version
// depending on this.api (otherwise infinite loops can occur). To // depending on this.api (otherwise infinite loops can occur). To
// simplify and to make it easier to automatically remove the backward // 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 // IMPORTANT: THIS ASSUMES THAT visitMethodInsn IS NOT OVERRIDDEN IN
// LocalVariableSorter. // LocalVariableSorter.
if (mv != null) { if (mv != null) {
mv.visitMethodInsn(opcode, remapper.mapType(owner), mv.visitMethodInsn(
remapper.mapMethodName(owner, name, desc), opcode,
remapper.mapMethodDesc(desc), itf); remapper.mapType(owner),
remapper.mapMethodName(owner, name, descriptor),
remapper.mapMethodDesc(descriptor),
isInterface);
} }
} }
@Override @Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, public void visitInvokeDynamicInsn(
Object... bsmArgs) { final String name,
for (int i = 0; i < bsmArgs.length; i++) { final String descriptor,
bsmArgs[i] = remapper.mapValue(bsmArgs[i]); final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
for (int i = 0; i < bootstrapMethodArguments.length; i++) {
bootstrapMethodArguments[i] = remapper.mapValue(bootstrapMethodArguments[i]);
} }
super.visitInvokeDynamicInsn( super.visitInvokeDynamicInsn(
remapper.mapInvokeDynamicMethodName(name, desc), remapper.mapInvokeDynamicMethodName(name, descriptor),
remapper.mapMethodDesc(desc), (Handle) remapper.mapValue(bsm), remapper.mapMethodDesc(descriptor),
bsmArgs); (Handle) remapper.mapValue(bootstrapMethodHandle),
bootstrapMethodArguments);
} }
@Override @Override
public void visitTypeInsn(int opcode, String type) { public void visitTypeInsn(final int opcode, final String type) {
super.visitTypeInsn(opcode, remapper.mapType(type)); super.visitTypeInsn(opcode, remapper.mapType(type));
} }
@Override @Override
public void visitLdcInsn(Object cst) { public void visitLdcInsn(final Object value) {
super.visitLdcInsn(remapper.mapValue(cst)); super.visitLdcInsn(remapper.mapValue(value));
} }
@Override @Override
public void visitMultiANewArrayInsn(String desc, int dims) { public void visitMultiANewArrayInsn(final String descriptor, final int numDimensions) {
super.visitMultiANewArrayInsn(remapper.mapDesc(desc), dims); super.visitMultiANewArrayInsn(remapper.mapDesc(descriptor), numDimensions);
} }
@Override @Override
public AnnotationVisitor visitInsnAnnotation(int typeRef, public AnnotationVisitor visitInsnAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitInsnAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitInsnAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public void visitTryCatchBlock(Label start, Label end, Label handler, public void visitTryCatchBlock(
String type) { final Label start, final Label end, final Label handler, final String type) {
super.visitTryCatchBlock(start, end, handler, type == null ? null super.visitTryCatchBlock(start, end, handler, type == null ? null : remapper.mapType(type));
: remapper.mapType(type));
} }
@Override @Override
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, public AnnotationVisitor visitTryCatchAnnotation(
TypePath typePath, String desc, boolean visible) { final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
AnnotationVisitor av = super.visitTryCatchAnnotation(typeRef, typePath, AnnotationVisitor annotationVisitor =
remapper.mapDesc(desc), visible); super.visitTryCatchAnnotation(typeRef, typePath, remapper.mapDesc(descriptor), visible);
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); return annotationVisitor == null
? annotationVisitor
: new RemappingAnnotationAdapter(annotationVisitor, remapper);
} }
@Override @Override
public void visitLocalVariable(String name, String desc, String signature, public void visitLocalVariable(
Label start, Label end, int index) { final String name,
super.visitLocalVariable(name, remapper.mapDesc(desc), final String descriptor,
remapper.mapSignature(signature, true), start, end, index); 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 @Override
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, public AnnotationVisitor visitLocalVariableAnnotation(
TypePath typePath, Label[] start, Label[] end, int[] index, final int typeRef,
String desc, boolean visible) { final TypePath typePath,
AnnotationVisitor av = super.visitLocalVariableAnnotation(typeRef, final Label[] start,
typePath, start, end, index, remapper.mapDesc(desc), visible); final Label[] end,
return av == null ? av : new RemappingAnnotationAdapter(av, remapper); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
@ -71,116 +70,118 @@ import jdk.internal.org.objectweb.asm.signature.SignatureVisitor;
@Deprecated @Deprecated
public class RemappingSignatureAdapter extends SignatureVisitor { public class RemappingSignatureAdapter extends SignatureVisitor {
private final SignatureVisitor v; private final SignatureVisitor signatureVisitor;
private final Remapper remapper; private final Remapper remapper;
private String className; private String className;
public RemappingSignatureAdapter(final SignatureVisitor v, public RemappingSignatureAdapter(
final Remapper remapper) { final SignatureVisitor signatureVisitor, final Remapper remapper) {
this(Opcodes.ASM6, v, remapper); this(Opcodes.ASM6, signatureVisitor, remapper);
} }
protected RemappingSignatureAdapter(final int api, protected RemappingSignatureAdapter(
final SignatureVisitor v, final Remapper remapper) { final int api, final SignatureVisitor signatureVisitor, final Remapper remapper) {
super(api); super(api);
this.v = v; this.signatureVisitor = signatureVisitor;
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public void visitClassType(String name) { public void visitClassType(final String name) {
className = name; className = name;
v.visitClassType(remapper.mapType(name)); signatureVisitor.visitClassType(remapper.mapType(name));
} }
@Override @Override
public void visitInnerClassType(String name) { public void visitInnerClassType(final String name) {
String remappedOuter = remapper.mapType(className) + '$'; String remappedOuter = remapper.mapType(className) + '$';
className = className + '$' + name; className = className + '$' + name;
String remappedName = remapper.mapType(className); String remappedName = remapper.mapType(className);
int index = remappedName.startsWith(remappedOuter) ? remappedOuter int index =
.length() : remappedName.lastIndexOf('$') + 1; remappedName.startsWith(remappedOuter)
v.visitInnerClassType(remappedName.substring(index)); ? remappedOuter.length()
: remappedName.lastIndexOf('$') + 1;
signatureVisitor.visitInnerClassType(remappedName.substring(index));
} }
@Override @Override
public void visitFormalTypeParameter(String name) { public void visitFormalTypeParameter(final String name) {
v.visitFormalTypeParameter(name); signatureVisitor.visitFormalTypeParameter(name);
} }
@Override @Override
public void visitTypeVariable(String name) { public void visitTypeVariable(final String name) {
v.visitTypeVariable(name); signatureVisitor.visitTypeVariable(name);
} }
@Override @Override
public SignatureVisitor visitArrayType() { public SignatureVisitor visitArrayType() {
v.visitArrayType(); signatureVisitor.visitArrayType();
return this; return this;
} }
@Override @Override
public void visitBaseType(char descriptor) { public void visitBaseType(final char descriptor) {
v.visitBaseType(descriptor); signatureVisitor.visitBaseType(descriptor);
} }
@Override @Override
public SignatureVisitor visitClassBound() { public SignatureVisitor visitClassBound() {
v.visitClassBound(); signatureVisitor.visitClassBound();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitExceptionType() { public SignatureVisitor visitExceptionType() {
v.visitExceptionType(); signatureVisitor.visitExceptionType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitInterface() { public SignatureVisitor visitInterface() {
v.visitInterface(); signatureVisitor.visitInterface();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitInterfaceBound() { public SignatureVisitor visitInterfaceBound() {
v.visitInterfaceBound(); signatureVisitor.visitInterfaceBound();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitParameterType() { public SignatureVisitor visitParameterType() {
v.visitParameterType(); signatureVisitor.visitParameterType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitReturnType() { public SignatureVisitor visitReturnType() {
v.visitReturnType(); signatureVisitor.visitReturnType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitSuperclass() { public SignatureVisitor visitSuperclass() {
v.visitSuperclass(); signatureVisitor.visitSuperclass();
return this; return this;
} }
@Override @Override
public void visitTypeArgument() { public void visitTypeArgument() {
v.visitTypeArgument(); signatureVisitor.visitTypeArgument();
} }
@Override @Override
public SignatureVisitor visitTypeArgument(char wildcard) { public SignatureVisitor visitTypeArgument(final char wildcard) {
v.visitTypeArgument(wildcard); signatureVisitor.visitTypeArgument(wildcard);
return this; return this;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
v.visitEnd(); signatureVisitor.visitEnd();
} }
} }

View file

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

View file

@ -56,133 +56,149 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; 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.Opcodes;
import jdk.internal.org.objectweb.asm.signature.SignatureVisitor; 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 * @author Eugene Kuleshov
*/ */
public class SignatureRemapper extends SignatureVisitor { public class SignatureRemapper extends SignatureVisitor {
private final SignatureVisitor v; private final SignatureVisitor signatureVisitor;
private final Remapper remapper; 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); super(api);
this.v = v; this.signatureVisitor = signatureVisitor;
this.remapper = remapper; this.remapper = remapper;
} }
@Override @Override
public void visitClassType(String name) { public void visitClassType(final String name) {
classNames.push(name); classNames.add(name);
v.visitClassType(remapper.mapType(name)); signatureVisitor.visitClassType(remapper.mapType(name));
} }
@Override @Override
public void visitInnerClassType(String name) { public void visitInnerClassType(final String name) {
String outerClassName = classNames.pop(); String outerClassName = classNames.remove(classNames.size() - 1);
String className = outerClassName + '$' + name; String className = outerClassName + '$' + name;
classNames.push(className); classNames.add(className);
String remappedOuter = remapper.mapType(outerClassName) + '$'; String remappedOuter = remapper.mapType(outerClassName) + '$';
String remappedName = remapper.mapType(className); String remappedName = remapper.mapType(className);
int index = remappedName.startsWith(remappedOuter) ? remappedOuter int index =
.length() : remappedName.lastIndexOf('$') + 1; remappedName.startsWith(remappedOuter)
v.visitInnerClassType(remappedName.substring(index)); ? remappedOuter.length()
: remappedName.lastIndexOf('$') + 1;
signatureVisitor.visitInnerClassType(remappedName.substring(index));
} }
@Override @Override
public void visitFormalTypeParameter(String name) { public void visitFormalTypeParameter(final String name) {
v.visitFormalTypeParameter(name); signatureVisitor.visitFormalTypeParameter(name);
} }
@Override @Override
public void visitTypeVariable(String name) { public void visitTypeVariable(final String name) {
v.visitTypeVariable(name); signatureVisitor.visitTypeVariable(name);
} }
@Override @Override
public SignatureVisitor visitArrayType() { public SignatureVisitor visitArrayType() {
v.visitArrayType(); signatureVisitor.visitArrayType();
return this; return this;
} }
@Override @Override
public void visitBaseType(char descriptor) { public void visitBaseType(final char descriptor) {
v.visitBaseType(descriptor); signatureVisitor.visitBaseType(descriptor);
} }
@Override @Override
public SignatureVisitor visitClassBound() { public SignatureVisitor visitClassBound() {
v.visitClassBound(); signatureVisitor.visitClassBound();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitExceptionType() { public SignatureVisitor visitExceptionType() {
v.visitExceptionType(); signatureVisitor.visitExceptionType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitInterface() { public SignatureVisitor visitInterface() {
v.visitInterface(); signatureVisitor.visitInterface();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitInterfaceBound() { public SignatureVisitor visitInterfaceBound() {
v.visitInterfaceBound(); signatureVisitor.visitInterfaceBound();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitParameterType() { public SignatureVisitor visitParameterType() {
v.visitParameterType(); signatureVisitor.visitParameterType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitReturnType() { public SignatureVisitor visitReturnType() {
v.visitReturnType(); signatureVisitor.visitReturnType();
return this; return this;
} }
@Override @Override
public SignatureVisitor visitSuperclass() { public SignatureVisitor visitSuperclass() {
v.visitSuperclass(); signatureVisitor.visitSuperclass();
return this; return this;
} }
@Override @Override
public void visitTypeArgument() { public void visitTypeArgument() {
v.visitTypeArgument(); signatureVisitor.visitTypeArgument();
} }
@Override @Override
public SignatureVisitor visitTypeArgument(char wildcard) { public SignatureVisitor visitTypeArgument(final char wildcard) {
v.visitTypeArgument(wildcard); signatureVisitor.visitTypeArgument(wildcard);
return this; return this;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
v.visitEnd(); signatureVisitor.visitEnd();
classNames.pop(); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import java.util.Collections; import java.util.Collections;
@ -71,34 +70,57 @@ public class SimpleRemapper extends Remapper {
private final Map<String, String> mapping; 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; 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); this.mapping = Collections.singletonMap(oldName, newName);
} }
@Override @Override
public String mapMethodName(String owner, String name, String desc) { public String mapMethodName(final String owner, final String name, final String descriptor) {
String s = map(owner + '.' + name + desc); String remappedName = map(owner + '.' + name + descriptor);
return s == null ? name : s; return remappedName == null ? name : remappedName;
} }
@Override @Override
public String mapInvokeDynamicMethodName(String name, String desc) { public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
String s = map('.' + name + desc); String remappedName = map('.' + name + descriptor);
return s == null ? name : s; return remappedName == null ? name : remappedName;
} }
@Override @Override
public String mapFieldName(String owner, String name, String desc) { public String mapFieldName(final String owner, final String name, final String descriptor) {
String s = map(owner + '.' + name); String remappedName = map(owner + '.' + name);
return s == null ? name : s; return remappedName == null ? name : remappedName;
} }
@Override @Override
public String map(String key) { public String map(final String key) {
return mapping.get(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; 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 * @author Eric Bruneton
*/ */
public class StaticInitMerger extends ClassVisitor { 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) { * Constructs a new {@link StaticInitMerger}.
super(api, cv); *
this.prefix = prefix; * @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 @Override
public void visit(final int version, final int access, final String name, public void visit(
final String signature, final String superName, final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) { final String[] interfaces) {
cv.visit(version, access, name, signature, superName, interfaces); super.visit(version, access, name, signature, superName, interfaces);
this.name = name; this.owner = name;
} }
@Override @Override
public MethodVisitor visitMethod(final int access, final String name, public MethodVisitor visitMethod(
final String desc, final String signature, final String[] exceptions) { final int access,
MethodVisitor mv; final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
MethodVisitor methodVisitor;
if ("<clinit>".equals(name)) { if ("<clinit>".equals(name)) {
int a = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC; int newAccess = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC;
String n = prefix + counter++; String newName = renamedClinitMethodPrefix + numClinitMethods++;
mv = cv.visitMethod(a, n, desc, signature, exceptions); methodVisitor = super.visitMethod(newAccess, newName, descriptor, signature, exceptions);
if (clinit == null) { if (mergedClinitVisitor == null) {
clinit = cv.visitMethod(a, name, desc, null, null); mergedClinitVisitor = super.visitMethod(newAccess, name, descriptor, null, null);
} }
clinit.visitMethodInsn(Opcodes.INVOKESTATIC, this.name, n, desc, mergedClinitVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, owner, newName, descriptor, false);
false);
} else { } else {
mv = cv.visitMethod(access, name, desc, signature, exceptions); methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions);
} }
return mv; return methodVisitor;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
if (clinit != null) { if (mergedClinitVisitor != null) {
clinit.visitInsn(Opcodes.RETURN); mergedClinitVisitor.visitInsn(Opcodes.RETURN);
clinit.visitMaxs(0, 0); mergedClinitVisitor.visitMaxs(0, 0);
} }
cv.visitEnd(); super.visitEnd();
} }
} }

View file

@ -70,17 +70,13 @@ import jdk.internal.org.objectweb.asm.Label;
public interface TableSwitchGenerator { public interface TableSwitchGenerator {
/** /**
* Generates the code for a switch case. * Generates the code for a switch case.
* *
* @param key * @param key the switch case key.
* the switch case key. * @param end a label that corresponds to the end of the switch statement.
* @param end */
* a label that corresponds to the end of the switch statement.
*/
void generateCase(int key, Label end); void generateCase(int key, Label end);
/** /** Generates the code for the default switch case. */
* Generates the code for the default switch case.
*/
void generateDefault(); void generateDefault();
} }

View file

@ -56,65 +56,89 @@
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.commons; package jdk.internal.org.objectweb.asm.commons;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.tree.MethodNode; import jdk.internal.org.objectweb.asm.tree.MethodNode;
import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode; import jdk.internal.org.objectweb.asm.tree.TryCatchBlockNode;
/** /**
* A {@link MethodVisitor} adapter to sort the exception handlers. The handlers * A {@link MethodVisitor} adapter to sort the exception handlers. The handlers are sorted in a
* are sorted in a method innermost-to-outermost. This allows the programmer to * method innermost-to-outermost. This allows the programmer to add handlers without worrying about
* add handlers without worrying about ordering them correctly with respect to * ordering them correctly with respect to existing, in-code handlers.
* existing, in-code handlers.
* *
* Behavior is only defined for properly-nested handlers. If any "try" blocks * <p>Behavior is only defined for properly-nested handlers. If any "try" blocks overlap (something
* overlap (something that isn't possible in Java code) then this may not do * that isn't possible in Java code) then this may not do what you want. In fact, this adapter just
* what you want. In fact, this adapter just sorts by the length of the "try" * sorts by the length of the "try" block, taking advantage of the fact that a given try block must
* block, taking advantage of the fact that a given try block must be larger * be larger than any block it contains).
* than any block it contains).
* *
* @author Adrian Sampson * @author Adrian Sampson
*/ */
public class TryCatchBlockSorter extends MethodNode { 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) { 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, protected TryCatchBlockSorter(
final int access, final String name, final String desc, final int api,
final String signature, final String[] exceptions) { final MethodVisitor methodVisitor,
super(api, access, name, desc, signature, exceptions); final int access,
this.mv = mv; final String name,
final String descriptor,
final String signature,
final String[] exceptions) {
super(api, access, name, descriptor, signature, exceptions);
this.mv = methodVisitor;
} }
@Override @Override
public void visitEnd() { public void visitEnd() {
// Compares TryCatchBlockNodes by the length of their "try" block. // Sort the TryCatchBlockNode elements by the length of their "try" block.
Comparator<TryCatchBlockNode> comp = new Comparator<TryCatchBlockNode>() { Collections.sort(
tryCatchBlocks,
new Comparator<TryCatchBlockNode>() {
public int compare(TryCatchBlockNode t1, TryCatchBlockNode t2) { @Override
int len1 = blockLength(t1); public int compare(
int len2 = blockLength(t2); final TryCatchBlockNode tryCatchBlockNode1,
return len1 - len2; final TryCatchBlockNode tryCatchBlockNode2) {
} return blockLength(tryCatchBlockNode1) - blockLength(tryCatchBlockNode2);
}
private int blockLength(TryCatchBlockNode block) { private int blockLength(final TryCatchBlockNode tryCatchBlockNode) {
int startidx = instructions.indexOf(block.start); int startIndex = instructions.indexOf(tryCatchBlockNode.start);
int endidx = instructions.indexOf(block.end); int endIndex = instructions.indexOf(tryCatchBlockNode.end);
return endidx - startidx; return endIndex - startIndex;
} }
}; });
Collections.sort(tryCatchBlocks, comp); // Update the 'target' of each try catch block annotation.
// Updates the 'target' of each try catch block annotation.
for (int i = 0; i < tryCatchBlocks.size(); ++i) { for (int i = 0; i < tryCatchBlocks.size(); ++i) {
tryCatchBlocks.get(i).updateIndex(i); tryCatchBlocks.get(i).updateIndex(i);
} }

View file

@ -59,199 +59,225 @@
package jdk.internal.org.objectweb.asm.signature; package jdk.internal.org.objectweb.asm.signature;
/** /**
* A type signature parser to make a signature visitor visit an existing * A parser for signature literals, as defined in the Java Virtual Machine Specification (JVMS), to
* signature. * 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 Thomas Hallgren
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public class SignatureReader { public class SignatureReader {
/** /** The JVMS signature to be read. */
* The signature to be read. private final String signatureValue;
*/
private final String signature;
/** /**
* Constructs a {@link SignatureReader} for the given signature. * Constructs a {@link SignatureReader} for the given signature.
* *
* @param signature * @param signature A <i>JavaTypeSignature</i>, <i>ClassSignature</i> or <i>MethodSignature</i>.
* A <i>ClassSignature</i>, <i>MethodTypeSignature</i>, or */
* <i>FieldTypeSignature</i>.
*/
public SignatureReader(final String signature) { public SignatureReader(final String signature) {
this.signature = signature; this.signatureValue = signature;
} }
/** /**
* Makes the given visitor visit the signature of this * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
* {@link SignatureReader}. This signature is the one specified in the * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
* constructor (see {@link #SignatureReader(String) SignatureReader}). This * be called on a {@link SignatureReader} that was created using a <i>ClassSignature</i> (such as
* method is intended to be called on a {@link SignatureReader} that was * the <code>signature</code> parameter of the {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit}
* created using a <i>ClassSignature</i> (such as the <code>signature</code> * method) or a <i>MethodSignature</i> (such as the <code>signature</code> parameter of the {@link
* parameter of the {@link jdk.internal.org.objectweb.asm.ClassVisitor#visit * jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod} method).
* ClassVisitor.visit} method) or a <i>MethodTypeSignature</i> (such as the *
* <code>signature</code> parameter of the * @param signatureVistor the visitor that must visit this signature.
* {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitMethod */
* ClassVisitor.visitMethod} method). public void accept(final SignatureVisitor signatureVistor) {
* String signature = this.signatureValue;
* @param v int length = signature.length();
* the visitor that must visit this signature. int offset; // Current offset in the parsed signature (parsed from left to right).
*/ char currentChar; // The signature character at 'offset', or just before.
public void accept(final SignatureVisitor v) {
String signature = this.signature;
int len = signature.length();
int pos;
char c;
// 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) == '<') { 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 { do {
int end = signature.indexOf(':', pos); // The formal type parameter name is everything between offset - 1 and the first ':'.
v.visitFormalTypeParameter(signature.substring(pos - 1, end)); int classBoundStartOffset = signature.indexOf(':', offset);
pos = end + 1; signatureVistor.visitFormalTypeParameter(
signature.substring(offset - 1, classBoundStartOffset));
c = signature.charAt(pos); // If the character after the ':' class bound marker is not the start of a
if (c == 'L' || c == '[' || c == 'T') { // ReferenceTypeSignature, it means the class bound is empty (which is a valid case).
pos = parseType(signature, pos, v.visitClassBound()); offset = classBoundStartOffset + 1;
currentChar = signature.charAt(offset);
if (currentChar == 'L' || currentChar == '[' || currentChar == 'T') {
offset = parseType(signature, offset, signatureVistor.visitClassBound());
} }
while ((c = signature.charAt(pos++)) == ':') { // While the character after the class bound or after the last parsed interface bound
pos = parseType(signature, pos, v.visitInterfaceBound()); // 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 { } else {
pos = 0; offset = 0;
} }
if (signature.charAt(pos) == '(') { // If the (optional) TypeParameters is followed by '(' this means we are parsing a
pos++; // MethodSignature, which has JavaTypeSignature type inside parentheses, followed by a Result
while (signature.charAt(pos) != ')') { // type and optional ThrowsSignature types.
pos = parseType(signature, pos, v.visitParameterType()); if (signature.charAt(offset) == '(') {
offset++;
while (signature.charAt(offset) != ')') {
offset = parseType(signature, offset, signatureVistor.visitParameterType());
} }
pos = parseType(signature, pos + 1, v.visitReturnType()); // Use offset + 1 to skip ')'.
while (pos < len) { offset = parseType(signature, offset + 1, signatureVistor.visitReturnType());
pos = parseType(signature, pos + 1, v.visitExceptionType()); while (offset < length) {
// Use offset + 1 to skip the first character of a ThrowsSignature, i.e. '^'.
offset = parseType(signature, offset + 1, signatureVistor.visitExceptionType());
} }
} else { } else {
pos = parseType(signature, pos, v.visitSuperclass()); // Otherwise we are parsing a ClassSignature (by hypothesis on the method input), which has
while (pos < len) { // one or more ClassTypeSignature for the super class and the implemented interfaces.
pos = parseType(signature, pos, v.visitInterface()); offset = parseType(signature, offset, signatureVistor.visitSuperclass());
while (offset < length) {
offset = parseType(signature, offset, signatureVistor.visitInterface());
} }
} }
} }
/** /**
* Makes the given visitor visit the signature of this * Makes the given visitor visit the signature of this {@link SignatureReader}. This signature is
* {@link SignatureReader}. This signature is the one specified in the * the one specified in the constructor (see {@link #SignatureReader}). This method is intended to
* constructor (see {@link #SignatureReader(String) SignatureReader}). This * be called on a {@link SignatureReader} that was created using a <i>JavaTypeSignature</i>, such
* method is intended to be called on a {@link SignatureReader} that was * as the <code>signature</code> parameter of the {@link
* created using a <i>FieldTypeSignature</i>, such as the * jdk.internal.org.objectweb.asm.ClassVisitor#visitField} or {@link
* <code>signature</code> parameter of the * jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable} methods.
* {@link jdk.internal.org.objectweb.asm.ClassVisitor#visitField ClassVisitor.visitField} *
* or {@link jdk.internal.org.objectweb.asm.MethodVisitor#visitLocalVariable * @param signatureVisitor the visitor that must visit this signature.
* MethodVisitor.visitLocalVariable} methods. */
* public void acceptType(final SignatureVisitor signatureVisitor) {
* @param v parseType(signatureValue, 0, signatureVisitor);
* the visitor that must visit this signature.
*/
public void acceptType(final SignatureVisitor v) {
parseType(this.signature, 0, v);
} }
/** /**
* Parses a field type signature and makes the given visitor visit it. * Parses a JavaTypeSignature and makes the given visitor visit it.
* *
* @param signature * @param signature a string containing the signature that must be parsed.
* a string containing the signature that must be parsed. * @param startOffset index of the first character of the signature to parsed.
* @param pos * @param signatureVisitor the visitor that must visit this signature.
* index of the first character of the signature to parsed. * @return the index of the first character after the parsed signature.
* @param v */
* the visitor that must visit this signature. private static int parseType(
* @return the index of the first character after the parsed signature. final String signature, final int startOffset, final SignatureVisitor signatureVisitor) {
*/ int offset = startOffset; // Current offset in the parsed signature.
private static int parseType(final String signature, int pos, char currentChar = signature.charAt(offset++); // The signature character at 'offset'.
final SignatureVisitor v) {
char c;
int start, end;
boolean visited, inner;
String name;
switch (c = signature.charAt(pos++)) { // Switch based on the first character of the JavaTypeSignature, which indicates its kind.
case 'Z': switch (currentChar) {
case 'C': case 'Z':
case 'B': case 'C':
case 'S': case 'B':
case 'I': case 'S':
case 'F': case 'I':
case 'J': case 'F':
case 'D': case 'J':
case 'V': case 'D':
v.visitBaseType(c); case 'V':
return pos; // Case of a BaseType or a VoidDescriptor.
signatureVisitor.visitBaseType(currentChar);
return offset;
case '[': case '[':
return parseType(signature, pos, v.visitArrayType()); // Case of an ArrayTypeSignature, a '[' followed by a JavaTypeSignature.
return parseType(signature, offset, signatureVisitor.visitArrayType());
case 'T': case 'T':
end = signature.indexOf(';', pos); // Case of TypeVariableSignature, an identifier between 'T' and ';'.
v.visitTypeVariable(signature.substring(pos, end)); int endOffset = signature.indexOf(';', offset);
return end + 1; signatureVisitor.visitTypeVariable(signature.substring(offset, endOffset));
return endOffset + 1;
default: // case 'L': case 'L':
start = pos; // Case of a ClassTypeSignature, which ends with ';'.
visited = false; // These signatures have a main class type followed by zero or more inner class types
inner = false; // (separated by '.'). Each can have type arguments, inside '<' and '>'.
for (;;) { int start = offset; // The start offset of the currently parsed main or inner class name.
switch (c = signature.charAt(pos++)) { boolean visited = false; // Whether the currently parsed class name has been visited.
case '.': boolean inner = false; // Whether we are currently parsing an inner class type.
case ';': // Parses the signature, one character at a time.
if (!visited) { while (true) {
name = signature.substring(start, pos - 1); 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) {
String name = signature.substring(start, offset - 1);
if (inner) {
signatureVisitor.visitInnerClassType(name);
} else {
signatureVisitor.visitClassType(name);
}
}
// 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 = offset;
visited = false;
inner = true;
} 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) { if (inner) {
v.visitInnerClassType(name); signatureVisitor.visitInnerClassType(name);
} else { } else {
v.visitClassType(name); signatureVisitor.visitClassType(name);
} }
} visited = true;
if (c == ';') { // Now, parse the TypeArgument(s), one at a time.
v.visitEnd(); while ((currentChar = signature.charAt(offset)) != '>') {
return pos; switch (currentChar) {
} case '*':
start = pos; // Unbounded TypeArgument.
visited = false; ++offset;
inner = true; signatureVisitor.visitTypeArgument();
break; break;
case '+':
case '<': case '-':
name = signature.substring(start, pos - 1); // Extends or Super TypeArgument. Use offset + 1 to skip the '+' or '-'.
if (inner) { offset =
v.visitInnerClassType(name); parseType(
} else { signature, offset + 1, signatureVisitor.visitTypeArgument(currentChar));
v.visitClassType(name); break;
} default:
visited = true; // Instanceof TypeArgument. The '=' is implicit.
top: for (;;) { offset = parseType(signature, offset, signatureVisitor.visitTypeArgument('='));
switch (c = signature.charAt(pos)) { break;
case '>': }
break top;
case '*':
++pos;
v.visitTypeArgument();
break;
case '+':
case '-':
pos = parseType(signature, pos + 1,
v.visitTypeArgument(c));
break;
default:
pos = parseType(signature, pos,
v.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; import jdk.internal.org.objectweb.asm.Opcodes;
/** /**
* A visitor to visit a generic signature. The methods of this interface must be * A visitor to visit a generic signature. The methods of this interface must be called in one of
* called in one of the three following orders (the last one is the only valid * the three following orders (the last one is the only valid order for a {@link SignatureVisitor}
* order for a {@link SignatureVisitor} that is returned by a method of this * that is returned by a method of this interface):
* interface): *
* <ul> * <ul>
* <li><i>ClassSignature</i> = ( <tt>visitFormalTypeParameter</tt> * <li><i>ClassSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* ( * visitInterfaceBound}* )* ({@code visitSuperclass} {@code visitInterface}* )
* <tt>visitSuperclass</tt> <tt>visitInterface</tt>* )</li> * <li><i>MethodSignature</i> = ( {@code visitFormalTypeParameter} {@code visitClassBound}? {@code
* <li><i>MethodSignature</i> = ( <tt>visitFormalTypeParameter</tt> * visitInterfaceBound}* )* ({@code visitParameterType}* {@code visitReturnType} {@code
* <tt>visitClassBound</tt>? <tt>visitInterfaceBound</tt>* )* ( * visitExceptionType}* )
* <tt>visitParameterType</tt>* <tt>visitReturnType</tt> * <li><i>TypeSignature</i> = {@code visitBaseType} | {@code visitTypeVariable} | {@code
* <tt>visitExceptionType</tt>* )</li> * visitArrayType} | ( {@code visitClassType} {@code visitTypeArgument}* ( {@code
* <li><i>TypeSignature</i> = <tt>visitBaseType</tt> | * visitInnerClassType} {@code visitTypeArgument}* )* {@code visitEnd} ) )
* <tt>visitTypeVariable</tt> | <tt>visitArrayType</tt> | (
* <tt>visitClassType</tt> <tt>visitTypeArgument</tt>* (
* <tt>visitInnerClassType</tt> <tt>visitTypeArgument</tt>* )* <tt>visitEnd</tt>
* ) )</li>
* </ul> * </ul>
* *
* @author Thomas Hallgren * @author Thomas Hallgren
@ -85,183 +81,154 @@ import jdk.internal.org.objectweb.asm.Opcodes;
*/ */
public abstract class SignatureVisitor { public abstract class SignatureVisitor {
/** /** Wildcard for an "extends" type argument. */
* Wildcard for an "extends" type argument. public static final char EXTENDS = '+';
*/
public final static 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. * 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}.
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}.
*/
protected final int api; protected final int api;
/** /**
* Constructs a new {@link SignatureVisitor}. * Constructs a new {@link SignatureVisitor}.
* *
* @param api * @param api the ASM API version implemented by this visitor. Must be one of {@link
* the ASM API version implemented by this visitor. Must be one * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. */
*/
public SignatureVisitor(final int api) { 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(); throw new IllegalArgumentException();
} }
this.api = api; this.api = api;
} }
/** /**
* Visits a formal type parameter. * Visits a formal type parameter.
* *
* @param name * @param name the name of the formal parameter.
* the name of the formal parameter. */
*/ public void visitFormalTypeParameter(final String name) {}
public void visitFormalTypeParameter(String name) {
}
/** /**
* Visits the class bound of the last visited formal type parameter. * Visits the class bound of the last visited formal type parameter.
* *
* @return a non null visitor to visit the signature of the class bound. * @return a non null visitor to visit the signature of the class bound.
*/ */
public SignatureVisitor visitClassBound() { public SignatureVisitor visitClassBound() {
return this; return this;
} }
/** /**
* Visits an interface bound of the last visited formal type parameter. * Visits an interface bound of the last visited formal type parameter.
* *
* @return a non null visitor to visit the signature of the interface bound. * @return a non null visitor to visit the signature of the interface bound.
*/ */
public SignatureVisitor visitInterfaceBound() { public SignatureVisitor visitInterfaceBound() {
return this; return this;
} }
/** /**
* Visits the type of the super class. * Visits the type of the super class.
* *
* @return a non null visitor to visit the signature of the super class * @return a non null visitor to visit the signature of the super class type.
* type. */
*/
public SignatureVisitor visitSuperclass() { public SignatureVisitor visitSuperclass() {
return this; return this;
} }
/** /**
* Visits the type of an interface implemented by the class. * Visits the type of an interface implemented by the class.
* *
* @return a non null visitor to visit the signature of the interface type. * @return a non null visitor to visit the signature of the interface type.
*/ */
public SignatureVisitor visitInterface() { public SignatureVisitor visitInterface() {
return this; return this;
} }
/** /**
* Visits the type of a method parameter. * Visits the type of a method parameter.
* *
* @return a non null visitor to visit the signature of the parameter type. * @return a non null visitor to visit the signature of the parameter type.
*/ */
public SignatureVisitor visitParameterType() { public SignatureVisitor visitParameterType() {
return this; return this;
} }
/** /**
* Visits the return type of the method. * Visits the return type of the method.
* *
* @return a non null visitor to visit the signature of the return type. * @return a non null visitor to visit the signature of the return type.
*/ */
public SignatureVisitor visitReturnType() { public SignatureVisitor visitReturnType() {
return this; return this;
} }
/** /**
* Visits the type of a method exception. * Visits the type of a method exception.
* *
* @return a non null visitor to visit the signature of the exception type. * @return a non null visitor to visit the signature of the exception type.
*/ */
public SignatureVisitor visitExceptionType() { public SignatureVisitor visitExceptionType() {
return this; return this;
} }
/** /**
* Visits a signature corresponding to a primitive type. * Visits a signature corresponding to a primitive type.
* *
* @param descriptor * @param descriptor the descriptor of the primitive type, or 'V' for {@code void} .
* the descriptor of the primitive type, or 'V' for <tt>void</tt> */
* . public void visitBaseType(final char descriptor) {}
*/
public void visitBaseType(char descriptor) {
}
/** /**
* Visits a signature corresponding to a type variable. * Visits a signature corresponding to a type variable.
* *
* @param name * @param name the name of the type variable.
* the name of the type variable. */
*/ public void visitTypeVariable(final String name) {}
public void visitTypeVariable(String name) {
}
/** /**
* Visits a signature corresponding to an array type. * Visits a signature corresponding to an array type.
* *
* @return a non null visitor to visit the signature of the array element * @return a non null visitor to visit the signature of the array element type.
* type. */
*/
public SignatureVisitor visitArrayType() { public SignatureVisitor visitArrayType() {
return this; return this;
} }
/** /**
* Starts the visit of a signature corresponding to a class or interface * Starts the visit of a signature corresponding to a class or interface type.
* type. *
* * @param name the internal name of the class or interface.
* @param name */
* the internal name of the class or interface. public void visitClassType(final String name) {}
*/
public void visitClassType(String name) {
}
/** /**
* Visits an inner class. * Visits an inner class.
* *
* @param name * @param name the local name of the inner class in its enclosing class.
* the local name of the inner class in its enclosing class. */
*/ public void visitInnerClassType(final String name) {}
public void visitInnerClassType(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 * Visits a type argument of the last visited class or inner class type.
* class type. *
*/ * @param wildcard '+', '-' or '='.
public void visitTypeArgument() { * @return a non null visitor to visit the signature of the type argument.
} */
public SignatureVisitor visitTypeArgument(final char wildcard) {
/**
* Visits a type argument of the last visited class or inner class type.
*
* @param wildcard
* '+', '-' or '='.
* @return a non null visitor to visit the signature of the type argument.
*/
public SignatureVisitor visitTypeArgument(char wildcard) {
return this; return this;
} }
/** /** Ends the visit of a signature corresponding to a class or interface type. */
* Ends the visit of a signature corresponding to a class or interface type. public void visitEnd() {}
*/
public void visitEnd() {
}
} }

View file

@ -61,55 +61,61 @@ package jdk.internal.org.objectweb.asm.signature;
import jdk.internal.org.objectweb.asm.Opcodes; 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 Thomas Hallgren
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public class SignatureWriter extends SignatureVisitor { public class SignatureWriter extends SignatureVisitor {
/** /** The builder used to construct the visited signature. */
* Builder used to construct the signature. private final StringBuilder stringBuilder = new StringBuilder();
*/
private final StringBuilder buf = new StringBuilder();
/** /** Whether the visited signature contains formal type parameters. */
* Indicates if the signature contains formal type parameters.
*/
private boolean hasFormals; private boolean hasFormals;
/** /** Whether the visited signature contains method parameter types. */
* Indicates if the signature contains method parameter types.
*/
private boolean hasParameters; private boolean hasParameters;
/** /**
* Stack used to keep track of class types that have arguments. Each element * The stack used to keep track of class types that have arguments. Each element of this stack is
* of this stack is a boolean encoded in one bit. The top of the stack is * a boolean encoded in one bit. The top of the stack is the least significant bit. Pushing false
* the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = * = *2, pushing true = *2+1, popping = /2.
* /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; private int argumentStack;
/** /** Constructs a new {@link SignatureWriter}. */
* Constructs a new {@link SignatureWriter} object.
*/
public SignatureWriter() { public SignatureWriter() {
super(Opcodes.ASM6); super(Opcodes.ASM7);
} }
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
// Implementation of the SignatureVisitor interface // Implementation of the SignatureVisitor interface
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
@Override @Override
public void visitFormalTypeParameter(final String name) { public void visitFormalTypeParameter(final String name) {
if (!hasFormals) { if (!hasFormals) {
hasFormals = true; hasFormals = true;
buf.append('<'); stringBuilder.append('<');
} }
buf.append(name); stringBuilder.append(name);
buf.append(':'); stringBuilder.append(':');
} }
@Override @Override
@ -119,7 +125,7 @@ public class SignatureWriter extends SignatureVisitor {
@Override @Override
public SignatureVisitor visitInterfaceBound() { public SignatureVisitor visitInterfaceBound() {
buf.append(':'); stringBuilder.append(':');
return this; return this;
} }
@ -139,7 +145,7 @@ public class SignatureWriter extends SignatureVisitor {
endFormals(); endFormals();
if (!hasParameters) { if (!hasParameters) {
hasParameters = true; hasParameters = true;
buf.append('('); stringBuilder.append('(');
} }
return this; return this;
} }
@ -148,68 +154,78 @@ public class SignatureWriter extends SignatureVisitor {
public SignatureVisitor visitReturnType() { public SignatureVisitor visitReturnType() {
endFormals(); endFormals();
if (!hasParameters) { if (!hasParameters) {
buf.append('('); stringBuilder.append('(');
} }
buf.append(')'); stringBuilder.append(')');
return this; return this;
} }
@Override @Override
public SignatureVisitor visitExceptionType() { public SignatureVisitor visitExceptionType() {
buf.append('^'); stringBuilder.append('^');
return this; return this;
} }
@Override @Override
public void visitBaseType(final char descriptor) { public void visitBaseType(final char descriptor) {
buf.append(descriptor); stringBuilder.append(descriptor);
} }
@Override @Override
public void visitTypeVariable(final String name) { public void visitTypeVariable(final String name) {
buf.append('T'); stringBuilder.append('T');
buf.append(name); stringBuilder.append(name);
buf.append(';'); stringBuilder.append(';');
} }
@Override @Override
public SignatureVisitor visitArrayType() { public SignatureVisitor visitArrayType() {
buf.append('['); stringBuilder.append('[');
return this; return this;
} }
@Override @Override
public void visitClassType(final String name) { public void visitClassType(final String name) {
buf.append('L'); stringBuilder.append('L');
buf.append(name); 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; argumentStack *= 2;
} }
@Override @Override
public void visitInnerClassType(final String name) { public void visitInnerClassType(final String name) {
endArguments(); endArguments();
buf.append('.'); stringBuilder.append('.');
buf.append(name); 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; argumentStack *= 2;
} }
@Override @Override
public void visitTypeArgument() { 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) { if (argumentStack % 2 == 0) {
++argumentStack; argumentStack |= 1;
buf.append('<'); stringBuilder.append('<');
} }
buf.append('*'); stringBuilder.append('*');
} }
@Override @Override
public SignatureVisitor visitTypeArgument(final char wildcard) { 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) { if (argumentStack % 2 == 0) {
++argumentStack; argumentStack |= 1;
buf.append('<'); stringBuilder.append('<');
} }
if (wildcard != '=') { if (wildcard != '=') {
buf.append(wildcard); stringBuilder.append(wildcard);
} }
return this; return this;
} }
@ -217,39 +233,38 @@ public class SignatureWriter extends SignatureVisitor {
@Override @Override
public void visitEnd() { public void visitEnd() {
endArguments(); endArguments();
buf.append(';'); stringBuilder.append(';');
} }
/** /**
* Returns the signature that was built by this signature writer. * Returns the signature that was built by this signature writer.
* *
* @return the signature that was built by this signature writer. * @return the signature that was built by this signature writer.
*/ */
@Override @Override
public String toString() { public String toString() {
return buf.toString(); return stringBuilder.toString();
} }
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
// Utility methods // Utility methods
// ------------------------------------------------------------------------ // -----------------------------------------------------------------------------------------------
/** /** Ends the formal type parameters section of the signature. */
* Ends the formal type parameters section of the signature.
*/
private void endFormals() { private void endFormals() {
if (hasFormals) { if (hasFormals) {
hasFormals = false; 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() { private void endArguments() {
if (argumentStack % 2 != 0) { // If the top of the stack is 'true', this means that some type arguments have been visited for
buf.append('>'); // 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; argumentStack /= 2;
} }

View file

@ -61,293 +61,234 @@ package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
/** /**
* A node that represents a bytecode instruction. <i>An instruction can appear * A node that represents a bytecode instruction. <i>An instruction can appear at most once in at
* at most once in at most one {@link InsnList} at a time</i>. * most one {@link InsnList} at a time</i>.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public abstract class AbstractInsnNode { public abstract class AbstractInsnNode {
/** /** The type of {@link InsnNode} instructions. */
* The type of {@link InsnNode} instructions.
*/
public static final int INSN = 0; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; 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; public static final int FRAME = 14;
/** /** The type of {@link LineNumberNode} "instructions". */
* The type of {@link LineNumberNode} "instructions".
*/
public static final int LINE = 15; public static final int LINE = 15;
/** /** The opcode of this instruction. */
* The opcode of this instruction.
*/
protected int opcode; protected int opcode;
/** /**
* The runtime visible type annotations of this instruction. This field is * The runtime visible type annotations of this instruction. This field is only used for real
* only used for real instructions (i.e. not for labels, frames, or line * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
* number nodes). This list is a list of {@link TypeAnnotationNode} objects. * TypeAnnotationNode} objects. May be {@literal null}.
* May be <tt>null</tt>. */
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label visible
*/
public List<TypeAnnotationNode> visibleTypeAnnotations; public List<TypeAnnotationNode> visibleTypeAnnotations;
/** /**
* The runtime invisible type annotations of this instruction. This field is * The runtime invisible type annotations of this instruction. This field is only used for real
* only used for real instructions (i.e. not for labels, frames, or line * instructions (i.e. not for labels, frames, or line number nodes). This list is a list of {@link
* number nodes). This list is a list of {@link TypeAnnotationNode} objects. * TypeAnnotationNode} objects. May be {@literal null}.
* May be <tt>null</tt>. */
*
* @associates jdk.internal.org.objectweb.asm.tree.TypeAnnotationNode
* @label invisible
*/
public List<TypeAnnotationNode> invisibleTypeAnnotations; public List<TypeAnnotationNode> invisibleTypeAnnotations;
/** /** The previous instruction in the list to which this instruction belongs. */
* Previous instruction in the list to which this instruction belongs. AbstractInsnNode previousInsn;
*/
AbstractInsnNode prev; /** The next instruction in the list to which this instruction belongs. */
AbstractInsnNode nextInsn;
/** /**
* Next instruction in the list to which this instruction belongs. * 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
AbstractInsnNode next; * instruction does not belong to any {@link InsnList}.
*/
/**
* 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; int index;
/** /**
* Constructs a new {@link AbstractInsnNode}. * Constructs a new {@link AbstractInsnNode}.
* *
* @param opcode * @param opcode the opcode of the instruction to be constructed.
* the opcode of the instruction to be constructed. */
*/
protected AbstractInsnNode(final int opcode) { protected AbstractInsnNode(final int opcode) {
this.opcode = opcode; this.opcode = opcode;
this.index = -1; this.index = -1;
} }
/** /**
* Returns the opcode of this instruction. * Returns the opcode of this instruction.
* *
* @return the opcode of this instruction. * @return the opcode of this instruction.
*/ */
public int getOpcode() { public int getOpcode() {
return opcode; return opcode;
} }
/** /**
* Returns the type of this instruction. * Returns the type of this instruction.
* *
* @return the type of this instruction, i.e. one the constants defined in * @return the type of this instruction, i.e. one the constants defined in this class.
* this class. */
*/
public abstract int getType(); public abstract int getType();
/** /**
* Returns the previous instruction in the list to which this instruction * Returns the previous instruction in the list to which this instruction belongs, if any.
* belongs, if any. *
* * @return the previous instruction in the list to which this instruction belongs, if any. May be
* @return the previous instruction in the list to which this instruction * {@literal null}.
* belongs, if any. May be <tt>null</tt>. */
*/
public AbstractInsnNode getPrevious() { public AbstractInsnNode getPrevious() {
return prev; return previousInsn;
} }
/** /**
* Returns the next instruction in the list to which this instruction * Returns the next instruction in the list to which this instruction belongs, if any.
* belongs, if any. *
* * @return the next instruction in the list to which this instruction belongs, if any. May be
* @return the next instruction in the list to which this instruction * {@literal null}.
* belongs, if any. May be <tt>null</tt>. */
*/
public AbstractInsnNode getNext() { 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 * @param methodVisitor a method visitor.
* a code visitor. */
*/ public abstract void accept(MethodVisitor methodVisitor);
public abstract void accept(final MethodVisitor cv);
/** /**
* Makes the given visitor visit the annotations of this instruction. * Makes the given visitor visit the annotations of this instruction.
* *
* @param mv * @param methodVisitor a method visitor.
* a method visitor. */
*/ protected final void acceptAnnotations(final MethodVisitor methodVisitor) {
protected final void acceptAnnotations(final MethodVisitor mv) { if (visibleTypeAnnotations != null) {
int n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations for (int i = 0, n = visibleTypeAnnotations.size(); i < n; ++i) {
.size(); TypeAnnotationNode typeAnnotation = visibleTypeAnnotations.get(i);
for (int i = 0; i < n; ++i) { typeAnnotation.accept(
TypeAnnotationNode an = visibleTypeAnnotations.get(i); methodVisitor.visitInsnAnnotation(
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc, typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, true));
true)); }
} }
n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations if (invisibleTypeAnnotations != null) {
.size(); for (int i = 0, n = invisibleTypeAnnotations.size(); i < n; ++i) {
for (int i = 0; i < n; ++i) { TypeAnnotationNode typeAnnotation = invisibleTypeAnnotations.get(i);
TypeAnnotationNode an = invisibleTypeAnnotations.get(i); typeAnnotation.accept(
an.accept(mv.visitInsnAnnotation(an.typeRef, an.typePath, an.desc, methodVisitor.visitInsnAnnotation(
false)); typeAnnotation.typeRef, typeAnnotation.typePath, typeAnnotation.desc, false));
}
} }
} }
/** /**
* Returns a copy of this instruction. * Returns a copy of this instruction.
* *
* @param labels * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* a map from LabelNodes to cloned LabelNodes. * @return a copy of this instruction. The returned instruction does not belong to any {@link
* @return a copy of this instruction. The returned instruction does not * InsnList}.
* belong to any {@link InsnList}. */
*/ public abstract AbstractInsnNode clone(Map<LabelNode, LabelNode> clonedLabels);
public abstract AbstractInsnNode clone(
final Map<LabelNode, LabelNode> labels);
/** /**
* Returns the clone of the given label. * Returns the clone of the given label.
* *
* @param label * @param label a label.
* a label. * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* @param map * @return the clone of the given label.
* a map from LabelNodes to cloned LabelNodes. */
* @return the clone of the given label. static LabelNode clone(final LabelNode label, final Map<LabelNode, LabelNode> clonedLabels) {
*/ return clonedLabels.get(label);
static LabelNode clone(final LabelNode label,
final Map<LabelNode, LabelNode> map) {
return map.get(label);
} }
/** /**
* Returns the clones of the given labels. * Returns the clones of the given labels.
* *
* @param labels * @param labels a list of labels.
* a list of labels. * @param clonedLabels a map from LabelNodes to cloned LabelNodes.
* @param map * @return the clones of the given labels.
* 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> clonedLabels) {
static LabelNode[] clone(final List<LabelNode> labels,
final Map<LabelNode, LabelNode> map) {
LabelNode[] clones = new LabelNode[labels.size()]; LabelNode[] clones = new LabelNode[labels.size()];
for (int i = 0; i < clones.length; ++i) { for (int i = 0, n = clones.length; i < n; ++i) {
clones[i] = map.get(labels.get(i)); clones[i] = clonedLabels.get(labels.get(i));
} }
return clones; return clones;
} }
/** /**
* Clones the annotations of the given instruction into this instruction. * Clones the annotations of the given instruction into this instruction.
* *
* @param insn * @param insnNode the source instruction.
* the source instruction. * @return this instruction.
* @return this instruction. */
*/ protected final AbstractInsnNode cloneAnnotations(final AbstractInsnNode insnNode) {
protected final AbstractInsnNode cloneAnnotations( if (insnNode.visibleTypeAnnotations != null) {
final AbstractInsnNode insn) {
if (insn.visibleTypeAnnotations != null) {
this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(); this.visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.visibleTypeAnnotations.size(); ++i) { for (int i = 0, n = insnNode.visibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode src = insn.visibleTypeAnnotations.get(i); TypeAnnotationNode sourceAnnotation = insnNode.visibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef, TypeAnnotationNode cloneAnnotation =
src.typePath, src.desc); new TypeAnnotationNode(
src.accept(ann); sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
this.visibleTypeAnnotations.add(ann); sourceAnnotation.accept(cloneAnnotation);
this.visibleTypeAnnotations.add(cloneAnnotation);
} }
} }
if (insn.invisibleTypeAnnotations != null) { if (insnNode.invisibleTypeAnnotations != null) {
this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(); this.invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>();
for (int i = 0; i < insn.invisibleTypeAnnotations.size(); ++i) { for (int i = 0, n = insnNode.invisibleTypeAnnotations.size(); i < n; ++i) {
TypeAnnotationNode src = insn.invisibleTypeAnnotations.get(i); TypeAnnotationNode sourceAnnotation = insnNode.invisibleTypeAnnotations.get(i);
TypeAnnotationNode ann = new TypeAnnotationNode(src.typeRef, TypeAnnotationNode cloneAnnotation =
src.typePath, src.desc); new TypeAnnotationNode(
src.accept(ann); sourceAnnotation.typeRef, sourceAnnotation.typePath, sourceAnnotation.desc);
this.invisibleTypeAnnotations.add(ann); sourceAnnotation.accept(cloneAnnotation);
this.invisibleTypeAnnotations.add(cloneAnnotation);
} }
} }
return this; return this;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -59,16 +59,13 @@
package jdk.internal.org.objectweb.asm.tree; package jdk.internal.org.objectweb.asm.tree;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor; 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 { public class LabelNode extends AbstractInsnNode {
private Label label; private Label value;
public LabelNode() { public LabelNode() {
super(-1); super(-1);
@ -76,7 +73,7 @@ public class LabelNode extends AbstractInsnNode {
public LabelNode(final Label label) { public LabelNode(final Label label) {
super(-1); super(-1);
this.label = label; this.value = label;
} }
@Override @Override
@ -84,24 +81,30 @@ public class LabelNode extends AbstractInsnNode {
return LABEL; 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() { public Label getLabel() {
if (label == null) { if (value == null) {
label = new Label(); value = new Label();
} }
return label; return value;
} }
@Override @Override
public void accept(final MethodVisitor cv) { public void accept(final MethodVisitor methodVisitor) {
cv.visitLabel(getLabel()); methodVisitor.visitLabel(getLabel());
} }
@Override @Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return labels.get(this); return clonedLabels.get(this);
} }
public void resetLabel() { public void resetLabel() {
label = null; value = null;
} }
} }

View file

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

View file

@ -59,37 +59,29 @@
package jdk.internal.org.objectweb.asm.tree; package jdk.internal.org.objectweb.asm.tree;
import java.util.Map; import java.util.Map;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
/** /**
* A node that represents a line number declaration. These nodes are pseudo * A node that represents a line number declaration. These nodes are pseudo instruction nodes in
* instruction nodes in order to be inserted in an instruction list. * order to be inserted in an instruction list.
* *
* @author Eric Bruneton * @author Eric Bruneton
*/ */
public class LineNumberNode extends AbstractInsnNode { 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; public int line;
/** /** The first instruction corresponding to this line number. */
* The first instruction corresponding to this line number.
*/
public LabelNode start; public LabelNode start;
/** /**
* Constructs a new {@link LineNumberNode}. * Constructs a new {@link LineNumberNode}.
* *
* @param line * @param line a line number. This number refers to the source file from which the class was
* a line number. This number refers to the source file from * compiled.
* which the class was compiled. * @param start the first instruction corresponding to this line number.
* @param start */
* the first instruction corresponding to this line number.
*/
public LineNumberNode(final int line, final LabelNode start) { public LineNumberNode(final int line, final LabelNode start) {
super(-1); super(-1);
this.line = line; this.line = line;
@ -102,12 +94,12 @@ public class LineNumberNode extends AbstractInsnNode {
} }
@Override @Override
public void accept(final MethodVisitor mv) { public void accept(final MethodVisitor methodVisitor) {
mv.visitLineNumber(line, start.getLabel()); methodVisitor.visitLineNumber(line, start.getLabel());
} }
@Override @Override
public AbstractInsnNode clone(final Map<LabelNode, LabelNode> labels) { public AbstractInsnNode clone(final Map<LabelNode, LabelNode> clonedLabels) {
return new LineNumberNode(line, clone(start, labels)); 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 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE. * THE POSSIBILITY OF SUCH DAMAGE.
*/ */
package jdk.internal.org.objectweb.asm.tree; package jdk.internal.org.objectweb.asm.tree;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.Label;
import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.internal.org.objectweb.asm.MethodVisitor;
import jdk.internal.org.objectweb.asm.Opcodes; import jdk.internal.org.objectweb.asm.Opcodes;
import jdk.internal.org.objectweb.asm.TypePath; 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. * 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 { public class LocalVariableAnnotationNode extends TypeAnnotationNode {
/** /**
* The fist instructions corresponding to the continuous ranges that make * The fist instructions corresponding to the continuous ranges that make the scope of this local
* the scope of this local variable (inclusive). Must not be <tt>null</tt>. * variable (inclusive). Must not be {@literal null}.
*/ */
public List<LabelNode> start; public List<LabelNode> start;
/** /**
* The last instructions corresponding to the continuous ranges that make * The last instructions corresponding to the continuous ranges that make the scope of this local
* the scope of this local variable (exclusive). This list must have the * variable (exclusive). This list must have the same size as the 'start' list. Must not be
* same size as the 'start' list. Must not be <tt>null</tt>. * {@literal null}.
*/ */
public List<LabelNode> end; public List<LabelNode> end;
/** /**
* The local variable's index in each range. This list must have the same * The local variable's index in each range. This list must have the same size as the 'start'
* size as the 'start' list. Must not be <tt>null</tt>. * list. Must not be {@literal null}.
*/ */
public List<Integer> index; public List<Integer> index;
/** /**
* Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must * Constructs a new {@link LocalVariableAnnotationNode}. <i>Subclasses must not use this
* not use this constructor</i>. Instead, they must use the * constructor</i>. Instead, they must use the {@link #LocalVariableAnnotationNode(int, TypePath,
* {@link #LocalVariableAnnotationNode(int, TypePath, LabelNode[], LabelNode[], int[], String)} * LabelNode[], LabelNode[], int[], String)} version.
* version. *
* * @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
* @param typeRef * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* a reference to the annotated type. See {@link TypeReference}. * static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* @param typePath * 'typeRef' as a whole.
* the path to the annotated type argument, wildcard bound, array * @param start the fist instructions corresponding to the continuous ranges that make the scope
* element type, or static inner type within 'typeRef'. May be * of this local variable (inclusive).
* <tt>null</tt> if the annotation targets 'typeRef' as a whole. * @param end the last instructions corresponding to the continuous ranges that make the scope of
* @param start * this local variable (exclusive). This array must have the same size as the 'start' array.
* the fist instructions corresponding to the continuous ranges * @param index the local variable's index in each range. This array must have the same size as
* that make the scope of this local variable (inclusive). * the 'start' array.
* @param end * @param descriptor the class descriptor of the annotation class.
* the last instructions corresponding to the continuous ranges */
* that make the scope of this local variable (exclusive). This public LocalVariableAnnotationNode(
* array must have the same size as the 'start' array. final int typeRef,
* @param index final TypePath typePath,
* the local variable's index in each range. This array must have final LabelNode[] start,
* the same size as the 'start' array. final LabelNode[] end,
* @param desc final int[] index,
* the class descriptor of the annotation class. final String descriptor) {
*/ this(Opcodes.ASM7, typeRef, typePath, start, end, index, descriptor);
public LocalVariableAnnotationNode(int typeRef, TypePath typePath,
LabelNode[] start, LabelNode[] end, int[] index, String desc) {
this(Opcodes.ASM6, typeRef, typePath, start, end, index, desc);
} }
/** /**
* Constructs a new {@link LocalVariableAnnotationNode}. * Constructs a new {@link LocalVariableAnnotationNode}.
* *
* @param api * @param api the ASM API version implemented by this visitor. Must be one of {@link
* the ASM API version implemented by this visitor. Must be one * Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* of {@link Opcodes#ASM4}, {@link Opcodes#ASM5} or {@link Opcodes#ASM6}. * @param typeRef a reference to the annotated type. See {@link jdk.internal.org.objectweb.asm.TypeReference}.
* @param typeRef * @param start the fist instructions corresponding to the continuous ranges that make the scope
* a reference to the annotated type. See {@link TypeReference}. * of this local variable (inclusive).
* @param start * @param end the last instructions corresponding to the continuous ranges that make the scope of
* the fist instructions corresponding to the continuous ranges * this local variable (exclusive). This array must have the same size as the 'start' array.
* that make the scope of this local variable (inclusive). * @param index the local variable's index in each range. This array must have the same size as
* @param end * the 'start' array.
* the last instructions corresponding to the continuous ranges * @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* that make the scope of this local variable (exclusive). This * static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* array must have the same size as the 'start' array. * 'typeRef' as a whole.
* @param index * @param descriptor the class descriptor of the annotation class.
* the local variable's index in each range. This array must have */
* the same size as the 'start' array. public LocalVariableAnnotationNode(
* @param typePath final int api,
* the path to the annotated type argument, wildcard bound, array final int typeRef,
* element type, or static inner type within 'typeRef'. May be final TypePath typePath,
* <tt>null</tt> if the annotation targets 'typeRef' as a whole. final LabelNode[] start,
* @param desc final LabelNode[] end,
* the class descriptor of the annotation class. final int[] index,
*/ final String descriptor) {
public LocalVariableAnnotationNode(int api, int typeRef, TypePath typePath, super(api, typeRef, typePath, descriptor);
LabelNode[] start, LabelNode[] end, int[] index, String desc) { this.start = Util.asArrayList(start);
super(api, typeRef, typePath, desc); this.end = Util.asArrayList(end);
this.start = new ArrayList<LabelNode>(start.length); this.index = Util.asArrayList(index);
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);
}
} }
/** /**
* Makes the given visitor visit this type annotation. * Makes the given visitor visit this type annotation.
* *
* @param mv * @param methodVisitor the visitor that must visit this annotation.
* the visitor that must visit this annotation. * @param visible {@literal true} if the annotation is visible at runtime.
* @param visible */
* <tt>true</tt> if the annotation is visible at runtime. public void accept(final MethodVisitor methodVisitor, final boolean visible) {
*/ Label[] startLabels = new Label[this.start.size()];
public void accept(final MethodVisitor mv, boolean visible) { Label[] endLabels = new Label[this.end.size()];
Label[] start = new Label[this.start.size()]; int[] indices = new int[this.index.size()];
Label[] end = new Label[this.end.size()]; for (int i = 0, n = startLabels.length; i < n; ++i) {
int[] index = new int[this.index.size()]; startLabels[i] = this.start.get(i).getLabel();
for (int i = 0; i < start.length; ++i) { endLabels[i] = this.end.get(i).getLabel();
start[i] = this.start.get(i).getLabel(); indices[i] = this.index.get(i);
end[i] = this.end.get(i).getLabel();
index[i] = this.index.get(i);
} }
accept(mv.visitLocalVariableAnnotation(typeRef, typePath, start, end, accept(
index, desc, visible)); 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 { public class LocalVariableNode {
/** /** The name of a local variable. */
* The name of a local variable.
*/
public String name; public String name;
/** /** The type descriptor of this local variable. */
* The type descriptor of this local variable.
*/
public String desc; public String desc;
/** /** The signature of this local variable. May be {@literal null}. */
* The signature of this local variable. May be <tt>null</tt>.
*/
public String signature; 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; 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; public LabelNode end;
/** /** The local variable's index. */
* The local variable's index.
*/
public int index; public int index;
/** /**
* Constructs a new {@link LocalVariableNode}. * Constructs a new {@link LocalVariableNode}.
* *
* @param name * @param name the name of a local variable.
* the name of a local variable. * @param descriptor the type descriptor of this local variable.
* @param desc * @param signature the signature of this local variable. May be {@literal null}.
* the type descriptor of this local variable. * @param start the first instruction corresponding to the scope of this local variable
* @param signature * (inclusive).
* the signature of this local variable. May be <tt>null</tt>. * @param end the last instruction corresponding to the scope of this local variable (exclusive).
* @param start * @param index the local variable's index.
* the first instruction corresponding to the scope of this local */
* variable (inclusive). public LocalVariableNode(
* @param end final String name,
* the last instruction corresponding to the scope of this local final String descriptor,
* variable (exclusive). final String signature,
* @param index final LabelNode start,
* the local variable's index. final LabelNode end,
*/
public LocalVariableNode(final String name, final String desc,
final String signature, final LabelNode start, final LabelNode end,
final int index) { final int index) {
this.name = name; this.name = name;
this.desc = desc; this.desc = descriptor;
this.signature = signature; this.signature = signature;
this.start = start; this.start = start;
this.end = end; this.end = end;
@ -129,13 +112,12 @@ public class LocalVariableNode {
} }
/** /**
* Makes the given visitor visit this local variable declaration. * Makes the given visitor visit this local variable declaration.
* *
* @param mv * @param methodVisitor a method visitor.
* a method visitor. */
*/ public void accept(final MethodVisitor methodVisitor) {
public void accept(final MethodVisitor mv) { methodVisitor.visitLocalVariable(
mv.visitLocalVariable(name, desc, signature, start.getLabel(), name, desc, signature, start.getLabel(), end.getLabel(), index);
end.getLabel(), index);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -61,45 +61,39 @@ package jdk.internal.org.objectweb.asm.tree;
import jdk.internal.org.objectweb.asm.MethodVisitor; 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 * @author Remi Forax
*/ */
public class ParameterNode { public class ParameterNode {
/**
* The parameter's name. /** The parameter's name. */
*/
public String name; public String name;
/** /**
* The parameter's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). * The parameter's access flags (see {@link jdk.internal.org.objectweb.asm.Opcodes}). Valid values are {@code
* Valid values are <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> and * ACC_FINAL}, {@code ACC_SYNTHETIC} and {@code ACC_MANDATED}.
* <tt>ACC_MANDATED</tt>. */
*/
public int access; public int access;
/** /**
* Constructs a new {@link ParameterNode}. * Constructs a new {@link ParameterNode}.
* *
* @param access * @param access The parameter's access flags. Valid values are {@code ACC_FINAL}, {@code
* The parameter's access flags. Valid values are * ACC_SYNTHETIC} or/and {@code ACC_MANDATED} (see {@link jdk.internal.org.objectweb.asm.Opcodes}).
* <tt>ACC_FINAL</tt>, <tt>ACC_SYNTHETIC</tt> or/and * @param name the parameter's name.
* <tt>ACC_MANDATED</tt> (see {@link jdk.internal.org.objectweb.asm.Opcodes}). */
* @param name
* the parameter's name.
*/
public ParameterNode(final String name, final int access) { public ParameterNode(final String name, final int access) {
this.name = name; this.name = name;
this.access = access; this.access = access;
} }
/** /**
* Makes the given visitor visit this parameter declaration. * Makes the given visitor visit this parameter declaration.
* *
* @param mv * @param methodVisitor a method visitor.
* a method visitor. */
*/ public void accept(final MethodVisitor methodVisitor) {
public void accept(final MethodVisitor mv) { methodVisitor.visitParameter(name, access);
mv.visitParameter(name, access);
} }
} }

View file

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

View file

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

View file

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

View file

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