Skip to content

Commit

Permalink
Avoid needless instantiations of memberless annotation literals
Browse files Browse the repository at this point in the history
A lot of annotation types for which we construct annotation literal classes
have no members. For such types, creating a new instance for each usage
is a waste of resources; a singleton instance is always sufficient.
  • Loading branch information
Ladicek authored and igorregis committed Oct 16, 2022
1 parent 16f6945 commit c680fcc
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.quarkus.arc.processor.AnnotationLiteralProcessor.AnnotationLiteralClassInfo;
import io.quarkus.arc.processor.AnnotationLiteralProcessor.CacheKey;
import io.quarkus.arc.processor.ResourceOutput.Resource;
import io.quarkus.gizmo.BranchResult;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.FieldCreator;
Expand Down Expand Up @@ -119,6 +120,7 @@ private void createAnnotationLiteralClass(ClassOutput classOutput, AnnotationLit

MethodCreator constructor = annotationLiteral.getMethodCreator(Methods.INIT, "V",
literal.annotationMembers().stream().map(m -> m.returnType().name().toString()).toArray());

constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(AnnotationLiteral.class), constructor.getThis());

int constructorParameterIndex = 0;
Expand All @@ -141,7 +143,35 @@ private void createAnnotationLiteralClass(ClassOutput classOutput, AnnotationLit
}
constructor.returnValue(null);

generateStaticFieldsWithDefaultValues(annotationLiteral, literal.annotationMembers());
if (literal.annotationMembers().isEmpty()) {
constructor.setModifiers(ACC_PRIVATE);

FieldCreator singleton = annotationLiteral.getFieldCreator("INSTANCE", generatedName);
singleton.setModifiers(ACC_PUBLIC | ACC_STATIC | ACC_FINAL);

MethodCreator staticInit = annotationLiteral.getMethodCreator(Methods.CLINIT, void.class);
staticInit.setModifiers(ACC_STATIC);
ResultHandle singletonInstance = staticInit.newInstance(constructor.getMethodDescriptor());
staticInit.writeStaticField(singleton.getFieldDescriptor(), singletonInstance);
staticInit.returnValue(null);

// only one instance ever exists
MethodCreator equals = annotationLiteral.getMethodCreator("equals", boolean.class, Object.class);
BranchResult equality = equals.ifReferencesEqual(equals.readStaticField(singleton.getFieldDescriptor()),
equals.getMethodParam(0));
equality.trueBranch().returnValue(equality.trueBranch().load(true));
equality.falseBranch().returnValue(equality.falseBranch().load(false));

// consistent with AnnotationLiteral's default `hashCode` implementation
MethodCreator hashCode = annotationLiteral.getMethodCreator("hashCode", int.class);
hashCode.returnValue(hashCode.load(0));

// consistent with AnnotationLiteral's default `toString` implementation
MethodCreator toString = annotationLiteral.getMethodCreator("toString", String.class);
toString.returnValue(toString.load("@" + literal.annotationClass.name() + "()"));
} else {
generateStaticFieldsWithDefaultValues(annotationLiteral, literal.annotationMembers());
}

annotationLiteral.close();
LOGGER.debugf("Annotation literal class generated: %s", literal.generatedClassName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@ public ResultHandle create(BytecodeCreator bytecode, ClassInfo annotationClass,
Objects.requireNonNull(annotationClass, "Annotation class not available: " + annotationInstance);
AnnotationLiteralClassInfo literal = cache.getValue(new CacheKey(annotationClass));

if (literal.annotationMembers().isEmpty()) {
return bytecode.readStaticField(FieldDescriptor.of(literal.generatedClassName, "INSTANCE",
literal.generatedClassName));
}

ResultHandle[] constructorParameters = new ResultHandle[literal.annotationMembers().size()];

int constructorParameterIndex = 0;
Expand Down Expand Up @@ -384,9 +389,9 @@ static class AnnotationLiteralClassInfo {
* Name of the generated annotation literal class.
*/
final String generatedClassName;

/**
* Whether the generated annotation literal class is an application class.
* Only used when sharing is enabled.
*/
final boolean isApplicationClass;

Expand Down

0 comments on commit c680fcc

Please sign in to comment.