Skip to content

Commit be64112

Browse files
committed
[GR-33184] Disable optimization for LocatableAnnotation.
PullRequest: graal/9603
2 parents a3a1e5f + 9d29c95 commit be64112

File tree

2 files changed

+49
-18
lines changed

2 files changed

+49
-18
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@
5959
import java.util.stream.Collectors;
6060
import java.util.stream.StreamSupport;
6161

62-
import com.oracle.graal.pointsto.BigBang;
63-
import com.oracle.svm.hosted.analysis.Inflation;
64-
import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis;
6562
import org.graalvm.collections.EconomicSet;
6663
import org.graalvm.collections.Pair;
6764
import org.graalvm.compiler.api.replacements.Fold;
@@ -136,6 +133,7 @@
136133
import org.graalvm.word.PointerBase;
137134

138135
import com.oracle.graal.pointsto.AnalysisPolicy;
136+
import com.oracle.graal.pointsto.BigBang;
139137
import com.oracle.graal.pointsto.BytecodeSensitiveAnalysisPolicy;
140138
import com.oracle.graal.pointsto.DefaultAnalysisPolicy;
141139
import com.oracle.graal.pointsto.api.PointstoOptions;
@@ -228,6 +226,8 @@
228226
import com.oracle.svm.hosted.FeatureImpl.OnAnalysisExitAccessImpl;
229227
import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider;
230228
import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider;
229+
import com.oracle.svm.hosted.analysis.Inflation;
230+
import com.oracle.svm.hosted.analysis.NativeImagePointsToAnalysis;
231231
import com.oracle.svm.hosted.analysis.SVMAnalysisMetaAccess;
232232
import com.oracle.svm.hosted.annotation.AnnotationSupport;
233233
import com.oracle.svm.hosted.c.CAnnotationProcessorCache;
@@ -1437,6 +1437,10 @@ private static boolean addAssertionLIRPhases(LIRSuites lirSuites, boolean hosted
14371437
return true;
14381438
}
14391439

1440+
private static String format(TypeState state) {
1441+
return state.typesStream().map(t -> t.toJavaName(true)).collect(Collectors.joining(","));
1442+
}
1443+
14401444
private void checkUniverse() {
14411445
if (bb instanceof NativeImagePointsToAnalysis) {
14421446
NativeImagePointsToAnalysis bigbang = (NativeImagePointsToAnalysis) this.bb;
@@ -1460,7 +1464,8 @@ private void checkUniverse() {
14601464
String methodKey = method.format("%H.%n(%p)");
14611465
bigbang.getUnsupportedFeatures().addMessage(methodKey, method,
14621466
"Parameter " + i + " of " + methodKey + " has declared type " + declaredType.toJavaName(true) +
1463-
" with state " + declaredTypeState + " which is incompatible with types in parameter state: " + parameterState);
1467+
", with assignable types: " + format(declaredTypeState) +
1468+
", which is incompatible with analysis inferred types: " + format(parameterState) + ".");
14641469
}
14651470
}
14661471
}
@@ -1471,11 +1476,14 @@ private void checkUniverse() {
14711476
if (state != null) {
14721477
AnalysisType declaredType = field.getType();
14731478
if (declaredType.isInterface()) {
1474-
state = TypeState.forSubtraction(bigbang, state, declaredType.getAssignableTypes(true));
1479+
TypeState declaredTypeState = declaredType.getAssignableTypes(true);
1480+
state = TypeState.forSubtraction(bigbang, state, declaredTypeState);
14751481
if (!state.isEmpty()) {
14761482
String fieldKey = field.format("%H.%n");
14771483
bigbang.getUnsupportedFeatures().addMessage(fieldKey, null,
1478-
"Field " + fieldKey + " has declared type " + declaredType.toJavaName(true) + " which is incompatible with types in state: " + state);
1484+
"Field " + fieldKey + " has declared type " + declaredType.toJavaName(true) +
1485+
", with assignable types: " + format(declaredTypeState) +
1486+
", which is incompatible with analysis inferred types: " + format(state) + ".");
14791487
}
14801488
}
14811489
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationSupport.java

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
*/
2525
package com.oracle.svm.hosted.annotation;
2626

27-
import java.lang.annotation.Annotation;
2827
import java.lang.reflect.InvocationHandler;
2928
import java.lang.reflect.Modifier;
3029
import 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

Comments
 (0)