Commit 184e82c8 authored by Eric Bruneton's avatar Eric Bruneton
Browse files

Add an abstract MemberVisitor class to be able to reduce code duplication in...

Add an abstract MemberVisitor class to be able to reduce code duplication in ClassReader. Not sure if the class and/or its methods must be public.

Results of 3 benchmark runs with this change:

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  623,892 ± 1,506  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  621,629 ± 1,835  ops/s

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  624,589 ± 1,260  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  622,971 ± 2,541  ops/s

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  623,515 ± 1,680  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  622,151 ± 1,619  ops/s

and without it:

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  624,141 ± 1,511  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  625,117 ± 1,653  ops/s

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  607,326 ± 1,285  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  621,902 ± 1,259  ops/s

Benchmark                          Mode  Cnt    Score   Error  Units
AdapterBenchmark.read_asm7_1      thrpt   30  623,548 ± 1,490  ops/s
AdapterBenchmark.read_asmCurrent  thrpt   30  621,814 ± 1,579  ops/s
parent 8486f103
Pipeline #6815 passed with stage
in 9 minutes and 52 seconds
......@@ -568,98 +568,14 @@ public class ClassReader {
classVisitor.visitOuterClass(className, name, type);
}
// Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleAnnotations attribute.
if (runtimeInvisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeVisibleTypeAnnotations attribute.
if (runtimeVisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleTypeAnnotations attribute.
if (runtimeInvisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
classVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the non standard attributes.
while (attributes != null) {
// Copy and reset the nextAttribute field so that it can also be used in ClassWriter.
Attribute nextAttribute = attributes.nextAttribute;
attributes.nextAttribute = null;
classVisitor.visitAttribute(attributes);
attributes = nextAttribute;
}
readMember(
classVisitor,
context,
runtimeVisibleAnnotationsOffset,
runtimeInvisibleAnnotationsOffset,
runtimeVisibleTypeAnnotationsOffset,
runtimeInvisibleTypeAnnotationsOffset,
attributes);
// Visit the NestedMembers attribute.
if (nestMembersOffset != 0) {
......@@ -696,7 +612,7 @@ public class ClassReader {
}
}
// Visit Record components.
// Visit the Record attribute.
if (recordOffset != 0) {
int recordComponentsCount = readUnsignedShort(recordOffset);
recordOffset += 2;
......@@ -931,6 +847,8 @@ public class ClassReader {
return currentOffset;
}
// TODO: replace all code below with readMember() call, when no longer experimental.
// Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
......@@ -1113,105 +1031,19 @@ public class ClassReader {
// Visit the field declaration.
FieldVisitor fieldVisitor =
classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
if (fieldVisitor == null) {
return currentOffset;
}
// Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleAnnotations attribute.
if (runtimeInvisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeVisibleTypeAnnotations attribute.
if (runtimeVisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
fieldVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the RuntimeInvisibleTypeAnnotations attribute.
if (runtimeInvisibleTypeAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
while (numAnnotations-- > 0) {
// Parse the target_type, target_info and target_path fields.
currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
// Parse the type_index field.
String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
currentAnnotationOffset += 2;
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
fieldVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
/* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
}
}
// Visit the non standard attributes.
while (attributes != null) {
// Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
Attribute nextAttribute = attributes.nextAttribute;
attributes.nextAttribute = null;
fieldVisitor.visitAttribute(attributes);
attributes = nextAttribute;
if (fieldVisitor != null) {
readMember(
fieldVisitor,
context,
runtimeVisibleAnnotationsOffset,
runtimeInvisibleAnnotationsOffset,
runtimeVisibleTypeAnnotationsOffset,
runtimeInvisibleTypeAnnotationsOffset,
attributes);
// Visit the end of the field.
fieldVisitor.visitEnd();
}
// Visit the end of the field.
fieldVisitor.visitEnd();
return currentOffset;
}
......@@ -1378,6 +1210,69 @@ public class ClassReader {
}
}
readMember(
methodVisitor,
context,
runtimeVisibleAnnotationsOffset,
runtimeInvisibleAnnotationsOffset,
runtimeVisibleTypeAnnotationsOffset,
runtimeInvisibleTypeAnnotationsOffset,
attributes);
// Visit the RuntimeVisibleParameterAnnotations attribute.
if (runtimeVisibleParameterAnnotationsOffset != 0) {
readParameterAnnotations(
methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
}
// Visit the RuntimeInvisibleParameterAnnotations attribute.
if (runtimeInvisibleParameterAnnotationsOffset != 0) {
readParameterAnnotations(
methodVisitor,
context,
runtimeInvisibleParameterAnnotationsOffset,
/* visible = */ false);
}
// Visit the Code attribute.
if (codeOffset != 0) {
methodVisitor.visitCode();
readCode(methodVisitor, context, codeOffset);
}
// Visit the end of the method.
methodVisitor.visitEnd();
return currentOffset;
}
/**
* Reads the annotations, type annotations and non standard attributes of a class, field, method
* or record component.
*
* @param memberVisitor the visitor that must visit the annotations and attributes.
* @param context information about the class being parsed.
* @param runtimeVisibleAnnotationsOffset The offset of the RuntimeVisibleAnnotations attribute,
* or 0.
* @param runtimeInvisibleAnnotationsOffset The offset of the RuntimeInvisibleAnnotations
* attribute, or 0.
* @param runtimeVisibleTypeAnnotationsOffset The offset of the RuntimeVisibleTypeAnnotations
* attribute, or 0.
* @param runtimeInvisibleTypeAnnotationsOffset The offset of the RuntimeInvisibleTypeAnnotations
* attribute, or 0.
* @param attributes The non standard attributes (linked with their {@link
* Attribute#nextAttribute} field). This list in the <i>reverse order</i> or their order in
* the ClassFile structure.
*/
private void readMember(
final MemberVisitor memberVisitor,
final Context context,
final int runtimeVisibleAnnotationsOffset,
final int runtimeInvisibleAnnotationsOffset,
final int runtimeVisibleTypeAnnotationsOffset,
final int runtimeInvisibleTypeAnnotationsOffset,
final Attribute attributes) {
char[] charBuffer = context.charBuffer;
// Visit the RuntimeVisibleAnnotations attribute.
if (runtimeVisibleAnnotationsOffset != 0) {
int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
......@@ -1389,7 +1284,7 @@ public class ClassReader {
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
memberVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
......@@ -1407,7 +1302,7 @@ public class ClassReader {
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
methodVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
memberVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
currentAnnotationOffset,
/* named = */ true,
charBuffer);
......@@ -1427,7 +1322,7 @@ public class ClassReader {
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
methodVisitor.visitTypeAnnotation(
memberVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
......@@ -1451,7 +1346,7 @@ public class ClassReader {
// Parse num_element_value_pairs and element_value_pairs and visit these values.
currentAnnotationOffset =
readElementValues(
methodVisitor.visitTypeAnnotation(
memberVisitor.visitTypeAnnotation(
context.currentTypeAnnotationTarget,
context.currentTypeAnnotationTargetPath,
annotationDescriptor,
......@@ -1462,39 +1357,15 @@ public class ClassReader {
}
}
// Visit the RuntimeVisibleParameterAnnotations attribute.
if (runtimeVisibleParameterAnnotationsOffset != 0) {
readParameterAnnotations(
methodVisitor, context, runtimeVisibleParameterAnnotationsOffset, /* visible = */ true);
}
// Visit the RuntimeInvisibleParameterAnnotations attribute.
if (runtimeInvisibleParameterAnnotationsOffset != 0) {
readParameterAnnotations(
methodVisitor,
context,
runtimeInvisibleParameterAnnotationsOffset,
/* visible = */ false);
}
// Visit the non standard attributes.
while (attributes != null) {
// Copy and reset the nextAttribute field so that it can also be used in MethodWriter.
Attribute nextAttribute = attributes.nextAttribute;
attributes.nextAttribute = null;
methodVisitor.visitAttribute(attributes);
attributes = nextAttribute;
Attribute attributeList = attributes;
while (attributeList != null) {
// Copy and reset the nextAttribute field so that it can also be used in the *Writer class.
Attribute nextAttribute = attributeList.nextAttribute;
attributeList.nextAttribute = null;
memberVisitor.visitAttribute(attributes);
attributeList = nextAttribute;
}
// Visit the Code attribute.
if (codeOffset != 0) {
methodVisitor.visitCode();
readCode(methodVisitor, context, codeOffset);
}
// Visit the end of the method.
methodVisitor.visitEnd();
return currentOffset;
}
// ----------------------------------------------------------------------------------------------
......
......@@ -36,7 +36,7 @@ package org.objectweb.asm;
*
* @author Eric Bruneton
*/
public abstract class ClassVisitor {
public abstract class ClassVisitor extends MemberVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
......@@ -185,6 +185,7 @@ public abstract class ClassVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (cv != null) {
return cv.visitAnnotation(descriptor, visible);
......@@ -207,6 +208,7 @@ public abstract class ClassVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
......@@ -223,6 +225,7 @@ public abstract class ClassVisitor {
*
* @param attribute an attribute.
*/
@Override
public void visitAttribute(final Attribute attribute) {
if (cv != null) {
cv.visitAttribute(attribute);
......@@ -371,6 +374,7 @@ public abstract class ClassVisitor {
* Visits the end of the class. This method, which is the last one to be called, is used to inform
* the visitor that all the fields and methods of the class have been visited.
*/
@Override
public void visitEnd() {
if (cv != null) {
cv.visitEnd();
......
......@@ -34,7 +34,7 @@ package org.objectweb.asm;
*
* @author Eric Bruneton
*/
public abstract class FieldVisitor {
public abstract class FieldVisitor extends MemberVisitor {
/**
* The ASM API version implemented by this visitor. The value of this field must be one of {@link
......@@ -86,6 +86,7 @@ public abstract class FieldVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (fv != null) {
return fv.visitAnnotation(descriptor, visible);
......@@ -106,6 +107,7 @@ public abstract class FieldVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
......@@ -122,6 +124,7 @@ public abstract class FieldVisitor {
*
* @param attribute an attribute.
*/
@Override
public void visitAttribute(final Attribute attribute) {
if (fv != null) {
fv.visitAttribute(attribute);
......@@ -132,6 +135,7 @@ public abstract class FieldVisitor {
* Visits the end of the field. This method, which is the last one to be called, is used to inform
* the visitor that all the annotations and attributes of the field have been visited.
*/
@Override
public void visitEnd() {
if (fv != null) {
fv.visitEnd();
......
package org.objectweb.asm;
/**
* A visitor to visit a Java class, field, method or record component.
*
* @author Eric Bruneton
*/
abstract class MemberVisitor {
/**
* Visits an annotation of the member.
*
* @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.
*/
abstract AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible);
/**
* Visits an annotation on the type of the member.
*
* @param typeRef a reference to the annotated type.
* @param typePath the path to the annotated type argument, wildcard bound, array element type, or
* static inner type within 'typeRef'. May be {@literal null} if the annotation targets
* 'typeRef' as a whole.
* @param descriptor the class descriptor of the annotation class.
* @param visible {@literal true} if the annotation is visible at runtime.
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
abstract AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible);
/**
* Visits a non standard attribute of the member.
*
* @param attribute an attribute.
*/
abstract void visitAttribute(final Attribute attribute);
/** Visits the end of the member. */
abstract void visitEnd();
}
......@@ -46,7 +46,7 @@ package org.objectweb.asm;
*
* @author Eric Bruneton
*/
public abstract class MethodVisitor {
public abstract class MethodVisitor extends MemberVisitor {
private static final String REQUIRES_ASM5 = "This feature requires ASM5";
......@@ -137,6 +137,7 @@ public abstract class MethodVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitAnnotation(final String descriptor, final boolean visible) {
if (mv != null) {
return mv.visitAnnotation(descriptor, visible);
......@@ -160,6 +161,7 @@ public abstract class MethodVisitor {
* @return a visitor to visit the annotation values, or {@literal null} if this visitor is not
* interested in visiting this annotation.
*/
@Override
public AnnotationVisitor visitTypeAnnotation(
final int typeRef, final TypePath typePath, final String descriptor, final boolean visible) {
if (api < Opcodes.ASM5) {
......@@ -218,6 +220,7 @@ public abstract class MethodVisitor {
*
* @param attribute an attribute.
*/
@Override
public void visitAttribute(final Attribute attribute) {
if (mv != null) {
mv.visitAttribute(attribute);
......@@ -776,6 +779,7 @@ public abstract class MethodVisitor {
* Visits the end of the method. This method, which is the last one to be called, is used to
* inform the visitor that all the annotations and attributes of the method have been visited.
*/
@Override
public void visitEnd() {
if (mv != null) {
mv.visitEnd();
......
......@@ -36,6 +36,7 @@ package org.objectweb.asm;
* @author Eric Bruneton
* @deprecated this API is experimental.
*/
// TODO: extend MemberVisitor when no longer experimental.
@Deprecated
public abstract class RecordComponentVisitor {
/**
......
......@@ -33,7 +33,7 @@ buildscript {
plugins { id 'biz.aQute.bnd.builder' version '4.2.0' apply false }
plugins { id 'com.github.sherter.google-java-format' version '0.8' apply false }
plugins { id 'me.champeau.gradle.jmh' version '0.4.8' apply false }
plugins { id 'me.champeau.gradle.jmh' version '0.5.0-rc-2' apply false }
plugins { id 'org.sonarqube' version '2.7.1' apply false }
description = 'ASM, a very small and fast Java bytecode manipulation framework'
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment