Skip to content

Commit 5b4716d

Browse files
committed
[GR-57248] Make HostedMethod naming layer-aware
PullRequest: graal/18671
2 parents 9fa5f68 + 0dfc6a5 commit 5b4716d

File tree

7 files changed

+179
-54
lines changed

7 files changed

+179
-54
lines changed

substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Collection;
3131
import java.util.HashSet;
3232
import java.util.List;
33+
import java.util.Objects;
3334
import java.util.Set;
3435
import java.util.concurrent.ConcurrentHashMap;
3536
import java.util.concurrent.ConcurrentMap;
@@ -1304,7 +1305,7 @@ public AnalysisMethod findConstructor(Signature signature) {
13041305
}
13051306

13061307
public Set<AnalysisMethod> getOpenTypeWorldDispatchTableMethods() {
1307-
AnalysisError.guarantee(dispatchTableMethods != null);
1308+
Objects.requireNonNull(dispatchTableMethods);
13081309
return dispatchTableMethods;
13091310
}
13101311

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ public void persistMethodInfo(Collection<HostedMethod> methods) {
449449
} else {
450450
if (priorIdx != vTableIndex) {
451451
if (generateErrorMessage()) {
452-
String message = String.format("VTable Index Mismatch %s. prior: %s new: %s", method.format("%H.%n"), priorIdx, vTableIndex);
452+
String message = String.format("VTable Index Mismatch %s. prior: %s new: %s", method.format("%H.%n(%p)"), priorIdx, vTableIndex);
453453
if (logErrorMessages()) {
454454
System.out.println(message);
455455
}

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
8080
import com.oracle.svm.hosted.image.NativeImageHeap;
8181
import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo;
82+
import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo;
8283
import com.oracle.svm.hosted.lambda.LambdaSubstitutionType;
8384
import com.oracle.svm.hosted.lambda.StableLambdaProxyNameFeature;
8485
import com.oracle.svm.hosted.meta.HostedField;
@@ -214,6 +215,14 @@ protected boolean shouldPersistMethod(AnalysisMethod method) {
214215
return false;
215216
}
216217

218+
@Override
219+
public void persistMethod(AnalysisMethod method) {
220+
super.persistMethod(method);
221+
222+
// register this method as persisted for name resolution
223+
HostedDynamicLayerInfo.singleton().recordPersistedMethod(hUniverse.lookup(method));
224+
}
225+
217226
@Override
218227
protected void persistField(AnalysisField field, EconomicMap<String, Object> fieldMap) {
219228
HostedField hostedField = hUniverse.lookup(field);

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

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
import java.util.List;
3636
import java.util.Map;
3737
import java.util.Set;
38+
import java.util.concurrent.ConcurrentHashMap;
39+
import java.util.stream.Collectors;
3840

3941
import org.graalvm.nativeimage.ImageSingletons;
4042
import org.graalvm.word.PointerBase;
@@ -57,25 +59,29 @@
5759
import com.oracle.svm.hosted.c.CGlobalDataFeature;
5860
import com.oracle.svm.hosted.image.NativeImage;
5961
import com.oracle.svm.hosted.meta.HostedMethod;
62+
import com.oracle.svm.hosted.meta.HostedMethodNameFactory.MethodNameInfo;
6063

6164
import jdk.graal.compiler.debug.Assertions;
6265

6366
public class HostedDynamicLayerInfo extends DynamicImageLayerInfo implements LayeredImageSingleton {
6467
private final Map<Integer, Integer> methodIdToOffsetMap;
68+
private final ConcurrentHashMap<Integer, MethodNameInfo> methodIdToNameInfoMap;
6569
private final CGlobalData<PointerBase> cGlobalData;
6670
private final Set<HostedMethod> priorLayerHostedMethods = new HashSet<>();
71+
private boolean persisted = false;
6772

6873
HostedDynamicLayerInfo() {
69-
this(0, null, new HashMap<>());
74+
this(0, null, new HashMap<>(), new ConcurrentHashMap<>());
7075
}
7176

7277
public static HostedDynamicLayerInfo singleton() {
7378
return (HostedDynamicLayerInfo) ImageSingletons.lookup(DynamicImageLayerInfo.class);
7479
}
7580

76-
private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map<Integer, Integer> methodIdToOffsetMap) {
81+
private HostedDynamicLayerInfo(int layerNumber, String codeSectionStartSymbol, Map<Integer, Integer> methodIdToOffsetMap, ConcurrentHashMap<Integer, MethodNameInfo> methodIdToNameInfoMap) {
7782
super(layerNumber);
7883
this.methodIdToOffsetMap = methodIdToOffsetMap;
84+
this.methodIdToNameInfoMap = methodIdToNameInfoMap;
7985
cGlobalData = codeSectionStartSymbol == null ? null : CGlobalDataFactory.forSymbol(codeSectionStartSymbol);
8086
}
8187

@@ -95,7 +101,23 @@ public boolean compiledInPriorLayer(AnalysisMethod aMethod) {
95101
return methodIdToOffsetMap.containsKey(aMethod.getId());
96102
}
97103

98-
void registerOffset(HostedMethod method) {
104+
public MethodNameInfo loadMethodNameInfo(AnalysisMethod method) {
105+
return methodIdToNameInfoMap.get(method.getId());
106+
}
107+
108+
public void recordPersistedMethod(HostedMethod hMethod) {
109+
assert !persisted : "Too late to record this information";
110+
MethodNameInfo info = new MethodNameInfo(hMethod.getName(), hMethod.getUniqueShortName());
111+
var prev = methodIdToNameInfoMap.put(hMethod.getWrapped().getId(), info);
112+
// will have to change for multiple layers
113+
assert prev == null : prev;
114+
}
115+
116+
public Set<String> getReservedNames() {
117+
return methodIdToNameInfoMap.values().stream().map(MethodNameInfo::uniqueShortName).collect(Collectors.toUnmodifiableSet());
118+
}
119+
120+
void registerCompilation(HostedMethod method) {
99121
assert BuildPhaseProvider.isCompileQueueFinished();
100122
int offset = method.getCodeAddressOffset();
101123
int methodID = method.getWrapped().getId();
@@ -143,6 +165,7 @@ boolean verifyUniqueOffsets(Collection<? extends SharedMethod> methods) {
143165

144166
@Override
145167
public PersistFlags preparePersist(ImageSingletonWriter writer) {
168+
persisted = true;
146169
/*
147170
* When there are multiple shared layers we will need to store the starting code offset of
148171
* each layer.
@@ -163,20 +186,33 @@ public PersistFlags preparePersist(ImageSingletonWriter writer) {
163186
* Write out all method offsets.
164187
*/
165188
List<Integer> offsets = new ArrayList<>(methodIdToOffsetMap.size());
166-
List<Integer> methodIDs = new ArrayList<>(methodIdToOffsetMap.size());
189+
List<Integer> methodOffsetIds = new ArrayList<>(methodIdToOffsetMap.size());
167190
methodIdToOffsetMap.forEach((key, value) -> {
168-
methodIDs.add(key);
191+
methodOffsetIds.add(key);
169192
offsets.add(value);
170193
});
171-
writer.writeIntList("methodIDs", methodIDs);
194+
writer.writeIntList("methodOffsetIDs", methodOffsetIds);
172195
writer.writeIntList("offsets", offsets);
173196

197+
/*
198+
* Write out all persisted method names
199+
*/
200+
List<Integer> methodNameIds = new ArrayList<>(methodIdToNameInfoMap.size());
201+
List<String> names = new ArrayList<>(methodIdToNameInfoMap.size() * 2);
202+
methodIdToNameInfoMap.forEach((key, value) -> {
203+
methodNameIds.add(key);
204+
names.add(value.name());
205+
names.add(value.uniqueShortName());
206+
});
207+
writer.writeIntList("methodNameIDs", methodNameIds);
208+
writer.writeStringList("names", names);
209+
174210
return PersistFlags.CREATE;
175211
}
176212

177213
@SuppressWarnings("unused")
178214
public static Object createFromLoader(ImageSingletonLoader loader) {
179-
assert loader.readIntList("offsets").size() == loader.readIntList("methodIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"),
215+
assert loader.readIntList("offsets").size() == loader.readIntList("methodOffsetIDs").size() : Assertions.errorMessage("Offsets and methodIDs are incompatible", loader.readIntList("offsets"),
180216
loader.readIntList("methodIDs"));
181217

182218
int layerNumber = loader.readInt("nextLayerNumber");
@@ -187,16 +223,32 @@ public static Object createFromLoader(ImageSingletonLoader loader) {
187223
* Load the offsets of all methods in the prior layers.
188224
*/
189225
var offsets = loader.readIntList("offsets").iterator();
190-
var methodIDs = loader.readIntList("methodIDs").iterator();
226+
var methodOffsetIds = loader.readIntList("methodOffsetIDs").iterator();
191227
Map<Integer, Integer> initialMethodIdToOffsetMap = new HashMap<>();
192228

193229
while (offsets.hasNext()) {
194-
int methodId = methodIDs.next();
230+
int methodId = methodOffsetIds.next();
195231
int offset = offsets.next();
196-
initialMethodIdToOffsetMap.put(methodId, offset);
232+
var prev = initialMethodIdToOffsetMap.put(methodId, offset);
233+
assert prev == null;
234+
}
235+
236+
/*
237+
* Load the names of all methods in the prior layers.
238+
*/
239+
var names = loader.readStringList("names").iterator();
240+
var methodNameIds = loader.readIntList("methodNameIDs").iterator();
241+
ConcurrentHashMap<Integer, MethodNameInfo> initialMethodIdToMethodNameMap = new ConcurrentHashMap<>();
242+
243+
while (methodNameIds.hasNext()) {
244+
int methodId = methodNameIds.next();
245+
String name = names.next();
246+
String uniqueShortName = names.next();
247+
var prev = initialMethodIdToMethodNameMap.put(methodId, new MethodNameInfo(name, uniqueShortName));
248+
assert prev == null;
197249
}
198250

199-
return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap);
251+
return new HostedDynamicLayerInfo(layerNumber, codeSectionStartSymbol, initialMethodIdToOffsetMap, initialMethodIdToMethodNameMap);
200252
}
201253
}
202254

@@ -231,7 +283,7 @@ public void afterCompilation(AfterCompilationAccess access) {
231283
assert HostedDynamicLayerInfo.singleton().verifyUniqueOffsets(config.getMethods());
232284

233285
for (var entry : config.getCodeCache().getOrderedCompilations()) {
234-
HostedDynamicLayerInfo.singleton().registerOffset(entry.getLeft());
286+
HostedDynamicLayerInfo.singleton().registerCompilation(entry.getLeft());
235287
}
236288
}
237289
}

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java

Lines changed: 4 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,10 @@
3232
import java.util.Collection;
3333
import java.util.Collections;
3434
import java.util.Map;
35-
import java.util.Set;
3635
import java.util.concurrent.ConcurrentHashMap;
3736
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
3837
import java.util.function.Function;
3938

40-
import org.graalvm.collections.Pair;
41-
import org.graalvm.nativeimage.ImageSingletons;
42-
import org.graalvm.nativeimage.Platform;
43-
import org.graalvm.nativeimage.Platforms;
44-
4539
import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
4640
import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider;
4741
import com.oracle.graal.pointsto.infrastructure.ResolvedSignature;
@@ -53,8 +47,6 @@
5347
import com.oracle.svm.core.Uninterruptible;
5448
import com.oracle.svm.core.code.ImageCodeInfo;
5549
import com.oracle.svm.core.deopt.Deoptimizer;
56-
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
57-
import com.oracle.svm.core.feature.InternalFeature;
5850
import com.oracle.svm.core.graal.code.CustomCallingConventionMethod;
5951
import com.oracle.svm.core.graal.code.ExplicitCallingConvention;
6052
import com.oracle.svm.core.graal.code.StubCallingConvention;
@@ -155,7 +147,7 @@ static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, Host
155147

156148
private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, ResolvedSignature<HostedType> signature,
157149
ConstantPool constantPool, ExceptionHandler[] handlers, MultiMethodKey key, Map<MultiMethodKey, MultiMethod> multiMethodMap, LocalVariableTable localVariableTable) {
158-
Function<Integer, Pair<String, String>> nameGenerator = (collisionCount) -> {
150+
Function<Integer, HostedMethodNameFactory.MethodNameInfo> nameGenerator = (collisionCount) -> {
159151
String name = wrapped.wrapped.getName(); // want name w/o any multimethodkey suffix
160152
if (key != ORIGINAL_METHOD) {
161153
name += StableMethodNameFormatter.MULTI_METHOD_KEY_SEPARATOR + key;
@@ -165,12 +157,12 @@ private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, R
165157
}
166158
String uniqueShortName = SubstrateUtil.uniqueShortName(holder.getJavaClass().getClassLoader(), holder, name, signature, wrapped.isConstructor());
167159

168-
return Pair.create(name, uniqueShortName);
160+
return new HostedMethodNameFactory.MethodNameInfo(name, uniqueShortName);
169161
};
170162

171-
Pair<String, String> names = ImageSingletons.lookup(HostedMethodNameFactory.class).createNames(nameGenerator);
163+
HostedMethodNameFactory.MethodNameInfo names = HostedMethodNameFactory.singleton().createNames(nameGenerator, wrapped);
172164

173-
return new HostedMethod(wrapped, holder, signature, constantPool, handlers, names.getLeft(), names.getRight(), localVariableTable, key, multiMethodMap);
165+
return new HostedMethod(wrapped, holder, signature, constantPool, handlers, names.name(), names.uniqueShortName(), localVariableTable, key, multiMethodMap);
174166
}
175167

176168
private static LocalVariableTable createLocalVariableTable(HostedUniverse universe, AnalysisMethod wrapped) {
@@ -627,31 +619,3 @@ public Collection<MultiMethod> getAllMultiMethods() {
627619
}
628620
}
629621
}
630-
631-
@Platforms(Platform.HOSTED_ONLY.class)
632-
@AutomaticallyRegisteredFeature
633-
class HostedMethodNameFactory implements InternalFeature {
634-
Map<String, Integer> methodNameCount = new ConcurrentHashMap<>();
635-
Set<String> uniqueShortNames = ConcurrentHashMap.newKeySet();
636-
637-
Pair<String, String> createNames(Function<Integer, Pair<String, String>> nameGenerator) {
638-
Pair<String, String> result = nameGenerator.apply(0);
639-
640-
int collisionCount = methodNameCount.merge(result.getRight(), 0, (oldValue, value) -> oldValue + 1);
641-
642-
if (collisionCount != 0) {
643-
result = nameGenerator.apply(collisionCount);
644-
}
645-
646-
boolean added = uniqueShortNames.add(result.getRight());
647-
VMError.guarantee(added, "failed to generate uniqueShortName for HostedMethod: %s", result.getRight());
648-
649-
return result;
650-
}
651-
652-
@Override
653-
public void afterCompilation(AfterCompilationAccess access) {
654-
methodNameCount = null;
655-
uniqueShortNames = null;
656-
}
657-
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2024, 2024, 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.meta;
26+
27+
import java.util.Map;
28+
import java.util.Set;
29+
import java.util.concurrent.ConcurrentHashMap;
30+
import java.util.function.Function;
31+
32+
import org.graalvm.nativeimage.ImageSingletons;
33+
34+
import com.oracle.graal.pointsto.meta.AnalysisMethod;
35+
import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
36+
import com.oracle.svm.core.feature.InternalFeature;
37+
import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
38+
import com.oracle.svm.core.util.VMError;
39+
import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo;
40+
41+
@AutomaticallyRegisteredFeature
42+
public class HostedMethodNameFactory implements InternalFeature {
43+
private Map<String, Integer> methodNameCount = new ConcurrentHashMap<>();
44+
private Set<String> uniqueShortNames = ConcurrentHashMap.newKeySet();
45+
private final boolean buildingExtensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer();
46+
private Set<String> reservedUniqueShortNames = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().getReservedNames() : null;
47+
48+
public record MethodNameInfo(String name, String uniqueShortName) {
49+
}
50+
51+
public static HostedMethodNameFactory singleton() {
52+
return ImageSingletons.lookup(HostedMethodNameFactory.class);
53+
}
54+
55+
MethodNameInfo createNames(Function<Integer, MethodNameInfo> nameGenerator, AnalysisMethod aMethod) {
56+
MethodNameInfo result = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().loadMethodNameInfo(aMethod) : null;
57+
if (result == null) {
58+
MethodNameInfo initialName = nameGenerator.apply(0);
59+
result = initialName;
60+
61+
do {
62+
int collisionCount = methodNameCount.merge(initialName.uniqueShortName(), 0, (oldValue, value) -> oldValue + 1);
63+
if (collisionCount != 0) {
64+
result = nameGenerator.apply(collisionCount);
65+
}
66+
/*
67+
* Redo if the short name is reserved.
68+
*/
69+
} while (buildingExtensionLayer && reservedUniqueShortNames.contains(result.uniqueShortName()));
70+
} else {
71+
assert reservedUniqueShortNames.contains(result.uniqueShortName()) : result;
72+
}
73+
74+
boolean added = uniqueShortNames.add(result.uniqueShortName());
75+
VMError.guarantee(added, "failed to generate uniqueShortName for HostedMethod: %s", result.uniqueShortName());
76+
77+
return result;
78+
}
79+
80+
@Override
81+
public void afterCompilation(AfterCompilationAccess access) {
82+
methodNameCount = null;
83+
uniqueShortNames = null;
84+
reservedUniqueShortNames = null;
85+
}
86+
}

0 commit comments

Comments
 (0)