Skip to content

Commit 4610ea9

Browse files
teshullcstancu
authored andcommitted
Add support for catching missing arrays in hubs.
1 parent bf98664 commit 4610ea9

File tree

4 files changed

+219
-8
lines changed

4 files changed

+219
-8
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
import com.oracle.svm.hosted.config.HybridLayout;
6565
import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo;
6666
import com.oracle.svm.hosted.imagelayer.CrossLayerConstantRegistryFeature;
67-
import com.oracle.svm.hosted.imagelayer.LayeredDispatchTableFeature;
67+
import com.oracle.svm.hosted.imagelayer.LayeredImageHooks;
6868
import com.oracle.svm.hosted.meta.HostedClass;
6969
import com.oracle.svm.hosted.meta.HostedField;
7070
import com.oracle.svm.hosted.meta.HostedInstanceClass;
@@ -431,7 +431,7 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) {
431431
instanceFields = instanceFields.filter(field -> !dynamicHubLayout.isIgnoredField(field));
432432

433433
if (imageLayer) {
434-
LayeredDispatchTableFeature.singleton().registerWrittenDynamicHub((DynamicHub) info.getObject(), heap.aUniverse, heap.hUniverse, vTable);
434+
LayeredImageHooks.processWrittenDynamicHub(new LayeredImageHooks.WrittenDynamicHubInfo((DynamicHub) info.getObject(), heap.aUniverse, heap.hUniverse, vTable));
435435
}
436436

437437
} else if (heap.getHybridLayout(clazz) != null) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredDispatchTableFeature.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,12 @@
4646
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
4747
import com.oracle.graal.pointsto.meta.AnalysisMethod;
4848
import com.oracle.graal.pointsto.meta.AnalysisType;
49-
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
5049
import com.oracle.objectfile.ObjectFile;
5150
import com.oracle.svm.core.InvalidMethodPointerHandler;
5251
import com.oracle.svm.core.SubstrateOptions;
5352
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
5453
import com.oracle.svm.core.feature.InternalFeature;
5554
import com.oracle.svm.core.graal.snippets.OpenTypeWorldDispatchTableSnippets;
56-
import com.oracle.svm.core.hub.DynamicHub;
5755
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
5856
import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
5957
import com.oracle.svm.core.meta.MethodPointer;
@@ -67,7 +65,6 @@
6765
import com.oracle.svm.hosted.meta.HostedMetaAccess;
6866
import com.oracle.svm.hosted.meta.HostedMethod;
6967
import com.oracle.svm.hosted.meta.HostedType;
70-
import com.oracle.svm.hosted.meta.HostedUniverse;
7168
import com.oracle.svm.hosted.meta.VTableBuilder;
7269

7370
import jdk.graal.compiler.code.CompilationResult;
@@ -133,6 +130,7 @@ public void beforeAnalysis(Feature.BeforeAnalysisAccess access) {
133130
config.registerAsRoot(aMethod, false, "in prior layer dispatch table");
134131
});
135132
}
133+
LayeredImageHooks.registerDynamicHubWrittenCallback(this::onDynamicHubWritten);
136134
}
137135

138136
@Override
@@ -395,12 +393,13 @@ private static void compareTypeInfo(HostedDispatchTable curInfo, PriorDispatchTa
395393
/*
396394
* Recording a hub was written to the heap
397395
*/
398-
public void registerWrittenDynamicHub(DynamicHub hub, AnalysisUniverse aUniverse, HostedUniverse hUniverse, Object vTable) {
399-
AnalysisType aType = ((SVMHost) aUniverse.hostVM()).lookupType(hub);
400-
HostedType hType = hUniverse.lookup(aType);
396+
public void onDynamicHubWritten(LayeredImageHooks.WrittenDynamicHubInfo hubInfo) {
397+
AnalysisType aType = ((SVMHost) hubInfo.aUniverse().hostVM()).lookupType(hubInfo.hub());
398+
HostedType hType = hubInfo.hUniverse().lookup(aType);
401399

402400
assert hType.getWrapped().isReachable() : "All installed hubs should be reachable " + hType;
403401

402+
Object vTable = hubInfo.vTable();
404403
int vtableLength = Array.getLength(vTable);
405404
if (VTableBuilder.hasEmptyDispatchTable(hType)) {
406405
assert vtableLength == 0 : hType;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
/*
2+
* Copyright (c) 2025, 2025, 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.svm.hosted.imagelayer;
26+
27+
import java.util.EnumSet;
28+
import java.util.Set;
29+
import java.util.concurrent.ConcurrentHashMap;
30+
31+
import org.graalvm.nativeimage.ImageSingletons;
32+
import org.graalvm.nativeimage.hosted.Feature;
33+
34+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
35+
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
36+
import com.oracle.svm.core.feature.InternalFeature;
37+
import com.oracle.svm.core.hub.DynamicHub;
38+
import com.oracle.svm.core.imagelayer.BuildingInitialLayerPredicate;
39+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
40+
import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
41+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonLoader;
42+
import com.oracle.svm.core.layeredimagesingleton.ImageSingletonWriter;
43+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingleton;
44+
import com.oracle.svm.core.layeredimagesingleton.LayeredImageSingletonBuilderFlags;
45+
import com.oracle.svm.hosted.FeatureImpl;
46+
import com.oracle.svm.hosted.meta.HostedType;
47+
import com.oracle.svm.util.LogUtils;
48+
49+
import jdk.graal.compiler.debug.Assertions;
50+
51+
/**
52+
* Tracks information about {@link DynamicHub} which should be consistent across builds.
53+
*/
54+
@AutomaticallyRegisteredFeature
55+
public class LayeredDynamicHubFeature implements InternalFeature, FeatureSingleton {
56+
57+
@Override
58+
public boolean isInConfiguration(Feature.IsInConfigurationAccess access) {
59+
return ImageLayerBuildingSupport.buildingImageLayer();
60+
}
61+
62+
@Override
63+
public void duringSetup(DuringSetupAccess access) {
64+
if (ImageLayerBuildingSupport.buildingSharedLayer()) {
65+
LayeredImageHooks.registerDynamicHubWrittenCallback(this::onDynamicHubWritten);
66+
}
67+
}
68+
69+
void onDynamicHubWritten(LayeredImageHooks.WrittenDynamicHubInfo info) {
70+
DynamicHub hub = info.hub();
71+
if (hub.getArrayHub() == null) {
72+
DynamicHubMetadataTracking.singleton().recordMissingArrayHub(hub);
73+
}
74+
}
75+
76+
@Override
77+
public void beforeCompilation(BeforeCompilationAccess access) {
78+
if (ImageLayerBuildingSupport.buildingApplicationLayer()) {
79+
/*
80+
* Scan all DynamicHubs to see if new missing array hubs have been installed. Currently
81+
* we must wait to do this until after typeIDs have been assigned.
82+
*/
83+
DynamicHubMetadataTracking tracking = DynamicHubMetadataTracking.singleton();
84+
FeatureImpl.BeforeCompilationAccessImpl config = (FeatureImpl.BeforeCompilationAccessImpl) access;
85+
config.getUniverse().getTypes().stream().filter(tracking::missingArrayHub).forEach(hType -> {
86+
if (hType.getHub().getArrayHub() != null) {
87+
var missingArrayName = hType.getHub().getArrayHub().getName();
88+
String message = String.format("New array type seen in application layer which was not installed within the dynamic hub.%nHub: %s%nArrayType: %s", hType.getHub().getName(),
89+
missingArrayName);
90+
LogUtils.warning(message);
91+
}
92+
});
93+
}
94+
}
95+
}
96+
97+
@AutomaticallyRegisteredImageSingleton(onlyWith = BuildingInitialLayerPredicate.class)
98+
class DynamicHubMetadataTracking implements LayeredImageSingleton {
99+
private final Set<Integer> typeIDsWithMissingHubs;
100+
101+
DynamicHubMetadataTracking() {
102+
this.typeIDsWithMissingHubs = ConcurrentHashMap.newKeySet();
103+
}
104+
105+
DynamicHubMetadataTracking(Set<Integer> missingHubSet) {
106+
this.typeIDsWithMissingHubs = missingHubSet;
107+
}
108+
109+
static DynamicHubMetadataTracking singleton() {
110+
return ImageSingletons.lookup(DynamicHubMetadataTracking.class);
111+
}
112+
113+
boolean missingArrayHub(HostedType hType) {
114+
return typeIDsWithMissingHubs.contains(hType.getTypeID());
115+
}
116+
117+
void recordMissingArrayHub(DynamicHub hub) {
118+
var added = typeIDsWithMissingHubs.add(hub.getTypeID());
119+
assert added : Assertions.errorMessage("type recorded twice:", hub);
120+
}
121+
122+
@Override
123+
public EnumSet<LayeredImageSingletonBuilderFlags> getImageBuilderFlags() {
124+
return LayeredImageSingletonBuilderFlags.BUILDTIME_ACCESS_ONLY;
125+
}
126+
127+
@Override
128+
public PersistFlags preparePersist(ImageSingletonWriter writer) {
129+
writer.writeIntList("typeIDsWithMissingArrayHubs", typeIDsWithMissingHubs.stream().toList());
130+
return PersistFlags.CREATE;
131+
}
132+
133+
@SuppressWarnings("unused")
134+
public static Object createFromLoader(ImageSingletonLoader loader) {
135+
Set<Integer> missingHubs = Set.copyOf(loader.readIntList("typeIDsWithMissingArrayHubs"));
136+
137+
return new DynamicHubMetadataTracking(missingHubs);
138+
}
139+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright (c) 2025, 2025, 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.svm.hosted.imagelayer;
26+
27+
import java.util.Set;
28+
import java.util.concurrent.ConcurrentHashMap;
29+
import java.util.function.Consumer;
30+
31+
import org.graalvm.nativeimage.ImageSingletons;
32+
import org.graalvm.nativeimage.hosted.Feature;
33+
34+
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
35+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
36+
import com.oracle.svm.core.feature.InternalFeature;
37+
import com.oracle.svm.core.hub.DynamicHub;
38+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
39+
import com.oracle.svm.core.layeredimagesingleton.FeatureSingleton;
40+
import com.oracle.svm.hosted.meta.HostedUniverse;
41+
42+
/**
43+
* Class containing hooks which can only be registered and executed during layered image builds.
44+
*/
45+
@AutomaticallyRegisteredFeature
46+
public class LayeredImageHooks implements InternalFeature, FeatureSingleton {
47+
private final Set<Consumer<WrittenDynamicHubInfo>> hubWrittenCallbacks = ConcurrentHashMap.newKeySet();
48+
49+
@Override
50+
public boolean isInConfiguration(Feature.IsInConfigurationAccess access) {
51+
return ImageLayerBuildingSupport.buildingImageLayer();
52+
}
53+
54+
private static LayeredImageHooks singleton() {
55+
return ImageSingletons.lookup(LayeredImageHooks.class);
56+
}
57+
58+
public record WrittenDynamicHubInfo(DynamicHub hub, AnalysisUniverse aUniverse, HostedUniverse hUniverse, Object vTable) {
59+
60+
}
61+
62+
/**
63+
* Register a callback which will execute each time a new {@link DynamicHub} is installed in the
64+
* image heap.
65+
*/
66+
public static void registerDynamicHubWrittenCallback(Consumer<WrittenDynamicHubInfo> consumer) {
67+
singleton().hubWrittenCallbacks.add(consumer);
68+
}
69+
70+
public static void processWrittenDynamicHub(WrittenDynamicHubInfo info) {
71+
singleton().hubWrittenCallbacks.forEach(callback -> callback.accept(info));
72+
}
73+
}

0 commit comments

Comments
 (0)