2424 */
2525package com .oracle .svm .hosted .annotation ;
2626
27- import java .lang .annotation .Annotation ;
2827import java .lang .reflect .InvocationHandler ;
2928import java .lang .reflect .Modifier ;
3029import java .lang .reflect .Proxy ;
@@ -125,7 +124,6 @@ public class AnnotationSupport extends CustomSubstitution<AnnotationSubstitution
125124
126125 private final SnippetReflectionProvider snippetReflection ;
127126
128- private final ResolvedJavaType javaLangAnnotationAnnotation ;
129127 private final ResolvedJavaType javaLangReflectProxy ;
130128 private final ResolvedJavaType constantAnnotationMarkerOriginalType ;
131129
@@ -143,7 +141,6 @@ public AnnotationSupport(MetaAccessProvider metaAccess, SnippetReflectionProvide
143141 super (metaAccess );
144142 this .snippetReflection = snippetReflection ;
145143
146- javaLangAnnotationAnnotation = metaAccess .lookupJavaType (java .lang .annotation .Annotation .class );
147144 javaLangReflectProxy = metaAccess .lookupJavaType (java .lang .reflect .Proxy .class );
148145 constantAnnotationMarkerOriginalType = metaAccess .lookupJavaType (constantAnnotationMarkerInterface );
149146 constantAnnotationMarkerSubstitutionType = new ConstantAnnotationMarkerSubstitutionType (constantAnnotationMarkerOriginalType , this );
@@ -153,16 +150,35 @@ public AnnotationSupport(MetaAccessProvider metaAccess, SnippetReflectionProvide
153150
154151 private boolean isConstantAnnotationType (ResolvedJavaType type ) {
155152 /*
156- * Check if the type implements all of Annotation, Proxy and the constant-annotation-marker
157- * interface. If so, then it is the type of a annotation proxy object encountered during
153+ * Check if the type implements all of: Annotation, Proxy and the constant-annotation-marker
154+ * interface. If so, then it is the type of an annotation proxy object encountered during
158155 * heap scanning. Only those types are substituted with a more efficient annotation proxy
159- * type implementation. If a type implements only Annotation and Proxy but not the
160- * constant-annotation-marker interface then it is a proxy type registered via the dynamic
161- * proxy API. Such type is used to allocate annotation instances at run time and must not be
162- * replaced.
156+ * type implementation.
157+ *
158+ * If a type implements only Annotation and Proxy but not the constant-annotation-marker
159+ * interface then it is a proxy type registered via the dynamic proxy API. Such type is used
160+ * to allocate annotation instances at run time and must not be replaced.
161+ *
162+ * If the type implements more than two interfaces then it could be a non-standard
163+ * annotation implementations like
164+ * com.sun.xml.internal.bind.v2.model.annotation.LocatableAnnotation, i.e., an annotation
165+ * wrapper that also implements com.sun.xml.internal.bind.v2.model.annotation.Locatable. We
166+ * don't optimize these types; the implementation would be too complicated for a marginal
167+ * benefit. Therefore, the type must implement two and only two interfaces: the annotation
168+ * interface and the marker interface.
163169 */
164- return javaLangAnnotationAnnotation .isAssignableFrom (type ) && javaLangReflectProxy .isAssignableFrom (type ) &&
165- constantAnnotationMarkerOriginalType .isAssignableFrom (type );
170+ return type .getInterfaces ().length == 2 &&
171+ isAnnotation (type .getInterfaces ()[0 ]) &&
172+ type .getInterfaces ()[1 ].equals (constantAnnotationMarkerOriginalType ) &&
173+ javaLangReflectProxy .isAssignableFrom (type );
174+ }
175+
176+ /* Value copied from java.lang.Class. */
177+ private static final int ANNOTATION = 0x00002000 ;
178+
179+ /* Method copied from java.lang.Class. */
180+ private static boolean isAnnotation (ResolvedJavaType type ) {
181+ return (type .getModifiers () & ANNOTATION ) != 0 ;
166182 }
167183
168184 @ Override
@@ -665,7 +681,14 @@ class AnnotationObjectReplacer implements Function<Object, Object> {
665681 @ Override
666682 public Object apply (Object original ) {
667683 Class <?> clazz = original .getClass ();
668- if (Annotation .class .isAssignableFrom (clazz ) && Proxy .class .isAssignableFrom (clazz )) {
684+ /*
685+ * We only optimize standard implementation annotation types, i.e., the type must implement
686+ * one and only one interface: the annotation interface, which in turn must implement
687+ * java.lang.Annotation. Non-standard annotation implementations use their default
688+ * implementation at run time.
689+ */
690+ if (clazz .getInterfaces ().length == 1 && clazz .getInterfaces ()[0 ].isAnnotation () &&
691+ Proxy .class .isAssignableFrom (clazz )) {
669692 return objectCache .computeIfAbsent (original , AnnotationObjectReplacer ::replacementComputer );
670693 } else if (original instanceof SubstrateAnnotationInvocationHandler ) {
671694 return SINGLETON_HANDLER ;
0 commit comments