Skip to content

Commit b39631a

Browse files
committed
[GR-36602] Add AnnotationSupport guarantees.
PullRequest: graal/10905
2 parents 6ca460e + 6ad770d commit b39631a

File tree

10 files changed

+121
-35
lines changed

10 files changed

+121
-35
lines changed

compiler/src/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -2304,7 +2304,7 @@ private boolean tryNodePluginForInvocation(ValueNode[] args, ResolvedJavaMethod
23042304
* Otherwise, it returns the {@link InlineInfo} that lead to the decision to not inline it, or
23052305
* {@code null} if there is no {@link InlineInfo} for this method.
23062306
*/
2307-
private InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) {
2307+
protected InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) {
23082308
boolean canBeInlined = forceInliningEverything || parsingIntrinsic() || targetMethod.canBeInlined();
23092309
if (!canBeInlined) {
23102310
return null;

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/ObjectScanner.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ public static String asString(BigBang bb, JavaConstant constant, boolean appendT
315315
if (obj == null) {
316316
return "null";
317317
}
318-
String str = obj.getClass().getTypeName() + '@' + Integer.toHexString(System.identityHashCode(obj));
318+
String str = analysisType(bb, obj).toJavaName() + '@' + Integer.toHexString(System.identityHashCode(obj));
319319
if (appendToString) {
320320
try {
321321
str += ": " + limit(obj.toString(), 80).replace(System.lineSeparator(), "");
@@ -431,8 +431,8 @@ public ScanReason getPrevious() {
431431
}
432432

433433
public static class OtherReason extends ScanReason {
434-
public static final ScanReason RESCAN = new OtherReason("Manually triggered rescan");
435-
public static final ScanReason HUB = new OtherReason("DynamicHub scan");
434+
public static final ScanReason RESCAN = new OtherReason("manually triggered rescan");
435+
public static final ScanReason HUB = new OtherReason("scanning a class constant");
436436

437437
final String reason;
438438

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java

+1
Original file line numberDiff line numberDiff line change
@@ -718,6 +718,7 @@ public void runAnalysis(DebugContext debugContext, Function<AnalysisUniverse, Bo
718718
}
719719
/* Outer analysis loop is done. Check if heap verification modifies analysis. */
720720
if (!analysisModified()) {
721+
assert universe.getHeapVerifier().checkTypes();
721722
return;
722723
}
723724
}

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/heap/HeapSnapshotVerifier.java

+69-28
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ static class Options {
6363
private boolean analysisModified;
6464

6565
private final int verbosity;
66+
private int iterations;
6667

6768
public HeapSnapshotVerifier(BigBang bb, ImageHeap imageHeap, ImageHeapScanner scanner) {
6869
this.bb = bb;
@@ -76,6 +77,7 @@ public boolean requireAnalysisIteration(CompletionExecutor executor) throws Inte
7677
info("Verifying the heap snapshot...");
7778
analysisModified = false;
7879
heapPatched = false;
80+
iterations++;
7981
scannedObjects.reset();
8082
ObjectScanner objectScanner = new ObjectScanner(bb, executor, scannedObjects, new ScanningObserver());
8183
executor.start();
@@ -91,14 +93,24 @@ public boolean requireAnalysisIteration(CompletionExecutor executor) throws Inte
9193
if (analysisModified) {
9294
info("Heap verification modified the analysis state. Executing an additional analysis iteration.");
9395
} else {
94-
info("Heap verification didn't modify the analysis state. Exiting analysis.");
96+
info("Heap verification didn't modify the analysis state. Heap state stabilized after " + iterations + " iterations.");
97+
info("Exiting analysis.");
9598
}
9699
return analysisModified;
97100
}
98101

99102
protected void scanTypes(@SuppressWarnings("unused") ObjectScanner objectScanner) {
100103
}
101104

105+
public boolean checkTypes() {
106+
for (AnalysisType t : bb.getUniverse().getTypes()) {
107+
if (t.isReachable() && !initializationInfoComputed(t)) {
108+
throw AnalysisError.shouldNotReachHere("Type is not initialized " + t.getName());
109+
}
110+
}
111+
return true;
112+
}
113+
102114
public void cleanupAfterAnalysis() {
103115
scannedObjects = null;
104116
}
@@ -209,34 +221,56 @@ public void forEmbeddedRoot(JavaConstant root, ScanReason reason) {
209221

210222
@Override
211223
public void forScannedConstant(JavaConstant value, ScanReason reason) {
212-
AnalysisFuture<ImageHeapObject> task = imageHeap.getTask(value);
213224
Object object = constantAsObject(bb, value);
214-
if (object.getClass().equals(Class.class)) {
225+
Class<?> objectClass = object.getClass();
226+
if (objectClass.equals(Class.class)) {
227+
/*
228+
* Ensure that java.lang.Class constants are fully initialized and scanned. If a
229+
* type is marked as reachable during the verification then it's class
230+
* initialization info will be missing since
231+
* ClassInitializationFeature.buildClassInitializationInfo() hasn't processed it
232+
* yet.
233+
*/
215234
AnalysisType type = bb.getMetaAccess().lookupJavaType((Class<?>) object);
216-
if (type.isReachable() && !initializationInfoComputed(type)) {
217-
/*
218-
* This means that the type has been marked as reachable during the verification
219-
* and ClassInitializationFeature.buildClassInitializationInfo() hasn't
220-
* processed it yet. Allow ClassInitializationFeature to build the
221-
* DynamicHub.classInitializationInfo.
222-
*/
223-
onNoInitInfoForHub(value, reason);
235+
if (!initializationInfoComputed(type)) {
236+
onNoInitInfoForClassConstant(type, reason);
237+
} else {
238+
ensureTypeScanned(value, type, reason);
224239
}
225-
/* Make sure the DynamicHub value is scanned. */
226-
if (task == null) {
227-
onNoTaskForHub(value, reason);
228-
scanner.toImageHeapObject(value, reason, null);
229-
heapPatched = true;
240+
} else {
241+
/*
242+
* Ensure that the Class of any other constants are also fully initialized and
243+
* scanned. An object replacer can introduce new types which otherwise could be
244+
* missed by the verifier. For example
245+
* com.oracle.svm.hosted.annotation.AnnotationObjectReplacer creates annotation
246+
* proxy types on the fly for constant annotation objects.
247+
*/
248+
AnalysisType type = bb.getMetaAccess().lookupJavaType(objectClass);
249+
if (!initializationInfoComputed(type)) {
250+
onNoInitInfoForObjectType(value, type, reason);
230251
} else {
231-
if (task.isDone()) {
232-
JavaConstant snapshot = task.guardedGet().getObject();
233-
if (!Objects.equals(snapshot, value)) {
234-
throw error(reason, "Value mismatch for hub snapshot: %s %n new value: %s %n", snapshot, value);
235-
}
236-
} else {
237-
/* If there is a task for the hub it should have been triggered. */
238-
throw error(reason, "Snapshot not yet computed for hub %n new value: %s %n", value);
252+
ensureTypeScanned(bb.getConstantReflectionProvider().asJavaClass(type), type, reason);
253+
}
254+
}
255+
}
256+
257+
private void ensureTypeScanned(JavaConstant value, AnalysisType type, ScanReason reason) {
258+
AnalysisError.guarantee(type.isReachable(), "The heap snapshot verifier discovered a type not marked as reachable " + type.toJavaName());
259+
AnalysisFuture<ImageHeapObject> task = imageHeap.getTask(value);
260+
/* Make sure the DynamicHub value is scanned. */
261+
if (task == null) {
262+
onNoTaskForClassConstant(value, reason);
263+
scanner.toImageHeapObject(value, reason, null);
264+
heapPatched = true;
265+
} else {
266+
if (task.isDone()) {
267+
JavaConstant snapshot = task.guardedGet().getObject();
268+
if (!Objects.equals(snapshot, value)) {
269+
throw error(reason, "Value mismatch for class constant snapshot: %s %n new value: %s %n", snapshot, value);
239270
}
271+
} else {
272+
/* If there is a task for the hub it should have been triggered. */
273+
throw error(reason, "Snapshot not yet computed for class constant %n new value: %s %n", value);
240274
}
241275
}
242276
}
@@ -246,17 +280,24 @@ protected boolean initializationInfoComputed(@SuppressWarnings("unused") Analysi
246280
return true;
247281
}
248282

249-
private void onNoInitInfoForHub(JavaConstant value, ScanReason reason) {
283+
private void onNoInitInfoForClassConstant(AnalysisType type, ScanReason reason) {
284+
analysisModified = true;
285+
if (printAll()) {
286+
warning(reason, "No initialization info computed for class constant %s %n", type.toJavaName());
287+
}
288+
}
289+
290+
private void onNoInitInfoForObjectType(JavaConstant object, AnalysisType type, ScanReason reason) {
250291
analysisModified = true;
251292
if (printAll()) {
252-
warning(reason, "No initialization info computed for hub %s %n", value);
293+
warning(reason, "No initialization info computed for class %s of object %s %n", type.toJavaName(), object);
253294
}
254295
}
255296

256-
private void onNoTaskForHub(JavaConstant value, ScanReason reason) {
297+
private void onNoTaskForClassConstant(JavaConstant value, ScanReason reason) {
257298
analysisModified = true;
258299
if (printAll()) {
259-
warning(reason, "No snapshot task found for hub %s %n", value);
300+
warning(reason, "No snapshot task found for class constant %s %n", value);
260301
}
261302
}
262303

substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/FieldsOffsetsFeature.java

+8-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@
4545
import org.graalvm.nativeimage.hosted.Feature;
4646

4747
import com.oracle.graal.pointsto.api.DefaultUnsafePartition;
48+
import com.oracle.graal.pointsto.meta.AnalysisField;
49+
import com.oracle.svm.core.BuildPhaseProvider;
4850
import com.oracle.svm.core.annotate.RecomputeFieldValue;
4951
import com.oracle.svm.core.graal.GraalEdgeUnsafePartition;
5052
import com.oracle.svm.core.util.VMError;
@@ -162,6 +164,9 @@ private static Object replaceFieldsOffsets(Object source) {
162164
/* Invoked once for every class that is reachable in the native image. */
163165
private static void classReachabilityListener(DuringAnalysisAccess a, Class<?> newlyReachableClass) {
164166
DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl) a;
167+
if (BuildPhaseProvider.isAnalysisFinished()) {
168+
throw VMError.shouldNotReachHere("New class reachable after analysis: " + newlyReachableClass);
169+
}
165170

166171
if (Node.class.isAssignableFrom(newlyReachableClass) && newlyReachableClass != Node.class) {
167172
FieldsOffsetsFeature.<NodeClass<?>> registerClass(newlyReachableClass, GraalSupport.get().nodeClasses, NodeClass::get, false, access);
@@ -214,7 +219,9 @@ private static void registerFields(Fields fields, UnsafePartitionKind partitionK
214219
getReplacements().put(fields.getOffsets(), new FieldsOffsetsReplacement(fields));
215220

216221
for (int i = 0; i < fields.getCount(); i++) {
217-
config.registerAsUnsafeAccessed(config.getMetaAccess().lookupJavaField(findField(fields, i)), partitionKind);
222+
AnalysisField aField = config.getMetaAccess().lookupJavaField(findField(fields, i));
223+
aField.getType().registerAsReachable();
224+
config.registerAsUnsafeAccessed(aField, partitionKind);
218225
}
219226
}
220227

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

+4
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
import com.oracle.graal.pointsto.meta.HostedProviders;
8484
import com.oracle.graal.pointsto.phases.InlineBeforeAnalysisPolicy;
8585
import com.oracle.graal.pointsto.util.GraalAccess;
86+
import com.oracle.svm.core.BuildPhaseProvider;
8687
import com.oracle.svm.core.RuntimeAssertionsSupport;
8788
import com.oracle.svm.core.SubstrateOptions;
8889
import com.oracle.svm.core.SubstrateUtil;
@@ -272,6 +273,9 @@ public void initializeType(AnalysisType analysisType) {
272273
if (!analysisType.isReachable()) {
273274
throw VMError.shouldNotReachHere("Registering and initializing a type that was not yet marked as reachable: " + analysisType);
274275
}
276+
if (BuildPhaseProvider.isAnalysisFinished()) {
277+
throw VMError.shouldNotReachHere("Initializing type after analysis: " + analysisType);
278+
}
275279

276280
/* Decide when the type should be initialized. */
277281
classInitializationSupport.maybeInitializeHosted(analysisType);

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import com.oracle.graal.pointsto.meta.AnalysisType;
3939
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
4040
import com.oracle.graal.pointsto.util.AnalysisError;
41+
import com.oracle.svm.core.BuildPhaseProvider;
4142
import com.oracle.svm.core.RuntimeAssertionsSupport;
4243
import com.oracle.svm.core.annotate.InjectAccessors;
4344
import com.oracle.svm.core.graal.meta.SharedConstantReflectionProvider;
@@ -327,6 +328,9 @@ protected static void registerAsReachable(SVMHost hostVM, DynamicHub dynamicHub)
327328
assert dynamicHub != null;
328329
/* Make sure that the DynamicHub of this type ends up in the native image. */
329330
AnalysisType valueType = hostVM.lookupType(dynamicHub);
331+
if (!valueType.isReachable() && BuildPhaseProvider.isAnalysisFinished()) {
332+
throw VMError.shouldNotReachHere("Registering type as reachable after analysis: " + valueType);
333+
}
330334
valueType.registerAsReachable();
331335
}
332336

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/DynamicHubInitializer.java

+5
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,12 @@
4242
import com.oracle.graal.pointsto.meta.AnalysisField;
4343
import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
4444
import com.oracle.graal.pointsto.meta.AnalysisType;
45+
import com.oracle.svm.core.BuildPhaseProvider;
4546
import com.oracle.svm.core.hub.AnnotatedSuperInfo;
4647
import com.oracle.svm.core.hub.DynamicHub;
4748
import com.oracle.svm.core.hub.GenericInfo;
4849
import com.oracle.svm.core.meta.SubstrateObjectConstant;
50+
import com.oracle.svm.core.util.VMError;
4951
import com.oracle.svm.hosted.SVMHost;
5052
import com.oracle.svm.util.ReflectionUtil;
5153

@@ -93,6 +95,9 @@ public DynamicHubInitializer(AnalysisMetaAccess metaAccess, UnsupportedFeatures
9395

9496
public void initializeMetaData(ImageHeapScanner heapScanner, AnalysisType type) {
9597
assert type.isReachable() : "Type " + type.toJavaName(true) + " is not marked as reachable.";
98+
if (BuildPhaseProvider.isAnalysisFinished()) {
99+
throw VMError.shouldNotReachHere("Initializing type metadata after analysis: " + type);
100+
}
96101

97102
Class<?> javaClass = type.getJavaClass();
98103
heapScanner.rescanObject(javaClass.getPackage());

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/SVMImageHeapVerifier.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ private static boolean imageStateModified() {
7070

7171
@Override
7272
protected void scanTypes(ObjectScanner objectScanner) {
73-
SVMHost svmHost = (SVMHost) bb.getHostVM();
73+
SVMHost svmHost = svmHost();
7474
/* First make sure that all DynamicHub fields are initialized and scanned. */
7575
bb.getUniverse().getTypes().stream().filter(AnalysisType::isReachable).forEach(((NativeImagePointsToAnalysis) bb)::initializeMetaData);
7676
/* Then verify the snapshots of reachable types, i.e., compare them with hosted values. */
@@ -84,7 +84,11 @@ private static void verifyHub(SVMHost svmHost, ObjectScanner objectScanner, Anal
8484

8585
@Override
8686
protected boolean initializationInfoComputed(AnalysisType type) {
87-
DynamicHub hub = ((SVMHost) bb.getHostVM()).dynamicHub(type);
87+
DynamicHub hub = svmHost().dynamicHub(type);
8888
return hub.getClassInitializationInfo() != null;
8989
}
90+
91+
private SVMHost svmHost() {
92+
return (SVMHost) bb.getHostVM();
93+
}
9094
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SubstrateGraphBuilderPhase.java

+20
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,17 @@
2727
import org.graalvm.compiler.java.BytecodeParser;
2828
import org.graalvm.compiler.java.GraphBuilderPhase;
2929
import org.graalvm.compiler.nodes.StructuredGraph;
30+
import org.graalvm.compiler.nodes.ValueNode;
3031
import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
32+
import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
3133
import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
3234
import org.graalvm.compiler.nodes.spi.CoreProviders;
3335
import org.graalvm.compiler.phases.OptimisticOptimizations;
3436
import org.graalvm.compiler.word.WordTypes;
3537

38+
import com.oracle.graal.pointsto.meta.AnalysisMethod;
39+
import com.oracle.graal.pointsto.meta.AnalysisType;
40+
3641
import jdk.vm.ci.meta.ResolvedJavaMethod;
3742

3843
public class SubstrateGraphBuilderPhase extends SharedGraphBuilderPhase {
@@ -52,5 +57,20 @@ public SubstrateBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance,
5257
IntrinsicContext intrinsicContext, boolean explicitExceptionEdges) {
5358
super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext, explicitExceptionEdges);
5459
}
60+
61+
@Override
62+
protected InlineInfo tryInline(ValueNode[] args, ResolvedJavaMethod targetMethod) {
63+
InlineInfo inlineInfo = super.tryInline(args, targetMethod);
64+
if (inlineInfo == InlineInfo.DO_NOT_INLINE_WITH_EXCEPTION && targetMethod instanceof AnalysisMethod) {
65+
/*
66+
* The target methods of intrinsified calls are still present in the image so their
67+
* type is reachable. The methods are used as keys in the
68+
* InvocationPlugins.resolvedRegistrations map reachable from
69+
* SubstrateReplacements.snippetInvocationPlugins.
70+
*/
71+
((AnalysisType) targetMethod.getDeclaringClass()).registerAsReachable();
72+
}
73+
return inlineInfo;
74+
}
5575
}
5676
}

0 commit comments

Comments
 (0)