Skip to content

Commit d15bb24

Browse files
committed
Refactor heap scanning.
1 parent dfe307e commit d15bb24

File tree

57 files changed

+1473
-152
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1473
-152
lines changed

sdk/src/org.graalvm.nativeimage/snapshot.sigtest

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,7 @@ CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$Dur
878878
intf org.graalvm.nativeimage.hosted.Feature$BeforeAnalysisAccess
879879
intf org.graalvm.nativeimage.hosted.Feature$QueryReachabilityAccess
880880
meth public abstract void requireAnalysisIteration()
881+
meth public abstract void rescanObject(java.lang.Object)
881882

882883
CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$DuringSetupAccess
883884
outer org.graalvm.nativeimage.hosted.Feature

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/Feature.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ interface DuringAnalysisAccess extends BeforeAnalysisAccess, QueryReachabilityAc
277277
* @since 19.0
278278
*/
279279
void requireAnalysisIteration();
280+
281+
/**
282+
* Rescan an object to be included in the image heap.
283+
*
284+
* @since 22.0
285+
*/
286+
void rescanObject(Object obj);
280287
}
281288

282289
/**

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import org.graalvm.compiler.options.OptionValues;
3434

35+
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
3536
import com.oracle.graal.pointsto.flow.AbstractSpecialInvokeTypeFlow;
3637
import com.oracle.graal.pointsto.flow.AbstractVirtualInvokeTypeFlow;
3738
import com.oracle.graal.pointsto.flow.ActualReturnTypeFlow;
@@ -207,7 +208,13 @@ public void onObservedUpdate(PointsToAnalysis bb) {
207208
continue;
208209
}
209210

210-
AnalysisMethod method = type.resolveConcreteMethod(getTargetMethod());
211+
AnalysisMethod method = null;
212+
try {
213+
method = type.resolveConcreteMethod(targetMethod);
214+
} catch (UnsupportedFeatureException ex) {
215+
bb.getUnsupportedFeatures().addMessage("resolve" + targetMethod.format("%H.%n(%p)"), targetMethod, ex.getMessage());
216+
}
217+
211218
if (method == null || Modifier.isAbstract(method.getModifiers())) {
212219
/*
213220
* Type states can be conservative, i.e., we can have receiver types that do not

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

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
5959
import org.graalvm.nativeimage.hosted.Feature;
6060

61-
import com.oracle.graal.pointsto.ObjectScanner.ReusableSet;
6261
import com.oracle.graal.pointsto.api.HostVM;
6362
import com.oracle.graal.pointsto.api.PointstoOptions;
6463
import com.oracle.graal.pointsto.constraints.UnsupportedFeatures;
@@ -128,7 +127,6 @@ public abstract class PointsToAnalysis implements BigBang {
128127
private final CompletionExecutor.Timing timing;
129128

130129
public final Timer typeFlowTimer;
131-
public final Timer checkObjectsTimer;
132130
public final Timer processFeaturesTimer;
133131
public final Timer analysisTimer;
134132

@@ -142,7 +140,6 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostedP
142140
this.hostVM = hostVM;
143141
String imageName = hostVM.getImageName();
144142
this.typeFlowTimer = new Timer(imageName, "(typeflow)", false);
145-
this.checkObjectsTimer = new Timer(imageName, "(objects)", false);
146143
this.processFeaturesTimer = new Timer(imageName, "(features)", false);
147144
this.analysisTimer = new Timer(imageName, "analysis", true);
148145

@@ -152,6 +149,7 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostedP
152149
this.unsupportedFeatures = unsupportedFeatures;
153150
this.providers = providers;
154151
this.strengthenGraalGraphs = strengthenGraalGraphs;
152+
providers.setBigBang(this);
155153

156154
this.objectType = metaAccess.lookupJavaType(Object.class);
157155
/*
@@ -194,14 +192,12 @@ public Timer getProcessFeaturesTimer() {
194192
@Override
195193
public void printTimers() {
196194
typeFlowTimer.print();
197-
checkObjectsTimer.print();
198195
processFeaturesTimer.print();
199196
}
200197

201198
@Override
202199
public void printTimerStatistics(PrintWriter out) {
203200
StatisticsPrinter.print(out, "typeflow_time_ms", typeFlowTimer.getTotalTime());
204-
StatisticsPrinter.print(out, "objects_time_ms", checkObjectsTimer.getTotalTime());
205201
StatisticsPrinter.print(out, "features_time_ms", processFeaturesTimer.getTotalTime());
206202
StatisticsPrinter.print(out, "total_analysis_time_ms", analysisTimer.getTotalTime());
207203

@@ -329,13 +325,14 @@ public void cleanupAfterAnalysis() {
329325
allSynchronizedTypeFlow = null;
330326
unsafeLoads = null;
331327
unsafeStores = null;
332-
scannedObjects = null;
333328

334329
ConstantObjectsProfiler.constantTypes.clear();
335330

336331
universe.getTypes().forEach(AnalysisType::cleanupAfterAnalysis);
337332
universe.getFields().forEach(AnalysisField::cleanupAfterAnalysis);
338333
universe.getMethods().forEach(AnalysisMethod::cleanupAfterAnalysis);
334+
335+
universe.getHeapScanner().cleanupAfterAnalysis();
339336
}
340337

341338
@Override
@@ -579,6 +576,10 @@ public CompletionExecutor getExecutor() {
579576
public void checkUserLimitations() {
580577
}
581578

579+
public void handleUnknownValueField(@SuppressWarnings("unused") AnalysisField field) {
580+
581+
}
582+
582583
public interface TypeFlowRunnable extends DebugContextRunnable {
583584
TypeFlow<?> getTypeFlow();
584585
}
@@ -643,10 +644,6 @@ public boolean finish() throws InterruptedException {
643644
*/
644645
assert executor.getPostedOperations() == 0;
645646
numTypes = universe.getTypes().size();
646-
try (StopTimer t = checkObjectsTimer.start()) {
647-
// track static fields
648-
checkObjectGraph();
649-
}
650647
} while (executor.getPostedOperations() != 0 || numTypes != universe.getTypes().size());
651648

652649
universe.setAnalysisDataValid(true);
@@ -669,39 +666,11 @@ public boolean doTypeflow() throws InterruptedException {
669666
return didSomeWork;
670667
}
671668

672-
private ReusableSet scannedObjects = new ReusableSet();
673-
674-
@SuppressWarnings("try")
675-
private void checkObjectGraph() throws InterruptedException {
676-
scannedObjects.reset();
677-
// scan constants
678-
boolean isParallel = PointstoOptions.ScanObjectsParallel.getValue(options);
679-
ObjectScanner objectScanner = new AnalysisObjectScanner(this, isParallel ? executor : null, scannedObjects);
680-
checkObjectGraph(objectScanner);
681-
if (isParallel) {
682-
executor.start();
683-
objectScanner.scanBootImageHeapRoots(null, null);
684-
executor.complete();
685-
executor.shutdown();
686-
executor.init(timing);
687-
} else {
688-
objectScanner.scanBootImageHeapRoots(null, null);
689-
}
690-
}
691-
692669
@Override
693670
public HeapScanningPolicy scanningPolicy() {
694671
return heapScanningPolicy;
695672
}
696673

697-
/**
698-
* Traverses the object graph to discover references to new types.
699-
*
700-
* @param objectScanner
701-
*/
702-
protected void checkObjectGraph(ObjectScanner objectScanner) {
703-
}
704-
705674
@Override
706675
public HostVM getHostVM() {
707676
return hostVM;

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,13 +277,14 @@ public void registerUsedElements(boolean registerEmbeddedRoots) {
277277
}
278278

279279
private void registerEmbeddedRoot(ConstantNode cn) {
280+
BytecodePosition position = cn.getNodeSourcePosition();
281+
if (position == null) {
282+
position = new BytecodePosition(null, method, 0);
283+
}
280284
if (bb.scanningPolicy().trackConstant(bb, cn.asJavaConstant())) {
281-
BytecodePosition position = cn.getNodeSourcePosition();
282-
if (position == null) {
283-
position = new BytecodePosition(null, method, 0);
284-
}
285285
bb.getUniverse().registerEmbeddedRoot(cn.asJavaConstant(), position);
286286
}
287+
bb.getUniverse().getHeapScanner().scanEmbeddedRoot(cn.asJavaConstant(), position);
287288
}
288289

289290
private static void registerForeignCall(PointsToAnalysis bb, ForeignCallDescriptor foreignCallDescriptor) {
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
/*
2+
* Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package com.oracle.graal.pointsto.heap;
26+
27+
import static com.oracle.graal.pointsto.heap.ImageHeapScanner.Reason;
28+
29+
import java.util.Collections;
30+
import java.util.Map;
31+
import java.util.Set;
32+
import java.util.concurrent.ConcurrentHashMap;
33+
34+
import com.oracle.graal.pointsto.meta.AnalysisField;
35+
import com.oracle.graal.pointsto.meta.AnalysisType;
36+
import com.oracle.graal.pointsto.util.AnalysisFuture;
37+
38+
import jdk.vm.ci.meta.JavaConstant;
39+
import jdk.vm.ci.meta.ResolvedJavaField;
40+
41+
public class ImageHeap {
42+
43+
/** Map the original object *and* the replaced object to the HeapObject snapshot. */
44+
protected final ConcurrentHashMap<JavaConstant, AnalysisFuture<ImageHeapObject>> heapObjects;
45+
/** Store a mapping from types to all scanned objects. */
46+
private final Map<AnalysisType, Set<ImageHeapObject>> typesToObjects;
47+
48+
public ImageHeap() {
49+
heapObjects = new ConcurrentHashMap<>();
50+
typesToObjects = new ConcurrentHashMap<>();
51+
}
52+
53+
public AnalysisFuture<ImageHeapObject> getTask(JavaConstant constant) {
54+
return heapObjects.get(constant);
55+
}
56+
57+
public ImageHeapObject get(JavaConstant constant) {
58+
return getTask(constant).ensureDone();
59+
}
60+
61+
public Set<ImageHeapObject> getObjects(AnalysisType type) {
62+
return typesToObjects.getOrDefault(type, Collections.emptySet());
63+
}
64+
65+
public void remove(JavaConstant original) {
66+
heapObjects.remove(original);
67+
}
68+
69+
public void remove(AnalysisType type, ImageHeapObject heapObj) {
70+
heapObjects(type).remove(heapObj);
71+
}
72+
73+
public boolean add(JavaConstant original, JavaConstant replaced, AnalysisFuture<ImageHeapObject> heapObj) {
74+
boolean r = heapObjects.putIfAbsent(replaced, heapObj) == null;
75+
boolean o = heapObjects.putIfAbsent(original, heapObj) == null;
76+
return r || o;
77+
}
78+
79+
public boolean add(AnalysisType type, ImageHeapObject heapObj) {
80+
return heapObjects(type).add(heapObj);
81+
}
82+
83+
private Set<ImageHeapObject> heapObjects(AnalysisType type) {
84+
return typesToObjects.computeIfAbsent(type, t -> Collections.newSetFromMap(new ConcurrentHashMap<>()));
85+
}
86+
87+
/**
88+
* Model for snapshotted objects. It stores the replaced object, i.e., the result of applying
89+
* object replacers on the original object, and the instance field values of this object. The
90+
* field values are stored as JavaConstant to also encode primitive values. ImageHeapObject are
91+
* created only after an object is processed through the object replacers.
92+
*/
93+
public static class ImageHeapObject implements Reason {
94+
final AnalysisType type;
95+
/** Store the object, already processed by the object transformers. */
96+
final JavaConstant object;
97+
98+
ImageHeapObject(JavaConstant object, AnalysisType type) {
99+
this.object = object;
100+
this.type = type;
101+
}
102+
103+
public JavaConstant getObject() {
104+
return object;
105+
}
106+
107+
/*
108+
* Equals and hascode just compare the replaced constant. Thus two HeapObject insantaces are
109+
* considered equal if they snapshot the same constant, even if the instanceFieldValues are
110+
* different, i.e., they were snapshotted at different times during analysis and one of them
111+
* mutated. This is necessary for the removal of the old snapshotted value on forced
112+
* updates. Alternativelly each AnalysisType needs a mapping from JavaConstant to HeapObject
113+
* instead of just a set of HeapObject.
114+
*/
115+
116+
@Override
117+
public boolean equals(Object o) {
118+
// TODO ==
119+
if (o instanceof ImageHeapObject) {
120+
ImageHeapObject other = (ImageHeapObject) o;
121+
return this.object.equals(other.object);
122+
}
123+
return false;
124+
}
125+
126+
@Override
127+
public int hashCode() {
128+
return object.hashCode();
129+
}
130+
}
131+
132+
public static final class ImageHeapInstance extends ImageHeapObject {
133+
134+
/** Store original field values of the object. */
135+
final Map<ResolvedJavaField, AnalysisFuture<JavaConstant>> rawObjectFieldValues;
136+
137+
ImageHeapInstance(JavaConstant object, AnalysisType type, Map<ResolvedJavaField, AnalysisFuture<JavaConstant>> rawObjectFieldValues) {
138+
super(object, type);
139+
this.rawObjectFieldValues = rawObjectFieldValues;
140+
}
141+
142+
public JavaConstant readFieldValue(AnalysisField field) {
143+
return rawObjectFieldValues.get(field).ensureDone();
144+
}
145+
146+
public AnalysisFuture<JavaConstant> getFieldTask(AnalysisField field) {
147+
return rawObjectFieldValues.get(field);
148+
}
149+
}
150+
151+
static final class ImageHeapArray extends ImageHeapObject {
152+
final JavaConstant[] rawArrayElementValues;
153+
154+
ImageHeapArray(JavaConstant object, AnalysisType type, JavaConstant[] rawArrayElementValues) {
155+
super(object, type);
156+
this.rawArrayElementValues = rawArrayElementValues;
157+
}
158+
159+
int getLength() {
160+
return rawArrayElementValues.length;
161+
}
162+
163+
}
164+
165+
}

0 commit comments

Comments
 (0)