Skip to content

Commit

Permalink
Adopt ASM 8.0 (#4431)
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Supol <jan.supol@oracle.com>
  • Loading branch information
jansupol committed Apr 17, 2020
1 parent 950ce6c commit d88025b
Show file tree
Hide file tree
Showing 19 changed files with 1,392 additions and 386 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,17 @@ public AnnotationVisitor(final int api) {
* calls. May be {@literal null}.
*/
public AnnotationVisitor(final int api, final AnnotationVisitor annotationVisitor) {
if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.av = annotationVisitor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ final class AnnotationWriter extends AnnotationVisitor {
final boolean useNamedValues,
final ByteVector annotation,
final AnnotationWriter previousAnnotation) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
this.symbolTable = symbolTable;
this.useNamedValues = useNamedValues;
this.annotation = annotation;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@
/**
* A visitor to visit a Java class. The methods of this class must be called in the following order:
* {@code visit} [ {@code visitSource} ] [ {@code visitModule} ][ {@code visitNestHost} ][ {@code
* visitOuterClass} ] ( {@code visitAnnotation} | {@code visitTypeAnnotation} | {@code
* visitAttribute} )* ( {@code visitNestMember} | {@code visitInnerClass} | {@code visitField} |
* {@code visitMethod} )* {@code visitEnd}.
* visitPermittedSubtype} ][ {@code visitOuterClass} ] ( {@code visitAnnotation} | {@code
* visitTypeAnnotation} | {@code visitAttribute} )* ( {@code visitNestMember} | {@code
* visitInnerClass} | {@code visitField} | {@code visitMethod} )* {@code visitEnd}.
*
* @author Eric Bruneton
*/
Expand Down Expand Up @@ -61,14 +61,23 @@ public ClassVisitor(final int api) {
* Constructs a new {@link ClassVisitor}.
*
* @param api the ASM API version implemented by this visitor. Must be one of {@link
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6} or {@link Opcodes#ASM7}.
* Opcodes#ASM4}, {@link Opcodes#ASM5}, {@link Opcodes#ASM6}, {@link Opcodes#ASM7} or {@link
* Opcodes#ASM8}.
* @param classVisitor the class visitor to which this visitor must delegate method calls. May be
* null.
*/
public ClassVisitor(final int api, final ClassVisitor classVisitor) {
if (api != Opcodes.ASM7 && api != Opcodes.ASM6 && api != Opcodes.ASM5 && api != Opcodes.ASM4) {
if (api != Opcodes.ASM8
&& api != Opcodes.ASM7
&& api != Opcodes.ASM6
&& api != Opcodes.ASM5
&& api != Opcodes.ASM4
&& api != Opcodes.ASM9_EXPERIMENTAL) {
throw new IllegalArgumentException("Unsupported api " + api);
}
if (api == Opcodes.ASM9_EXPERIMENTAL) {
Constants.checkAsmExperimental(this);
}
this.api = api;
this.cv = classVisitor;
}
Expand Down Expand Up @@ -240,6 +249,24 @@ public void visitNestMember(final String nestMember) {
}
}

/**
* <b>Experimental, use at your own risk. This method will be renamed when it becomes stable, this
* will break existing code using it</b>. Visits a permitted subtypes. A permitted subtypes is one
* of the allowed subtypes of the current class.
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Deprecated
public void visitPermittedSubtypeExperimental(final String permittedSubtype) {
if (api != Opcodes.ASM9_EXPERIMENTAL) {
throw new UnsupportedOperationException("This feature requires ASM9_EXPERIMENTAL");
}
if (cv != null) {
cv.visitPermittedSubtypeExperimental(permittedSubtype);
}
}

/**
* Visits information about an inner class. This inner class is not necessarily a member of the
* class being visited.
Expand All @@ -259,6 +286,27 @@ public void visitInnerClass(
}
}

/**
* Visits a record component of the class.
*
* @param name the record component name.
* @param descriptor the record component descriptor (see {@link Type}).
* @param signature the record component signature. May be {@literal null} if the record component
* type does not use generic types.
* @return a visitor to visit this record component annotations and attributes, or {@literal null}
* if this class visitor is not interested in visiting these annotations and attributes.
*/
public RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
if (api < Opcodes.ASM8) {
throw new UnsupportedOperationException("This feature requires ASM8");
}
if (cv != null) {
return cv.visitRecordComponent(name, descriptor, signature);
}
return null;
}

/**
* Visits a field of the class.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,26 @@ public class ClassWriter extends ClassVisitor {
/** The 'classes' array of the NestMembers attribute, or {@literal null}. */
private ByteVector nestMemberClasses;

/** The number_of_classes field of the PermittedSubtypes attribute, or 0. */
private int numberOfPermittedSubtypeClasses;

/** The 'classes' array of the PermittedSubtypes attribute, or {@literal null}. */
private ByteVector permittedSubtypeClasses;

/**
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the first
* element of this list.
*/
private RecordComponentWriter firstRecordComponent;

/**
* The record components of this class, stored in a linked list of {@link RecordComponentWriter}
* linked via their {@link RecordComponentWriter#delegate} field. This field stores the last
* element of this list.
*/
private RecordComponentWriter lastRecordComponent;

/**
* The first non standard attribute of this class. The next ones can be accessed with the {@link
* Attribute#nextAttribute} field. May be {@literal null}.
Expand Down Expand Up @@ -234,7 +254,7 @@ public ClassWriter(final int flags) {
* maximum stack size nor the stack frames will be computed for these methods</i>.
*/
public ClassWriter(final ClassReader classReader, final int flags) {
super(Opcodes.ASM7);
super(/* latest api = */ Opcodes.ASM8);
symbolTable = classReader == null ? new SymbolTable(this) : new SymbolTable(this, classReader);
if ((flags & COMPUTE_FRAMES) != 0) {
this.compute = MethodWriter.COMPUTE_ALL_FRAMES;
Expand Down Expand Up @@ -352,6 +372,22 @@ public final void visitNestMember(final String nestMember) {
nestMemberClasses.putShort(symbolTable.addConstantClass(nestMember).index);
}

/**
* <b>Experimental, use at your own risk.</b>
*
* @param permittedSubtype the internal name of a permitted subtype.
* @deprecated this API is experimental.
*/
@Override
@Deprecated
public final void visitPermittedSubtypeExperimental(final String permittedSubtype) {
if (permittedSubtypeClasses == null) {
permittedSubtypeClasses = new ByteVector();
}
++numberOfPermittedSubtypeClasses;
permittedSubtypeClasses.putShort(symbolTable.addConstantClass(permittedSubtype).index);
}

@Override
public final void visitInnerClass(
final String name, final String outerName, final String innerName, final int access) {
Expand All @@ -377,6 +413,19 @@ public final void visitInnerClass(
// and throw an exception if there is a difference?
}

@Override
public final RecordComponentVisitor visitRecordComponent(
final String name, final String descriptor, final String signature) {
RecordComponentWriter recordComponentWriter =
new RecordComponentWriter(symbolTable, name, descriptor, signature);
if (firstRecordComponent == null) {
firstRecordComponent = recordComponentWriter;
} else {
lastRecordComponent.delegate = recordComponentWriter;
}
return lastRecordComponent = recordComponentWriter;
}

@Override
public final FieldVisitor visitField(
final int access,
Expand Down Expand Up @@ -447,6 +496,7 @@ public byte[] toByteArray() {
size += methodWriter.computeMethodInfoSize();
methodWriter = (MethodWriter) methodWriter.mv;
}

// For ease of reference, we use here the same attribute order as in Section 4.7 of the JVMS.
int attributesCount = 0;
if (innerClasses != null) {
Expand Down Expand Up @@ -526,6 +576,24 @@ public byte[] toByteArray() {
size += 8 + nestMemberClasses.length;
symbolTable.addConstantUtf8(Constants.NEST_MEMBERS);
}
if (permittedSubtypeClasses != null) {
++attributesCount;
size += 8 + permittedSubtypeClasses.length;
symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES);
}
int recordComponentCount = 0;
int recordSize = 0;
if (firstRecordComponent != null) {
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
++recordComponentCount;
recordSize += recordComponentWriter.computeRecordComponentInfoSize();
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
++attributesCount;
size += 8 + recordSize;
symbolTable.addConstantUtf8(Constants.RECORD);
}
if (firstAttribute != null) {
attributesCount += firstAttribute.getAttributeCount();
size += firstAttribute.computeAttributesSize(symbolTable);
Expand Down Expand Up @@ -630,6 +698,24 @@ public byte[] toByteArray() {
.putShort(numberOfNestMemberClasses)
.putByteArray(nestMemberClasses.data, 0, nestMemberClasses.length);
}
if (permittedSubtypeClasses != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.PERMITTED_SUBTYPES))
.putInt(permittedSubtypeClasses.length + 2)
.putShort(numberOfPermittedSubtypeClasses)
.putByteArray(permittedSubtypeClasses.data, 0, permittedSubtypeClasses.length);
}
if (firstRecordComponent != null) {
result
.putShort(symbolTable.addConstantUtf8(Constants.RECORD))
.putInt(recordSize + 2)
.putShort(recordComponentCount);
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
recordComponentWriter.putRecordComponentInfo(result);
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
}
if (firstAttribute != null) {
firstAttribute.putAttributes(symbolTable, result);
}
Expand Down Expand Up @@ -666,6 +752,10 @@ private byte[] replaceAsmInstructions(final byte[] classFile, final boolean hasF
nestHostClassIndex = 0;
numberOfNestMemberClasses = 0;
nestMemberClasses = null;
numberOfPermittedSubtypeClasses = 0;
permittedSubtypeClasses = null;
firstRecordComponent = null;
lastRecordComponent = null;
firstAttribute = null;
compute = hasFrames ? MethodWriter.COMPUTE_INSERTED_FRAMES : MethodWriter.COMPUTE_NOTHING;
new ClassReader(classFile, 0, /* checkClassVersion = */ false)
Expand Down Expand Up @@ -694,6 +784,11 @@ private Attribute[] getAttributePrototypes() {
methodWriter.collectAttributePrototypes(attributePrototypes);
methodWriter = (MethodWriter) methodWriter.mv;
}
RecordComponentWriter recordComponentWriter = firstRecordComponent;
while (recordComponentWriter != null) {
recordComponentWriter.collectAttributePrototypes(attributePrototypes);
recordComponentWriter = (RecordComponentWriter) recordComponentWriter.delegate;
}
return attributePrototypes.toArray();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
package jersey.repackaged.org.objectweb.asm;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Pattern;

/**
* Defines additional JVM opcodes, access flags and constants which are not part of the ASM public
Expand All @@ -34,7 +38,7 @@
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-6.html">JVMS 6</a>
* @author Eric Bruneton
*/
final class Constants implements Opcodes {
final class Constants {

// The ClassFile attribute names, in the order they are defined in
// https://docs.oracle.com/javase/specs/jvms/se11/html/jvms-4.html#jvms-4.7-300.
Expand Down Expand Up @@ -68,6 +72,8 @@ final class Constants implements Opcodes {
static final String MODULE_MAIN_CLASS = "ModuleMainClass";
static final String NEST_HOST = "NestHost";
static final String NEST_MEMBERS = "NestMembers";
static final String PERMITTED_SUBTYPES = "PermittedSubtypes";
static final String RECORD = "Record";

// ASM specific access flags.
// WARNING: the 16 least significant bits must NOT be used, to avoid conflicts with standard
Expand Down Expand Up @@ -140,7 +146,7 @@ final class Constants implements Opcodes {
// Constants to convert between normal and wide jump instructions.

// The delta between the GOTO_W and JSR_W opcodes and GOTO and JUMP.
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - GOTO;
static final int WIDE_JUMP_OPCODE_DELTA = GOTO_W - Opcodes.GOTO;

// Constants to convert JVM opcodes to the equivalent ASM specific opcodes, and vice versa.

Expand All @@ -153,25 +159,62 @@ final class Constants implements Opcodes {

// ASM specific opcodes, used for long forward jump instructions.

static final int ASM_IFEQ = IFEQ + ASM_OPCODE_DELTA;
static final int ASM_IFNE = IFNE + ASM_OPCODE_DELTA;
static final int ASM_IFLT = IFLT + ASM_OPCODE_DELTA;
static final int ASM_IFGE = IFGE + ASM_OPCODE_DELTA;
static final int ASM_IFGT = IFGT + ASM_OPCODE_DELTA;
static final int ASM_IFLE = IFLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPEQ = IF_ICMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPNE = IF_ICMPNE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLT = IF_ICMPLT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGE = IF_ICMPGE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGT = IF_ICMPGT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLE = IF_ICMPLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPEQ = IF_ACMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPNE = IF_ACMPNE + ASM_OPCODE_DELTA;
static final int ASM_GOTO = GOTO + ASM_OPCODE_DELTA;
static final int ASM_JSR = JSR + ASM_OPCODE_DELTA;
static final int ASM_IFNULL = IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFEQ = Opcodes.IFEQ + ASM_OPCODE_DELTA;
static final int ASM_IFNE = Opcodes.IFNE + ASM_OPCODE_DELTA;
static final int ASM_IFLT = Opcodes.IFLT + ASM_OPCODE_DELTA;
static final int ASM_IFGE = Opcodes.IFGE + ASM_OPCODE_DELTA;
static final int ASM_IFGT = Opcodes.IFGT + ASM_OPCODE_DELTA;
static final int ASM_IFLE = Opcodes.IFLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPEQ = Opcodes.IF_ICMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPNE = Opcodes.IF_ICMPNE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLT = Opcodes.IF_ICMPLT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGE = Opcodes.IF_ICMPGE + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPGT = Opcodes.IF_ICMPGT + ASM_OPCODE_DELTA;
static final int ASM_IF_ICMPLE = Opcodes.IF_ICMPLE + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPEQ = Opcodes.IF_ACMPEQ + ASM_OPCODE_DELTA;
static final int ASM_IF_ACMPNE = Opcodes.IF_ACMPNE + ASM_OPCODE_DELTA;
static final int ASM_GOTO = Opcodes.GOTO + ASM_OPCODE_DELTA;
static final int ASM_JSR = Opcodes.JSR + ASM_OPCODE_DELTA;
static final int ASM_IFNULL = Opcodes.IFNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_IFNONNULL = Opcodes.IFNONNULL + ASM_IFNULL_OPCODE_DELTA;
static final int ASM_GOTO_W = 220;

private Constants() {}

static void checkAsmExperimental(final Object caller) {
Class<?> callerClass = caller.getClass();
String internalName = callerClass.getName().replace('.', '/');
if (!isWhitelisted(internalName)) {
checkIsPreview(callerClass.getClassLoader().getResourceAsStream(internalName + ".class"));
}
}

static boolean isWhitelisted(final String internalName) {
if (!internalName.startsWith("org/objectweb/asm/")) {
return false;
}
String member = "(Annotation|Class|Field|Method|Module|RecordComponent|Signature)";
return internalName.contains("Test$")
|| Pattern.matches(
"org/objectweb/asm/util/Trace" + member + "Visitor(\\$.*)?", internalName)
|| Pattern.matches(
"org/objectweb/asm/util/Check" + member + "Adapter(\\$.*)?", internalName);
}

static void checkIsPreview(final InputStream classInputStream) {
if (classInputStream == null) {
throw new IllegalStateException("Bytecode not available, can't check class version");
}
int minorVersion;
try (DataInputStream callerClassStream = new DataInputStream(classInputStream); ) {
callerClassStream.readInt();
minorVersion = callerClassStream.readUnsignedShort();
} catch (IOException ioe) {
throw new IllegalStateException("I/O error, can't check class version", ioe);
}
if (minorVersion != 0xFFFF) {
throw new IllegalStateException(
"ASM9_EXPERIMENTAL can only be used by classes compiled with --enable-preview");
}
}
}
Loading

0 comments on commit d88025b

Please sign in to comment.