From 8319ae8896725706da1386f9bdf2c5804728fdfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 23 Jun 2022 15:36:17 +0200 Subject: [PATCH 01/13] Externalize Comparability of Hosted{Type,Method,Field} --- .../AbstractAnalysisResultsBuilder.java | 1 - .../oracle/svm/hosted/code/CompileQueue.java | 3 +- .../svm/hosted/meta/HostedArrayClass.java | 6 - .../oracle/svm/hosted/meta/HostedField.java | 16 +- .../oracle/svm/hosted/meta/HostedMethod.java | 43 +----- .../svm/hosted/meta/HostedPrimitiveType.java | 6 - .../oracle/svm/hosted/meta/HostedType.java | 36 +---- .../svm/hosted/meta/TypeCheckBuilder.java | 2 +- .../svm/hosted/meta/UniverseBuilder.java | 142 +++++++++++++++++- 9 files changed, 142 insertions(+), 113 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java index 4c9bc51017b9..8481bc27961e 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java @@ -128,7 +128,6 @@ private JavaTypeProfile createTypeProfile(TypeState typeState) { double probability = 1d / typeState.typesCount(); JavaTypeProfile.ProfiledType[] pitems = typeState.typesStream(bb) .map(analysisType -> converter == null ? analysisType : converter.lookup(analysisType)) - .sorted() .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) .toArray(JavaTypeProfile.ProfiledType[]::new); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index cc02f0a33ef7..f4ced5eaf3a6 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -178,6 +178,7 @@ import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; +import com.oracle.svm.hosted.meta.UniverseBuilder; import com.oracle.svm.hosted.phases.DevirtualizeCallsPhase; import com.oracle.svm.hosted.phases.HostedGraphBuilderPhase; import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; @@ -1675,7 +1676,7 @@ private static void insertDeoptTests(HostedMethod method, StructuredGraph graph) } public Map getCompilationResults() { - Map result = new TreeMap<>(); + Map result = new TreeMap<>(UniverseBuilder.getMethodComparator()); for (Entry entry : compilations.entrySet()) { result.put(entry.getKey(), entry.getValue().result); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedArrayClass.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedArrayClass.java index 30a96a7a0609..1273d2eef846 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedArrayClass.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedArrayClass.java @@ -92,10 +92,4 @@ public boolean isLocal() { public boolean isMember() { return false; } - - @Override - int compareToEqualClass(HostedType other) { - assert getClass().equals(other.getClass()); - return getComponentType().compareTo(other.getComponentType()); - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java index 702dc883a152..0fdfd06d7f30 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedField.java @@ -41,7 +41,7 @@ /** * Store the compile-time information for a field in the Substrate VM, such as the field offset. */ -public class HostedField implements OriginalFieldProvider, SharedField, Comparable, WrappedJavaField, AnnotationWrapper { +public class HostedField implements OriginalFieldProvider, SharedField, WrappedJavaField, AnnotationWrapper { private final HostedUniverse universe; private final HostedMetaAccess metaAccess; @@ -198,20 +198,6 @@ public JavaKind getStorageKind() { return getType().getStorageKind(); } - @Override - public int compareTo(HostedField other) { - /* - * Order by JavaKind. This is required, since we want instance fields of the same size and - * kind consecutive. - */ - int result = other.getJavaKind().ordinal() - this.getJavaKind().ordinal(); - /* - * If the kind is the same, i.e., result == 0, we return 0 so that the sorting keeps the - * order unchanged and therefore keeps the field order we get from the hosting VM. - */ - return result; - } - @Override public Field getJavaField() { return OriginalFieldProvider.getJavaField(getDeclaringClass().universe.getSnippetReflection(), wrapped); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 18eef09a9d6f..7872c37afb9f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; -public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, Comparable, OriginalMethodProvider { +public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, OriginalMethodProvider { public static final String METHOD_NAME_DEOPT_SUFFIX = "**"; @@ -441,47 +441,6 @@ public int hashCode() { return wrapped.hashCode(); } - @Override - public int compareTo(HostedMethod other) { - if (this.equals(other)) { - return 0; - } - - /* - * Sort deoptimization targets towards the end of the code cache. They are rarely executed, - * and we do not want a deoptimization target as the first method (because offset 0 means no - * deoptimization target available). - */ - int result = Boolean.compare(this.compilationInfo.isDeoptTarget(), other.compilationInfo.isDeoptTarget()); - - if (result == 0) { - result = this.getDeclaringClass().compareTo(other.getDeclaringClass()); - } - if (result == 0) { - result = this.getName().compareTo(other.getName()); - } - if (result == 0) { - result = this.getSignature().getParameterCount(false) - other.getSignature().getParameterCount(false); - } - if (result == 0) { - for (int i = 0; i < this.getSignature().getParameterCount(false); i++) { - result = ((HostedType) this.getSignature().getParameterType(i, null)).compareTo((HostedType) other.getSignature().getParameterType(i, null)); - if (result != 0) { - break; - } - } - } - if (result == 0) { - result = ((HostedType) this.getSignature().getReturnType(null)).compareTo((HostedType) other.getSignature().getReturnType(null)); - } - /* - * Note that the result can still be 0 at this point: with class substitutions or incomplete - * classpath, two separate methods can have the same signature. Not ordering such methods is - * fine. GR-32976 should remove the sorting altogether. - */ - return result; - } - @Override public Executable getJavaMethod() { return OriginalMethodProvider.getJavaMethod(getDeclaringClass().universe.getSnippetReflection(), wrapped); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedPrimitiveType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedPrimitiveType.java index 256628ae8952..096df6b96ff9 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedPrimitiveType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedPrimitiveType.java @@ -93,10 +93,4 @@ public boolean isLocal() { public boolean isMember() { return false; } - - @Override - int compareToEqualClass(HostedType other) { - assert getClass().equals(other.getClass()); - return getJavaKind().ordinal() - other.getJavaKind().ordinal(); - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java index 77cc90f9bcb9..498ca532d4f4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java @@ -24,8 +24,6 @@ */ package com.oracle.svm.hosted.meta; -import static com.oracle.svm.core.util.VMError.shouldNotReachHere; - import org.graalvm.word.WordBase; import com.oracle.graal.pointsto.infrastructure.OriginalClassProvider; @@ -42,7 +40,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; -public abstract class HostedType implements SharedType, WrappedJavaType, Comparable, OriginalClassProvider { +public abstract class HostedType implements SharedType, WrappedJavaType, OriginalClassProvider { protected final HostedUniverse universe; protected final AnalysisType wrapped; @@ -430,36 +428,4 @@ public void setEnclosingType(HostedType enclosingType) { public Class getJavaClass() { return OriginalClassProvider.getJavaClass(universe.getSnippetReflection(), wrapped); } - - @Override - public int compareTo(HostedType other) { - if (this.equals(other)) { - return 0; - } - if (this.getClass().equals(other.getClass())) { - return compareToEqualClass(other); - } - int result = this.ordinal() - other.ordinal(); - assert result != 0 : "Types not distinguishable: " + this + ", " + other; - return result; - } - - int compareToEqualClass(HostedType other) { - assert getClass().equals(other.getClass()); - return getName().compareTo(other.getName()); - } - - private int ordinal() { - if (isInterface()) { - return 4; - } else if (isArray()) { - return 3; - } else if (isInstanceClass()) { - return 2; - } else if (getJavaKind() != JavaKind.Object) { - return 1; - } else { - throw shouldNotReachHere(); - } - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java index bbc213d7e1af..cdd66d40bc0f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java @@ -242,7 +242,7 @@ private Map> computeSubtypeInformation() { /* Convert values into a sorted list. */ Map> result = new HashMap<>(); - subtypes.forEach((k, v) -> result.put(k, v.stream().sorted().collect(Collectors.toList()))); + subtypes.forEach((k, v) -> result.put(k, v.stream().sorted(UniverseComparators.TYPE).collect(Collectors.toList()))); return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 70398bc3ff5b..262b048b2432 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -31,6 +31,7 @@ import java.util.BitSet; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -114,6 +115,10 @@ public class UniverseBuilder { private final UnsupportedFeatures unsupportedFeatures; private TypeCheckBuilder typeCheckBuilder; + public static final Comparator getMethodComparator() { + return UniverseComparators.METHOD; + } + public UniverseBuilder(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, HostedUniverse hUniverse, HostedMetaAccess hMetaAccess, AbstractAnalysisResultsBuilder staticAnalysisResultsBuilder, UnsupportedFeatures unsupportedFeatures) { this.aUniverse = aUniverse; @@ -181,9 +186,9 @@ public void build(DebugContext debug) { processFieldLocations(); hUniverse.orderedMethods = new ArrayList<>(hUniverse.methods.values()); - Collections.sort(hUniverse.orderedMethods); + Collections.sort(hUniverse.orderedMethods, UniverseComparators.METHOD); hUniverse.orderedFields = new ArrayList<>(hUniverse.fields.values()); - Collections.sort(hUniverse.orderedFields); + Collections.sort(hUniverse.orderedFields, UniverseComparators.FIELD); profilingInformationBuildTask.join(); } } @@ -442,7 +447,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(rawFields); + Collections.sort(rawFields, UniverseComparators.FIELD); int nextOffset = startSize; while (rawFields.size() > 0) { @@ -521,7 +526,7 @@ private void layoutStaticFields() { } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(fields); + Collections.sort(fields, UniverseComparators.FIELD); ObjectLayout layout = ConfigurationValues.getObjectLayout(); @@ -586,7 +591,7 @@ private void collectDeclaredMethods() { for (HostedType type : hUniverse.getTypes()) { List list = methodsOfType[type.getTypeID()]; if (list != null) { - Collections.sort(list); + Collections.sort(list, UniverseComparators.METHOD); type.allDeclaredMethods = list.toArray(new HostedMethod[list.size()]); } else { type.allDeclaredMethods = noMethods; @@ -599,7 +604,7 @@ private void collectMethodImplementations() { // Reuse the implementations from the analysis method. method.implementations = hUniverse.lookup(method.wrapped.getImplementations()); - Arrays.sort(method.implementations); + Arrays.sort(method.implementations, UniverseComparators.METHOD); } } @@ -1009,6 +1014,131 @@ private void processFieldLocations() { } } +final class UniverseComparators { + + private UniverseComparators() { + } + + static final Comparator TYPE = new TypeComparator(); + + private static final class TypeComparator implements Comparator { + + @Override + public int compare(HostedType o1, HostedType o2) { + if (o1.equals(o2)) { + return 0; + } + + int result; + if (o1.getClass().equals(o2.getClass())) { + if (o1.isPrimitive() && o2.isPrimitive()) { + assert o1 instanceof HostedPrimitiveType && o2 instanceof HostedPrimitiveType; + result = o1.getJavaKind().compareTo(o2.getJavaKind()); + VMError.guarantee(result != 0, "HostedPrimitiveType objects not distinguishable by javaKind: " + o1 + ", " + o2); + return result; + } + + if (o1.isArray() && o2.isArray()) { + assert o1 instanceof HostedArrayClass && o2 instanceof HostedArrayClass; + result = compare(o1.getComponentType(), o2.getComponentType()); + VMError.guarantee(result != 0, "HostedArrayClass objects not distinguishable by componentType: " + o1 + ", " + o2); + return result; + } + + result = o1.getName().compareTo(o2.getName()); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by name: " + o1 + ", " + o2); + return result; + } + + result = Integer.compare(ordinal(o1), ordinal(o2)); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by ordinal number: " + o1 + ", " + o2); + return result; + } + + private static int ordinal(HostedType type) { + if (type.isInterface()) { + return 4; + } else if (type.isArray()) { + return 3; + } else if (type.isInstanceClass()) { + return 2; + } else if (type.getJavaKind() != JavaKind.Object) { + return 1; + } else { + throw VMError.shouldNotReachHere(); + } + } + } + + static final Comparator METHOD = new MethodComparator(); + + private static final class MethodComparator implements Comparator { + @Override + public int compare(HostedMethod o1, HostedMethod o2) { + if (o1.equals(o2)) { + return 0; + } + + /* + * Sort deoptimization targets towards the end of the code cache. They are rarely + * executed, and we do not want a deoptimization target as the first method (because + * offset 0 means no deoptimization target available). + */ + int result = Boolean.compare(o1.compilationInfo.isDeoptTarget(), o2.compilationInfo.isDeoptTarget()); + if (result != 0) { + return result; + } + + result = TYPE.compare(o1.getDeclaringClass(), o2.getDeclaringClass()); + if (result != 0) { + return result; + } + + result = o1.getName().compareTo(o2.getName()); + if (result != 0) { + return result; + } + + Signature signature1 = o1.getSignature(); + Signature signature2 = o2.getSignature(); + int parameterCount1 = signature1.getParameterCount(false); + result = Integer.compare(parameterCount1, signature2.getParameterCount(false)); + if (result != 0) { + return result; + } + + for (int i = 0; i < parameterCount1; i++) { + result = TYPE.compare((HostedType) signature1.getParameterType(i, null), (HostedType) signature2.getParameterType(i, null)); + if (result != 0) { + return result; + } + } + + result = TYPE.compare((HostedType) signature1.getReturnType(null), (HostedType) signature2.getReturnType(null)); + if (result != 0) { + return result; + } + + /* + * Note that result can still be 0 at this point. Class substitutions or incomplete + * classpath can cause two separate methods to have the same signature. Fall back to + * identityResult to distinguish such cases. + */ + int identityResult = Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2)); + assert identityResult != 0 : "identityResult != 0"; + return identityResult; + } + } + + /* + * Order by JavaKind. This is required, since we want instance fields of the same size and kind + * consecutive. If the kind is the same, i.e., result == 0, we return 0 so that the sorting + * keeps the order unchanged and therefore keeps the field order we get from the hosting VM. + */ + static final Comparator FIELD = Comparator.comparing(HostedField::getJavaKind); + +} + @AutomaticFeature final class InvalidVTableEntryFeature implements Feature { From abe57e7489a567d5b2b91a6da17d1f26715a90c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 28 Jun 2022 16:56:42 +0200 Subject: [PATCH 02/13] Introduce HostedMethod name collision handling --- .../oracle/svm/hosted/code/CompileQueue.java | 3 +- .../oracle/svm/hosted/meta/HostedMethod.java | 52 +++++-- .../svm/hosted/meta/HostedUniverse.java | 137 +++++++++++++++- .../svm/hosted/meta/TypeCheckBuilder.java | 2 +- .../svm/hosted/meta/UniverseBuilder.java | 147 ++---------------- 5 files changed, 185 insertions(+), 156 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index f4ced5eaf3a6..a9f022e5a484 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -178,7 +178,6 @@ import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; -import com.oracle.svm.hosted.meta.UniverseBuilder; import com.oracle.svm.hosted.phases.DevirtualizeCallsPhase; import com.oracle.svm.hosted.phases.HostedGraphBuilderPhase; import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; @@ -1676,7 +1675,7 @@ private static void insertDeoptTests(HostedMethod method, StructuredGraph graph) } public Map getCompilationResults() { - Map result = new TreeMap<>(UniverseBuilder.getMethodComparator()); + Map result = new TreeMap<>(HostedUniverse.METHOD_COMPARATOR); for (Entry entry : compilations.entrySet()) { result.put(entry.getKey(), entry.getValue().result); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 7872c37afb9f..bdbecf5bb5be 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -68,6 +68,7 @@ public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, OriginalMethodProvider { + public static final String METHOD_NAME_COLLISION_SUFFIX = "*"; public static final String METHOD_NAME_DEOPT_SUFFIX = "**"; public final AnalysisMethod wrapped; @@ -96,17 +97,32 @@ public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvi public final CompilationInfo compilationInfo; private final LocalVariableTable localVariableTable; + private final String name; private final String uniqueShortName; - public HostedMethod(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, ExceptionHandler[] handlers, HostedMethod deoptOrigin) { - this.wrapped = wrapped; - this.holder = holder; - this.signature = signature; - this.constantPool = constantPool; - this.handlers = handlers; - this.compilationInfo = new CompilationInfo(this, deoptOrigin); - this.uniqueShortName = SubstrateUtil.uniqueShortName(this); + public static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, + ConstantPool constantPool, ExceptionHandler[] handlers, HostedMethod deoptOrigin) { + String name = deoptOrigin != null ? wrapped.getName() + METHOD_NAME_DEOPT_SUFFIX : wrapped.getName(); + LocalVariableTable localVariableTable = createLocalVariableTable(universe, wrapped); + HostedMethod hostedMethod = new HostedMethod(wrapped, holder, signature, constantPool, handlers, deoptOrigin, name, localVariableTable); + hostedMethod = makeUnique(universe, hostedMethod, deoptOrigin, name); + universe.orderedMethods.add(hostedMethod); + return hostedMethod; + } + + private static HostedMethod makeUnique(HostedUniverse universe, HostedMethod method, HostedMethod deoptOrigin, String name) { + if (!universe.orderedMethods.contains(method)) { + return method; + } + int collisionCount = universe.methodNameCollisions.merge(method, 1, (oldValue, value) -> oldValue + 1); + String collisionName = name + METHOD_NAME_COLLISION_SUFFIX + collisionCount; + HostedMethod hostedMethod = new HostedMethod(method.wrapped, method.holder, method.signature, method.constantPool, + method.handlers, deoptOrigin, collisionName, method.localVariableTable); + VMError.guarantee(!universe.orderedMethods.contains(hostedMethod), "HostedMethod name collision handling failed"); + return hostedMethod; + } + private static LocalVariableTable createLocalVariableTable(HostedUniverse universe, AnalysisMethod wrapped) { LocalVariableTable newLocalVariableTable = null; if (wrapped.getLocalVariableTable() != null) { try { @@ -126,7 +142,20 @@ public HostedMethod(HostedUniverse universe, AnalysisMethod wrapped, HostedType newLocalVariableTable = null; } } - localVariableTable = newLocalVariableTable; + return newLocalVariableTable; + } + + private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, + ExceptionHandler[] handlers, HostedMethod deoptOrigin, String name, LocalVariableTable localVariableTable) { + this.wrapped = wrapped; + this.holder = holder; + this.signature = signature; + this.constantPool = constantPool; + this.handlers = handlers; + this.compilationInfo = new CompilationInfo(this, deoptOrigin); + this.localVariableTable = localVariableTable; + this.name = name; + this.uniqueShortName = SubstrateUtil.uniqueShortName(this); } @Override @@ -260,10 +289,7 @@ public boolean hasCalleeSavedRegisters() { @Override public String getName() { - if (compilationInfo.isDeoptTarget()) { - return wrapped.getName() + METHOD_NAME_DEOPT_SUFFIX; - } - return wrapped.getName(); + return name; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index d765af45177d..1043e7b2ade3 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -27,10 +27,12 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Collection; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeSet; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.StructuredGraph; @@ -56,6 +58,7 @@ import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.hub.DynamicHub; +import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; @@ -286,9 +289,11 @@ public class HostedUniverse implements Universe { protected EnumMap kindToType = new EnumMap<>(JavaKind.class); protected List orderedTypes; - protected List orderedMethods; protected List orderedFields; + TreeSet orderedMethods = new TreeSet<>(new MethodComparator(TYPE_COMPARATOR, false)); + Map methodNameCollisions = new HashMap<>(); + public HostedUniverse(Inflation bb) { this.bb = bb; } @@ -306,7 +311,8 @@ public HostedInstanceClass getObjectClass() { public synchronized HostedMethod createDeoptTarget(HostedMethod method) { if (method.compilationInfo.getDeoptTargetMethod() == null) { - HostedMethod deoptTarget = new HostedMethod(this, method.getWrapped(), method.getDeclaringClass(), method.getSignature(), method.getConstantPool(), method.getExceptionHandlers(), method); + HostedMethod deoptTarget = HostedMethod.create(this, method.getWrapped(), method.getDeclaringClass(), + method.getSignature(), method.getConstantPool(), method.getExceptionHandlers(), method); assert method.staticAnalysisResults != null; deoptTarget.staticAnalysisResults = method.staticAnalysisResults; } @@ -449,4 +455,131 @@ public ResolvedJavaMethod resolveSubstitution(ResolvedJavaMethod method) { public HostedType objectType() { return types.get(bb.getUniverse().objectType()); } + + static final TypeComparator TYPE_COMPARATOR = new TypeComparator(); + + private static final class TypeComparator implements Comparator { + + @Override + public int compare(HostedType o1, HostedType o2) { + if (o1.equals(o2)) { + return 0; + } + + int result; + if (o1.getClass().equals(o2.getClass())) { + if (o1.isPrimitive() && o2.isPrimitive()) { + assert o1 instanceof HostedPrimitiveType && o2 instanceof HostedPrimitiveType; + result = o1.getJavaKind().compareTo(o2.getJavaKind()); + VMError.guarantee(result != 0, "HostedPrimitiveType objects not distinguishable by javaKind: " + o1 + ", " + o2); + return result; + } + + if (o1.isArray() && o2.isArray()) { + assert o1 instanceof HostedArrayClass && o2 instanceof HostedArrayClass; + result = compare(o1.getComponentType(), o2.getComponentType()); + VMError.guarantee(result != 0, "HostedArrayClass objects not distinguishable by componentType: " + o1 + ", " + o2); + return result; + } + + result = o1.getName().compareTo(o2.getName()); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by name: " + o1 + ", " + o2); + return result; + } + + result = Integer.compare(ordinal(o1), ordinal(o2)); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by ordinal number: " + o1 + ", " + o2); + return result; + } + + private static int ordinal(HostedType type) { + if (type.isInterface()) { + return 4; + } else if (type.isArray()) { + return 3; + } else if (type.isInstanceClass()) { + return 2; + } else if (type.getJavaKind() != JavaKind.Object) { + return 1; + } else { + throw VMError.shouldNotReachHere(); + } + } + } + + public static final MethodComparator METHOD_COMPARATOR = new MethodComparator(TYPE_COMPARATOR, true); + + private static final class MethodComparator implements Comparator { + + private final TypeComparator typeComparator; + + private final boolean collisionFatal; + + private MethodComparator(TypeComparator typeComparator, boolean collisionFatal) { + this.typeComparator = typeComparator; + this.collisionFatal = collisionFatal; + } + + @Override + public int compare(HostedMethod o1, HostedMethod o2) { + if (o1.equals(o2)) { + return 0; + } + + /* + * Sort deoptimization targets towards the end of the code cache. They are rarely + * executed, and we do not want a deoptimization target as the first method (because + * offset 0 means no deoptimization target available). + */ + int result = Boolean.compare(o1.compilationInfo.isDeoptTarget(), o2.compilationInfo.isDeoptTarget()); + if (result != 0) { + return result; + } + + result = typeComparator.compare(o1.getDeclaringClass(), o2.getDeclaringClass()); + if (result != 0) { + return result; + } + + result = o1.getName().compareTo(o2.getName()); + if (result != 0) { + return result; + } + + Signature signature1 = o1.getSignature(); + Signature signature2 = o2.getSignature(); + int parameterCount1 = signature1.getParameterCount(false); + result = Integer.compare(parameterCount1, signature2.getParameterCount(false)); + if (result != 0) { + return result; + } + + for (int i = 0; i < parameterCount1; i++) { + result = typeComparator.compare((HostedType) signature1.getParameterType(i, null), (HostedType) signature2.getParameterType(i, null)); + if (result != 0) { + return result; + } + } + + result = typeComparator.compare((HostedType) signature1.getReturnType(null), (HostedType) signature2.getReturnType(null)); + if (result != 0) { + return result; + } + + /* + * Note that result can still be 0 at this point. This in only allowed during + * HostedMethod name collision handling in HostedMethod#create. + */ + VMError.guarantee(!collisionFatal, "HostedMethod objects not distinguishable: " + o1 + ", " + o2); + return result; + } + } + + /* + * Order by JavaKind. This is required, since we want instance fields of the same size and kind + * consecutive. If the kind is the same, i.e., result == 0, we return 0 so that the sorting + * keeps the order unchanged and therefore keeps the field order we get from the hosting VM. + */ + static final Comparator FIELD_COMPARATOR = Comparator.comparing(HostedField::getJavaKind); + } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java index cdd66d40bc0f..d80de19f4573 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/TypeCheckBuilder.java @@ -242,7 +242,7 @@ private Map> computeSubtypeInformation() { /* Convert values into a sorted list. */ Map> result = new HashMap<>(); - subtypes.forEach((k, v) -> result.put(k, v.stream().sorted(UniverseComparators.TYPE).collect(Collectors.toList()))); + subtypes.forEach((k, v) -> result.put(k, v.stream().sorted(HostedUniverse.TYPE_COMPARATOR).collect(Collectors.toList()))); return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 262b048b2432..40c46cb20da0 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -31,7 +31,6 @@ import java.util.BitSet; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -115,10 +114,6 @@ public class UniverseBuilder { private final UnsupportedFeatures unsupportedFeatures; private TypeCheckBuilder typeCheckBuilder; - public static final Comparator getMethodComparator() { - return UniverseComparators.METHOD; - } - public UniverseBuilder(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, HostedUniverse hUniverse, HostedMetaAccess hMetaAccess, AbstractAnalysisResultsBuilder staticAnalysisResultsBuilder, UnsupportedFeatures unsupportedFeatures) { this.aUniverse = aUniverse; @@ -163,6 +158,9 @@ public void build(DebugContext debug) { makeMethod(aMethod); } + System.out.println("methodNameCollisions:"); + hUniverse.methodNameCollisions.forEach((method, count) -> System.out.println(count + ": " + method)); + Collection allTypes = hUniverse.types.values(); HostedType objectType = hUniverse.objectType(); HostedType cloneableType = hUniverse.types.get(aMetaAccess.lookupJavaType(Cloneable.class)); @@ -185,10 +183,8 @@ public void build(DebugContext debug) { processFieldLocations(); - hUniverse.orderedMethods = new ArrayList<>(hUniverse.methods.values()); - Collections.sort(hUniverse.orderedMethods, UniverseComparators.METHOD); hUniverse.orderedFields = new ArrayList<>(hUniverse.fields.values()); - Collections.sort(hUniverse.orderedFields, UniverseComparators.FIELD); + Collections.sort(hUniverse.orderedFields, HostedUniverse.FIELD_COMPARATOR); profilingInformationBuildTask.join(); } } @@ -299,7 +295,7 @@ private void makeMethod(AnalysisMethod aMethod) { sHandlers[i] = new ExceptionHandler(h.getStartBCI(), h.getEndBCI(), h.getHandlerBCI(), h.catchTypeCPI(), catchType); } - HostedMethod sMethod = new HostedMethod(hUniverse, aMethod, holder, signature, constantPool, sHandlers, null); + HostedMethod sMethod = HostedMethod.create(hUniverse, aMethod, holder, signature, constantPool, sHandlers, null); assert !hUniverse.methods.containsKey(aMethod); hUniverse.methods.put(aMethod, sMethod); @@ -447,7 +443,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(rawFields, UniverseComparators.FIELD); + Collections.sort(rawFields, HostedUniverse.FIELD_COMPARATOR); int nextOffset = startSize; while (rawFields.size() > 0) { @@ -526,7 +522,7 @@ private void layoutStaticFields() { } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(fields, UniverseComparators.FIELD); + Collections.sort(fields, HostedUniverse.FIELD_COMPARATOR); ObjectLayout layout = ConfigurationValues.getObjectLayout(); @@ -591,7 +587,7 @@ private void collectDeclaredMethods() { for (HostedType type : hUniverse.getTypes()) { List list = methodsOfType[type.getTypeID()]; if (list != null) { - Collections.sort(list, UniverseComparators.METHOD); + Collections.sort(list, HostedUniverse.METHOD_COMPARATOR); type.allDeclaredMethods = list.toArray(new HostedMethod[list.size()]); } else { type.allDeclaredMethods = noMethods; @@ -604,7 +600,7 @@ private void collectMethodImplementations() { // Reuse the implementations from the analysis method. method.implementations = hUniverse.lookup(method.wrapped.getImplementations()); - Arrays.sort(method.implementations, UniverseComparators.METHOD); + Arrays.sort(method.implementations, HostedUniverse.METHOD_COMPARATOR); } } @@ -1014,131 +1010,6 @@ private void processFieldLocations() { } } -final class UniverseComparators { - - private UniverseComparators() { - } - - static final Comparator TYPE = new TypeComparator(); - - private static final class TypeComparator implements Comparator { - - @Override - public int compare(HostedType o1, HostedType o2) { - if (o1.equals(o2)) { - return 0; - } - - int result; - if (o1.getClass().equals(o2.getClass())) { - if (o1.isPrimitive() && o2.isPrimitive()) { - assert o1 instanceof HostedPrimitiveType && o2 instanceof HostedPrimitiveType; - result = o1.getJavaKind().compareTo(o2.getJavaKind()); - VMError.guarantee(result != 0, "HostedPrimitiveType objects not distinguishable by javaKind: " + o1 + ", " + o2); - return result; - } - - if (o1.isArray() && o2.isArray()) { - assert o1 instanceof HostedArrayClass && o2 instanceof HostedArrayClass; - result = compare(o1.getComponentType(), o2.getComponentType()); - VMError.guarantee(result != 0, "HostedArrayClass objects not distinguishable by componentType: " + o1 + ", " + o2); - return result; - } - - result = o1.getName().compareTo(o2.getName()); - VMError.guarantee(result != 0, "HostedType objects not distinguishable by name: " + o1 + ", " + o2); - return result; - } - - result = Integer.compare(ordinal(o1), ordinal(o2)); - VMError.guarantee(result != 0, "HostedType objects not distinguishable by ordinal number: " + o1 + ", " + o2); - return result; - } - - private static int ordinal(HostedType type) { - if (type.isInterface()) { - return 4; - } else if (type.isArray()) { - return 3; - } else if (type.isInstanceClass()) { - return 2; - } else if (type.getJavaKind() != JavaKind.Object) { - return 1; - } else { - throw VMError.shouldNotReachHere(); - } - } - } - - static final Comparator METHOD = new MethodComparator(); - - private static final class MethodComparator implements Comparator { - @Override - public int compare(HostedMethod o1, HostedMethod o2) { - if (o1.equals(o2)) { - return 0; - } - - /* - * Sort deoptimization targets towards the end of the code cache. They are rarely - * executed, and we do not want a deoptimization target as the first method (because - * offset 0 means no deoptimization target available). - */ - int result = Boolean.compare(o1.compilationInfo.isDeoptTarget(), o2.compilationInfo.isDeoptTarget()); - if (result != 0) { - return result; - } - - result = TYPE.compare(o1.getDeclaringClass(), o2.getDeclaringClass()); - if (result != 0) { - return result; - } - - result = o1.getName().compareTo(o2.getName()); - if (result != 0) { - return result; - } - - Signature signature1 = o1.getSignature(); - Signature signature2 = o2.getSignature(); - int parameterCount1 = signature1.getParameterCount(false); - result = Integer.compare(parameterCount1, signature2.getParameterCount(false)); - if (result != 0) { - return result; - } - - for (int i = 0; i < parameterCount1; i++) { - result = TYPE.compare((HostedType) signature1.getParameterType(i, null), (HostedType) signature2.getParameterType(i, null)); - if (result != 0) { - return result; - } - } - - result = TYPE.compare((HostedType) signature1.getReturnType(null), (HostedType) signature2.getReturnType(null)); - if (result != 0) { - return result; - } - - /* - * Note that result can still be 0 at this point. Class substitutions or incomplete - * classpath can cause two separate methods to have the same signature. Fall back to - * identityResult to distinguish such cases. - */ - int identityResult = Integer.compare(System.identityHashCode(o1), System.identityHashCode(o2)); - assert identityResult != 0 : "identityResult != 0"; - return identityResult; - } - } - - /* - * Order by JavaKind. This is required, since we want instance fields of the same size and kind - * consecutive. If the kind is the same, i.e., result == 0, we return 0 so that the sorting - * keeps the order unchanged and therefore keeps the field order we get from the hosting VM. - */ - static final Comparator FIELD = Comparator.comparing(HostedField::getJavaKind); - -} - @AutomaticFeature final class InvalidVTableEntryFeature implements Feature { From f9200cee6fb884b723313932428c689553d77879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 29 Jun 2022 17:42:50 +0200 Subject: [PATCH 03/13] Allow classes with identical fqn from different classloaders in the same image --- .../com/oracle/svm/core/SubstrateUtil.java | 28 +++++++--- .../oracle/svm/hosted/meta/HostedMethod.java | 3 +- .../svm/hosted/meta/HostedUniverse.java | 54 +++++++++++-------- .../svm/hosted/meta/UniverseBuilder.java | 9 ++-- 4 files changed, 58 insertions(+), 36 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index 755d5edea3d9..7f1a0e93942a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -278,21 +278,37 @@ public static String digest(String value) { * name includes a digest of the fully qualified method name, which ensures uniqueness. */ public static String uniqueShortName(ResolvedJavaMethod m) { - StringBuilder fullName = new StringBuilder(); - fullName.append(m.getDeclaringClass().toClassName()).append(".").append(m.getName()).append("("); + return uniqueShortName(new StringBuilder(), m); + } + + public static String uniqueShortName(StringBuilder sb, ResolvedJavaMethod m) { + sb.append(m.getDeclaringClass().toClassName()).append(".").append(m.getName()).append("("); for (int i = 0; i < m.getSignature().getParameterCount(false); i++) { - fullName.append(m.getSignature().getParameterType(i, null).toClassName()).append(","); + sb.append(m.getSignature().getParameterType(i, null).toClassName()).append(","); } - fullName.append(')'); + sb.append(')'); if (!m.isConstructor()) { - fullName.append(m.getSignature().getReturnType(null).toClassName()); + sb.append(m.getSignature().getReturnType(null).toClassName()); } return stripPackage(m.getDeclaringClass().toJavaName()) + "_" + (m.isConstructor() ? "constructor" : m.getName()) + "_" + - SubstrateUtil.digest(fullName.toString()); + SubstrateUtil.digest(sb.toString()); } + public static String classLoaderNameAndId(ClassLoader loader) { + if (loader == null) { + return ""; + } + try { + return (String) classLoaderNameAndId.get(loader); + } catch (IllegalAccessException e) { + throw VMError.shouldNotReachHere("Cannot reflectively access ClassLoader.nameAndId"); + } + } + + private static final Field classLoaderNameAndId = ReflectionUtil.lookupField(ClassLoader.class, "nameAndId"); + /** * Returns a short, reasonably descriptive, but still unique name for the provided * {@link Method}, {@link Constructor}, or {@link Field}. The name includes a digest of the diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index bdbecf5bb5be..bb61765bd532 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -155,7 +155,8 @@ private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signat this.compilationInfo = new CompilationInfo(this, deoptOrigin); this.localVariableTable = localVariableTable; this.name = name; - this.uniqueShortName = SubstrateUtil.uniqueShortName(this); + StringBuilder sb = new StringBuilder(SubstrateUtil.classLoaderNameAndId(holder.getJavaClass().getClassLoader())); + this.uniqueShortName = SubstrateUtil.uniqueShortName(sb, this); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 1043e7b2ade3..220503c4058c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TreeSet; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; @@ -54,6 +55,7 @@ import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.meta.PointsToAnalysisMethod; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; @@ -466,29 +468,35 @@ public int compare(HostedType o1, HostedType o2) { return 0; } - int result; - if (o1.getClass().equals(o2.getClass())) { - if (o1.isPrimitive() && o2.isPrimitive()) { - assert o1 instanceof HostedPrimitiveType && o2 instanceof HostedPrimitiveType; - result = o1.getJavaKind().compareTo(o2.getJavaKind()); - VMError.guarantee(result != 0, "HostedPrimitiveType objects not distinguishable by javaKind: " + o1 + ", " + o2); - return result; - } + if (!o1.getClass().equals(o2.getClass())) { + int result = Integer.compare(ordinal(o1), ordinal(o2)); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by ordinal number: " + o1 + ", " + o2); + return result; + } - if (o1.isArray() && o2.isArray()) { - assert o1 instanceof HostedArrayClass && o2 instanceof HostedArrayClass; - result = compare(o1.getComponentType(), o2.getComponentType()); - VMError.guarantee(result != 0, "HostedArrayClass objects not distinguishable by componentType: " + o1 + ", " + o2); - return result; - } + if (o1.isPrimitive() && o2.isPrimitive()) { + assert o1 instanceof HostedPrimitiveType && o2 instanceof HostedPrimitiveType; + int result = o1.getJavaKind().compareTo(o2.getJavaKind()); + VMError.guarantee(result != 0, "HostedPrimitiveType objects not distinguishable by javaKind: " + o1 + ", " + o2); + return result; + } + + if (o1.isArray() && o2.isArray()) { + assert o1 instanceof HostedArrayClass && o2 instanceof HostedArrayClass; + int result = compare(o1.getComponentType(), o2.getComponentType()); + VMError.guarantee(result != 0, "HostedArrayClass objects not distinguishable by componentType: " + o1 + ", " + o2); + return result; + } - result = o1.getName().compareTo(o2.getName()); - VMError.guarantee(result != 0, "HostedType objects not distinguishable by name: " + o1 + ", " + o2); + int result = o1.getName().compareTo(o2.getName()); + if (result != 0) { return result; } - result = Integer.compare(ordinal(o1), ordinal(o2)); - VMError.guarantee(result != 0, "HostedType objects not distinguishable by ordinal number: " + o1 + ", " + o2); + ClassLoader l1 = Optional.ofNullable(o1.getJavaClass()).map(Class::getClassLoader).orElse(null); + ClassLoader l2 = Optional.ofNullable(o2.getJavaClass()).map(Class::getClassLoader).orElse(null); + result = SubstrateUtil.classLoaderNameAndId(l1).compareTo(SubstrateUtil.classLoaderNameAndId(l2)); + VMError.guarantee(result != 0, "HostedType objects not distinguishable by name and classloader: " + o1 + ", " + o2); return result; } @@ -513,11 +521,11 @@ private static final class MethodComparator implements Comparator private final TypeComparator typeComparator; - private final boolean collisionFatal; + private final boolean strict; - private MethodComparator(TypeComparator typeComparator, boolean collisionFatal) { + private MethodComparator(TypeComparator typeComparator, boolean strict) { this.typeComparator = typeComparator; - this.collisionFatal = collisionFatal; + this.strict = strict; } @Override @@ -570,7 +578,7 @@ public int compare(HostedMethod o1, HostedMethod o2) { * Note that result can still be 0 at this point. This in only allowed during * HostedMethod name collision handling in HostedMethod#create. */ - VMError.guarantee(!collisionFatal, "HostedMethod objects not distinguishable: " + o1 + ", " + o2); + VMError.guarantee(!strict, "HostedMethod objects not distinguishable: " + o1 + ", " + o2); return result; } } @@ -580,6 +588,6 @@ public int compare(HostedMethod o1, HostedMethod o2) { * consecutive. If the kind is the same, i.e., result == 0, we return 0 so that the sorting * keeps the order unchanged and therefore keeps the field order we get from the hosting VM. */ - static final Comparator FIELD_COMPARATOR = Comparator.comparing(HostedField::getJavaKind); + static final Comparator FIELD_COMPARATOR_RELAXED = Comparator.comparing(HostedField::getJavaKind); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 40c46cb20da0..147925431e6c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -158,9 +158,6 @@ public void build(DebugContext debug) { makeMethod(aMethod); } - System.out.println("methodNameCollisions:"); - hUniverse.methodNameCollisions.forEach((method, count) -> System.out.println(count + ": " + method)); - Collection allTypes = hUniverse.types.values(); HostedType objectType = hUniverse.objectType(); HostedType cloneableType = hUniverse.types.get(aMetaAccess.lookupJavaType(Cloneable.class)); @@ -184,7 +181,7 @@ public void build(DebugContext debug) { processFieldLocations(); hUniverse.orderedFields = new ArrayList<>(hUniverse.fields.values()); - Collections.sort(hUniverse.orderedFields, HostedUniverse.FIELD_COMPARATOR); + Collections.sort(hUniverse.orderedFields, HostedUniverse.FIELD_COMPARATOR_RELAXED); profilingInformationBuildTask.join(); } } @@ -443,7 +440,7 @@ private void layoutInstanceFields(HostedInstanceClass clazz, int superSize, Host } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(rawFields, HostedUniverse.FIELD_COMPARATOR); + Collections.sort(rawFields, HostedUniverse.FIELD_COMPARATOR_RELAXED); int nextOffset = startSize; while (rawFields.size() > 0) { @@ -522,7 +519,7 @@ private void layoutStaticFields() { } // Sort so that a) all Object fields are consecutive, and b) bigger types come first. - Collections.sort(fields, HostedUniverse.FIELD_COMPARATOR); + Collections.sort(fields, HostedUniverse.FIELD_COMPARATOR_RELAXED); ObjectLayout layout = ConfigurationValues.getObjectLayout(); From 22ee7eadf220ec2374b2fe224650177cdb3bbc80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Wed, 29 Jun 2022 18:40:09 +0200 Subject: [PATCH 04/13] Bring back sorted JavaTypeProfiles --- .../src/com/oracle/graal/pointsto/api/HostVM.java | 5 +++++ .../results/AbstractAnalysisResultsBuilder.java | 1 + .../src/com/oracle/svm/hosted/SVMHost.java | 13 ++++++++++++- .../com/oracle/svm/hosted/meta/HostedUniverse.java | 8 ++++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index 2e4a60a95a12..c1487bd0f533 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -28,6 +28,7 @@ import java.lang.reflect.AnnotatedElement; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; @@ -238,4 +239,8 @@ public void clearInThread() { public Object getConfiguration() { return null; } + + public Comparator getTypeComparator() { + return null; + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java index 8481bc27961e..146a56d8f5b9 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java @@ -128,6 +128,7 @@ private JavaTypeProfile createTypeProfile(TypeState typeState) { double probability = 1d / typeState.typesCount(); JavaTypeProfile.ProfiledType[] pitems = typeState.typesStream(bb) .map(analysisType -> converter == null ? analysisType : converter.lookup(analysisType)) + .sorted(converter.hostVM().getTypeComparator()) .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) .toArray(JavaTypeProfile.ProfiledType[]::new); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 7f875b7df427..283ffd770095 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -31,6 +31,7 @@ import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; @@ -65,7 +66,6 @@ import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.RelocatedPointer; -import com.oracle.svm.util.GuardedAnnotationAccess; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.api.HostVM; @@ -109,10 +109,12 @@ import com.oracle.svm.hosted.code.UninterruptibleAnnotationChecker; import com.oracle.svm.hosted.heap.PodSupport; import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.phases.AnalysisGraphBuilderPhase; import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyImpl; import com.oracle.svm.hosted.substitute.UnsafeAutomaticSubstitutionProcessor; +import com.oracle.svm.util.GuardedAnnotationAccess; import jdk.vm.ci.meta.DeoptimizationReason; import jdk.vm.ci.meta.ResolvedJavaField; @@ -743,4 +745,13 @@ public boolean neverInlineTrivial(AnalysisMethod caller, AnalysisMethod callee) } return false; } + + @Override + public Comparator getTypeComparator() { + return (Comparator) (o1, o2) -> { + VMError.guarantee(o1 instanceof HostedType, "Expected HostedType. Got " + o1.getClass().getName()); + VMError.guarantee(o2 instanceof HostedType, "Expected HostedType. Got " + o2.getClass().getName()); + return HostedUniverse.TYPE_COMPARATOR.compare((HostedType) o1, (HostedType) o2); + }; + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 220503c4058c..d3b516812bfc 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -458,7 +458,7 @@ public HostedType objectType() { return types.get(bb.getUniverse().objectType()); } - static final TypeComparator TYPE_COMPARATOR = new TypeComparator(); + public static final Comparator TYPE_COMPARATOR = new TypeComparator(); private static final class TypeComparator implements Comparator { @@ -515,15 +515,15 @@ private static int ordinal(HostedType type) { } } - public static final MethodComparator METHOD_COMPARATOR = new MethodComparator(TYPE_COMPARATOR, true); + public static final Comparator METHOD_COMPARATOR = new MethodComparator(TYPE_COMPARATOR, true); private static final class MethodComparator implements Comparator { - private final TypeComparator typeComparator; + private final Comparator typeComparator; private final boolean strict; - private MethodComparator(TypeComparator typeComparator, boolean strict) { + private MethodComparator(Comparator typeComparator, boolean strict) { this.typeComparator = typeComparator; this.strict = strict; } From 0fda7e802986c3965f5b757b20c2b21512173518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 30 Jun 2022 11:49:45 +0200 Subject: [PATCH 05/13] Style fixes --- .../oracle/svm/hosted/meta/HostedMethod.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index bb61765bd532..fad317b0e207 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -66,7 +66,7 @@ import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; -public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, OriginalMethodProvider { +public final class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvider, JavaMethodContext, OriginalMethodProvider { public static final String METHOD_NAME_COLLISION_SUFFIX = "*"; public static final String METHOD_NAME_DEOPT_SUFFIX = "**"; @@ -77,8 +77,8 @@ public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvi private final Signature signature; private final ConstantPool constantPool; private final ExceptionHandler[] handlers; - protected StaticAnalysisResults staticAnalysisResults; - protected int vtableIndex = -1; + StaticAnalysisResults staticAnalysisResults; + int vtableIndex = -1; /** * The address offset of the compiled code relative to the code of the first method in the @@ -92,7 +92,7 @@ public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvi * All concrete methods that can actually be called when calling this method. This includes all * overridden methods in subclasses, as well as this method if it is non-abstract. */ - protected HostedMethod[] implementations; + HostedMethod[] implementations; public final CompilationInfo compilationInfo; private final LocalVariableTable localVariableTable; @@ -123,26 +123,26 @@ private static HostedMethod makeUnique(HostedUniverse universe, HostedMethod met } private static LocalVariableTable createLocalVariableTable(HostedUniverse universe, AnalysisMethod wrapped) { - LocalVariableTable newLocalVariableTable = null; - if (wrapped.getLocalVariableTable() != null) { - try { - Local[] origLocals = wrapped.getLocalVariableTable().getLocals(); - Local[] newLocals = new Local[origLocals.length]; - for (int i = 0; i < newLocals.length; ++i) { - Local origLocal = origLocals[i]; - JavaType origType = origLocal.getType(); - if (!universe.contains(origType)) { - throw new UnsupportedFeatureException("No HostedType for given AnalysisType"); - } - HostedType newType = universe.lookup(origType); - newLocals[i] = new Local(origLocal.getName(), newType, origLocal.getStartBCI(), origLocal.getEndBCI(), origLocal.getSlot()); + LocalVariableTable lvt = wrapped.getLocalVariableTable(); + if (lvt == null) { + return null; + } + try { + Local[] origLocals = lvt.getLocals(); + Local[] newLocals = new Local[origLocals.length]; + for (int i = 0; i < newLocals.length; ++i) { + Local origLocal = origLocals[i]; + JavaType origType = origLocal.getType(); + if (!universe.contains(origType)) { + throw new UnsupportedFeatureException("No HostedType for given AnalysisType"); } - newLocalVariableTable = new LocalVariableTable(newLocals); - } catch (UnsupportedFeatureException e) { - newLocalVariableTable = null; + HostedType newType = universe.lookup(origType); + newLocals[i] = new Local(origLocal.getName(), newType, origLocal.getStartBCI(), origLocal.getEndBCI(), origLocal.getSlot()); } + return new LocalVariableTable(newLocals); + } catch (UnsupportedFeatureException e) { + return null; } - return newLocalVariableTable; } private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, From 21591fb9b85586db0868c39774bde70a555a1ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Thu, 30 Jun 2022 15:42:44 +0200 Subject: [PATCH 06/13] Fix all use of HostedUniverse.createDeoptTarget --- .../com/oracle/svm/hosted/code/CompileQueue.java | 11 +++++++---- .../oracle/svm/hosted/meta/HostedUniverse.java | 15 ++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index a9f022e5a484..38cb89993bfb 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -41,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ForkJoinPool; +import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.replacements.Fold; @@ -634,18 +635,20 @@ private void parseDeoptimizationTargetMethods() { * Deoptimization target code for all methods that were manually marked as deoptimization * targets. */ - universe.getMethods().stream() + List deoptTargetMethods = universe.getMethods().stream() .filter(method -> CompilationInfoSupport.singleton().isDeoptTarget(method)) - .forEach(method -> ensureParsed(universe.createDeoptTarget(method), null, new EntryPointReason())); + .collect(Collectors.toList()); + deoptTargetMethods.forEach(method -> ensureParsed(universe.createDeoptTarget(method), null, new EntryPointReason())); /* * Deoptimization target code for deoptimization testing: all methods that are not * blacklisted are possible deoptimization targets. The methods are also flagged so that all * possible deoptimization entry points are emitted. */ - universe.getMethods().stream() + List deoptTargetForTestingMethods = universe.getMethods().stream() .filter(method -> method.getWrapped().isImplementationInvoked() && canDeoptForTesting(method)) - .forEach(this::ensureParsedForDeoptTesting); + .collect(Collectors.toList()); + deoptTargetForTestingMethods.forEach(this::ensureParsedForDeoptTesting); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index d3b516812bfc..ac7f5a6da5c4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -311,14 +311,15 @@ public HostedInstanceClass getObjectClass() { return result; } - public synchronized HostedMethod createDeoptTarget(HostedMethod method) { - if (method.compilationInfo.getDeoptTargetMethod() == null) { - HostedMethod deoptTarget = HostedMethod.create(this, method.getWrapped(), method.getDeclaringClass(), - method.getSignature(), method.getConstantPool(), method.getExceptionHandlers(), method); - assert method.staticAnalysisResults != null; - deoptTarget.staticAnalysisResults = method.staticAnalysisResults; + public synchronized HostedMethod createDeoptTarget(HostedMethod deoptOrigin) { + assert !deoptOrigin.isDeoptTarget(); + if (deoptOrigin.compilationInfo.getDeoptTargetMethod() == null) { + HostedMethod deoptTarget = HostedMethod.create(this, deoptOrigin.getWrapped(), deoptOrigin.getDeclaringClass(), + deoptOrigin.getSignature(), deoptOrigin.getConstantPool(), deoptOrigin.getExceptionHandlers(), deoptOrigin); + assert deoptOrigin.staticAnalysisResults != null; + deoptTarget.staticAnalysisResults = deoptOrigin.staticAnalysisResults; } - return method.compilationInfo.getDeoptTargetMethod(); + return deoptOrigin.compilationInfo.getDeoptTargetMethod(); } public boolean contains(JavaType type) { From c022001cb694d618aeadce7a0a06fb4552859786 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 4 Jul 2022 14:16:10 +0200 Subject: [PATCH 07/13] HostedUniverse#getMethods must not contain deop-target methods --- .../src/com/oracle/svm/hosted/meta/HostedUniverse.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index ac7f5a6da5c4..04be61962347 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -34,6 +34,8 @@ import java.util.Map; import java.util.Optional; import java.util.TreeSet; +import java.util.function.Predicate; +import java.util.stream.Collectors; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.StructuredGraph; @@ -438,7 +440,9 @@ public Collection getFields() { } public Collection getMethods() { - return orderedMethods; + return orderedMethods.stream() + .filter(Predicate.not(HostedMethod::isDeoptTarget)) + .collect(Collectors.toList()); } public Inflation getBigBang() { From 648b99359be13a78799160febbf339067fb20078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 4 Jul 2022 15:43:01 +0200 Subject: [PATCH 08/13] Ensure HostedField sort order remains the same --- .../src/com/oracle/svm/hosted/meta/HostedUniverse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 04be61962347..4e4ffdf08014 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -593,6 +593,6 @@ public int compare(HostedMethod o1, HostedMethod o2) { * consecutive. If the kind is the same, i.e., result == 0, we return 0 so that the sorting * keeps the order unchanged and therefore keeps the field order we get from the hosting VM. */ - static final Comparator FIELD_COMPARATOR_RELAXED = Comparator.comparing(HostedField::getJavaKind); + static final Comparator FIELD_COMPARATOR_RELAXED = Comparator.comparing(HostedField::getJavaKind).reversed(); } From ab8de5ea8c6333a278b666e249084cf286fed249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 4 Jul 2022 17:39:27 +0200 Subject: [PATCH 09/13] Use HostedMethod.getUniqueShortName consistently in llvm backend --- .../src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java | 8 ++++---- .../svm/core/graal/llvm/LLVMNativeImageCodeCache.java | 3 +-- .../svm/core/graal/llvm/util/LLVMObjectFileReader.java | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java index 734cef105cfe..6ca7fab14c81 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMGenerator.java @@ -44,7 +44,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiFunction; -import com.oracle.svm.shadowed.org.bytedeco.llvm.global.LLVM; import org.graalvm.compiler.code.CompilationResult; import org.graalvm.compiler.core.common.CompressEncoding; import org.graalvm.compiler.core.common.LIRKind; @@ -83,7 +82,6 @@ import org.graalvm.compiler.serviceprovider.JavaVersionUtil; import org.graalvm.nativeimage.c.constant.CEnum; import org.graalvm.nativeimage.c.function.CEntryPoint; -import com.oracle.svm.util.GuardedAnnotationAccess; import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.ReservedRegisters; @@ -125,6 +123,8 @@ import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMBasicBlockRef; import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMTypeRef; import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMValueRef; +import com.oracle.svm.shadowed.org.bytedeco.llvm.global.LLVM; +import com.oracle.svm.util.GuardedAnnotationAccess; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.code.CallingConvention; @@ -186,7 +186,7 @@ public class LLVMGenerator implements LIRGeneratorTool, SubstrateLIRGenerator { this.lirKindTool = new LLVMUtils.LLVMKindTool(builder); this.debugInfoPrinter = new DebugInfoPrinter(this, debugLevel); - this.functionName = SubstrateUtil.uniqueShortName(method); + this.functionName = ((HostedMethod) method).getUniqueShortName(); this.isEntryPoint = isEntryPoint(method); this.modifiesSpecialRegisters = modifiesSpecialRegisters(graph); @@ -291,7 +291,7 @@ byte[] getBitcode() { } private static String getFunctionName(ResolvedJavaMethod method) { - return SubstrateUtil.uniqueShortName(method); + return ((HostedMethod) method).getUniqueShortName(); } private static boolean isEntryPoint(ResolvedJavaMethod method) { diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index cd57cdf50926..a61617d50c52 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -63,7 +63,6 @@ import com.oracle.objectfile.ObjectFile.Element; import com.oracle.objectfile.SectionName; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.graal.code.CGlobalDataInfo; import com.oracle.svm.core.graal.code.CGlobalDataReference; @@ -224,7 +223,7 @@ private void linkCompiledBatches(BatchExecutor executor, DebugContext debug, int executor.forEach(getOrderedCompilations(), pair -> (debugContext) -> { HostedMethod method = pair.getLeft(); - int offset = textSectionInfo.getOffset(SubstrateUtil.uniqueShortName(method)); + int offset = textSectionInfo.getOffset(method.getUniqueShortName()); int nextFunctionStartOffset = textSectionInfo.getNextOffset(offset); int functionSize = nextFunctionStartOffset - offset; diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java index f9ac10d52f8d..0ea11174e79b 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/util/LLVMObjectFileReader.java @@ -43,10 +43,10 @@ import com.oracle.objectfile.ObjectFile; import com.oracle.objectfile.SectionName; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.graal.llvm.LLVMGenerator; import com.oracle.svm.core.graal.llvm.LLVMNativeImageCodeCache.StackMapDumper; import com.oracle.svm.core.heap.SubstrateReferenceMap; +import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.shadowed.org.bytedeco.javacpp.BytePointer; import com.oracle.svm.shadowed.org.bytedeco.javacpp.Pointer; import com.oracle.svm.shadowed.org.bytedeco.llvm.LLVM.LLVMMemoryBufferRef; @@ -161,7 +161,7 @@ private LLVMStackMapInfo readStackMapSection(LLVMSectionIteratorRef sectionItera } public void readStackMap(LLVMStackMapInfo info, CompilationResult compilation, ResolvedJavaMethod method, int id) { - String methodSymbolName = SYMBOL_PREFIX + SubstrateUtil.uniqueShortName(method); + String methodSymbolName = SYMBOL_PREFIX + ((HostedMethod) method).getUniqueShortName(); long startPatchpointID = compilation.getInfopoints().stream().filter(ip -> ip.reason == InfopointReason.METHOD_START).findFirst() .orElseThrow(() -> new GraalError("no method start infopoint: " + methodSymbolName)).pcOffset; From 02653a5a0d08ee55a9d0c8aa7668df468fa6d670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 5 Jul 2022 10:58:15 +0200 Subject: [PATCH 10/13] Make HostVM.getTypeComparator abstract --- .../src/com/oracle/graal/pointsto/api/HostVM.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java index c1487bd0f533..9a66ef69be47 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/api/HostVM.java @@ -240,7 +240,5 @@ public Object getConfiguration() { return null; } - public Comparator getTypeComparator() { - return null; - } + public abstract Comparator getTypeComparator(); } From 77be326e9e7eb815bb4afebe02860383f3c19d02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Tue, 5 Jul 2022 13:44:17 +0200 Subject: [PATCH 11/13] Account for AbstractAnalysisResultsBuilder.converter being null --- .../results/AbstractAnalysisResultsBuilder.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java index 146a56d8f5b9..27c60b236312 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/AbstractAnalysisResultsBuilder.java @@ -27,6 +27,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; import com.oracle.graal.pointsto.BigBang; import com.oracle.graal.pointsto.api.PointstoOptions; @@ -38,6 +39,7 @@ import jdk.vm.ci.meta.JavaMethodProfile; import jdk.vm.ci.meta.JavaTypeProfile; import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.TriState; public abstract class AbstractAnalysisResultsBuilder { @@ -126,9 +128,12 @@ private JavaTypeProfile cachedTypeProfile(JavaTypeProfile[] cache, int cacheIdx, private JavaTypeProfile createTypeProfile(TypeState typeState) { double probability = 1d / typeState.typesCount(); - JavaTypeProfile.ProfiledType[] pitems = typeState.typesStream(bb) - .map(analysisType -> converter == null ? analysisType : converter.lookup(analysisType)) - .sorted(converter.hostVM().getTypeComparator()) + + Stream stream = typeState.typesStream(bb); + if (converter != null) { + stream = stream.map(converter::lookup).sorted(converter.hostVM().getTypeComparator()); + } + JavaTypeProfile.ProfiledType[] pitems = stream .map(type -> new JavaTypeProfile.ProfiledType(type, probability)) .toArray(JavaTypeProfile.ProfiledType[]::new); From 39a82fbeba14c7172c9c4b1420e81a0b2811d939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 11 Jul 2022 14:21:07 +0200 Subject: [PATCH 12/13] Decouple HostedMethod name collision handling from orderedMethods collection --- .../com/oracle/svm/core/SubstrateUtil.java | 20 +++++++------ .../src/com/oracle/svm/hosted/SVMHost.java | 2 -- .../oracle/svm/hosted/code/CompileQueue.java | 12 +++----- .../oracle/svm/hosted/meta/HostedMethod.java | 28 ++++++------------- .../svm/hosted/meta/HostedUniverse.java | 25 ++++------------- .../svm/hosted/meta/UniverseBuilder.java | 3 ++ 6 files changed, 33 insertions(+), 57 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java index 7f1a0e93942a..d81b9092c0df 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateUtil.java @@ -60,6 +60,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.Signature; import jdk.vm.ci.services.Services; public class SubstrateUtil { @@ -278,21 +279,22 @@ public static String digest(String value) { * name includes a digest of the fully qualified method name, which ensures uniqueness. */ public static String uniqueShortName(ResolvedJavaMethod m) { - return uniqueShortName(new StringBuilder(), m); + return uniqueShortName("", m.getDeclaringClass(), m.getName(), m.getSignature(), m.isConstructor()); } - public static String uniqueShortName(StringBuilder sb, ResolvedJavaMethod m) { - sb.append(m.getDeclaringClass().toClassName()).append(".").append(m.getName()).append("("); - for (int i = 0; i < m.getSignature().getParameterCount(false); i++) { - sb.append(m.getSignature().getParameterType(i, null).toClassName()).append(","); + public static String uniqueShortName(String loaderNameAndId, ResolvedJavaType declaringClass, String methodName, Signature methodSignature, boolean isConstructor) { + StringBuilder sb = new StringBuilder(loaderNameAndId); + sb.append(declaringClass.toClassName()).append(".").append(methodName).append("("); + for (int i = 0; i < methodSignature.getParameterCount(false); i++) { + sb.append(methodSignature.getParameterType(i, null).toClassName()).append(","); } sb.append(')'); - if (!m.isConstructor()) { - sb.append(m.getSignature().getReturnType(null).toClassName()); + if (!isConstructor) { + sb.append(methodSignature.getReturnType(null).toClassName()); } - return stripPackage(m.getDeclaringClass().toJavaName()) + "_" + - (m.isConstructor() ? "constructor" : m.getName()) + "_" + + return stripPackage(declaringClass.toJavaName()) + "_" + + (isConstructor ? "constructor" : methodName) + "_" + SubstrateUtil.digest(sb.toString()); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 283ffd770095..610d6bb7b5d2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -749,8 +749,6 @@ public boolean neverInlineTrivial(AnalysisMethod caller, AnalysisMethod callee) @Override public Comparator getTypeComparator() { return (Comparator) (o1, o2) -> { - VMError.guarantee(o1 instanceof HostedType, "Expected HostedType. Got " + o1.getClass().getName()); - VMError.guarantee(o2 instanceof HostedType, "Expected HostedType. Got " + o2.getClass().getName()); return HostedUniverse.TYPE_COMPARATOR.compare((HostedType) o1, (HostedType) o2); }; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index 38cb89993bfb..f308c884ed13 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -41,7 +41,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ForkJoinPool; -import java.util.stream.Collectors; import org.graalvm.collections.EconomicMap; import org.graalvm.compiler.api.replacements.Fold; @@ -635,21 +634,18 @@ private void parseDeoptimizationTargetMethods() { * Deoptimization target code for all methods that were manually marked as deoptimization * targets. */ - List deoptTargetMethods = universe.getMethods().stream() + universe.getMethods().stream() .filter(method -> CompilationInfoSupport.singleton().isDeoptTarget(method)) - .collect(Collectors.toList()); - deoptTargetMethods.forEach(method -> ensureParsed(universe.createDeoptTarget(method), null, new EntryPointReason())); + .forEach(method -> ensureParsed(universe.createDeoptTarget(method), null, new EntryPointReason())); /* * Deoptimization target code for deoptimization testing: all methods that are not * blacklisted are possible deoptimization targets. The methods are also flagged so that all * possible deoptimization entry points are emitted. */ - List deoptTargetForTestingMethods = universe.getMethods().stream() + universe.getMethods().stream() .filter(method -> method.getWrapped().isImplementationInvoked() && canDeoptForTesting(method)) - .collect(Collectors.toList()); - deoptTargetForTestingMethods.forEach(this::ensureParsedForDeoptTesting); - + .forEach(this::ensureParsedForDeoptTesting); } private void ensureParsedForDeoptTesting(HostedMethod method) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index fad317b0e207..161828267ed2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -102,24 +102,15 @@ public final class HostedMethod implements SharedMethod, WrappedJavaMethod, Grap public static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, ExceptionHandler[] handlers, HostedMethod deoptOrigin) { - String name = deoptOrigin != null ? wrapped.getName() + METHOD_NAME_DEOPT_SUFFIX : wrapped.getName(); LocalVariableTable localVariableTable = createLocalVariableTable(universe, wrapped); - HostedMethod hostedMethod = new HostedMethod(wrapped, holder, signature, constantPool, handlers, deoptOrigin, name, localVariableTable); - hostedMethod = makeUnique(universe, hostedMethod, deoptOrigin, name); - universe.orderedMethods.add(hostedMethod); - return hostedMethod; - } - - private static HostedMethod makeUnique(HostedUniverse universe, HostedMethod method, HostedMethod deoptOrigin, String name) { - if (!universe.orderedMethods.contains(method)) { - return method; + String name = deoptOrigin != null ? wrapped.getName() + METHOD_NAME_DEOPT_SUFFIX : wrapped.getName(); + String uniqueShortName = SubstrateUtil.uniqueShortName(SubstrateUtil.classLoaderNameAndId(holder.getJavaClass().getClassLoader()), holder, name, signature, wrapped.isConstructor()); + int collisionCount = universe.uniqueHostedMethodNames.merge(uniqueShortName, 0, (oldValue, value) -> oldValue + 1); + if (collisionCount > 0) { + name = name + METHOD_NAME_COLLISION_SUFFIX + collisionCount; + uniqueShortName = SubstrateUtil.uniqueShortName(SubstrateUtil.classLoaderNameAndId(holder.getJavaClass().getClassLoader()), holder, name, signature, wrapped.isConstructor()); } - int collisionCount = universe.methodNameCollisions.merge(method, 1, (oldValue, value) -> oldValue + 1); - String collisionName = name + METHOD_NAME_COLLISION_SUFFIX + collisionCount; - HostedMethod hostedMethod = new HostedMethod(method.wrapped, method.holder, method.signature, method.constantPool, - method.handlers, deoptOrigin, collisionName, method.localVariableTable); - VMError.guarantee(!universe.orderedMethods.contains(hostedMethod), "HostedMethod name collision handling failed"); - return hostedMethod; + return new HostedMethod(wrapped, holder, signature, constantPool, handlers, deoptOrigin, name, uniqueShortName, localVariableTable); } private static LocalVariableTable createLocalVariableTable(HostedUniverse universe, AnalysisMethod wrapped) { @@ -146,7 +137,7 @@ private static LocalVariableTable createLocalVariableTable(HostedUniverse univer } private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, - ExceptionHandler[] handlers, HostedMethod deoptOrigin, String name, LocalVariableTable localVariableTable) { + ExceptionHandler[] handlers, HostedMethod deoptOrigin, String name, String uniqueShortName, LocalVariableTable localVariableTable) { this.wrapped = wrapped; this.holder = holder; this.signature = signature; @@ -155,8 +146,7 @@ private HostedMethod(AnalysisMethod wrapped, HostedType holder, Signature signat this.compilationInfo = new CompilationInfo(this, deoptOrigin); this.localVariableTable = localVariableTable; this.name = name; - StringBuilder sb = new StringBuilder(SubstrateUtil.classLoaderNameAndId(holder.getJavaClass().getClassLoader())); - this.uniqueShortName = SubstrateUtil.uniqueShortName(sb, this); + this.uniqueShortName = uniqueShortName; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 4e4ffdf08014..847db6a5cc8f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -33,9 +33,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.TreeSet; -import java.util.function.Predicate; -import java.util.stream.Collectors; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.StructuredGraph; @@ -294,9 +291,9 @@ public class HostedUniverse implements Universe { protected List orderedTypes; protected List orderedFields; + protected List orderedMethods; - TreeSet orderedMethods = new TreeSet<>(new MethodComparator(TYPE_COMPARATOR, false)); - Map methodNameCollisions = new HashMap<>(); + Map uniqueHostedMethodNames = new HashMap<>(); public HostedUniverse(Inflation bb) { this.bb = bb; @@ -440,9 +437,7 @@ public Collection getFields() { } public Collection getMethods() { - return orderedMethods.stream() - .filter(Predicate.not(HostedMethod::isDeoptTarget)) - .collect(Collectors.toList()); + return orderedMethods; } public Inflation getBigBang() { @@ -520,17 +515,14 @@ private static int ordinal(HostedType type) { } } - public static final Comparator METHOD_COMPARATOR = new MethodComparator(TYPE_COMPARATOR, true); + public static final Comparator METHOD_COMPARATOR = new MethodComparator(TYPE_COMPARATOR); private static final class MethodComparator implements Comparator { private final Comparator typeComparator; - private final boolean strict; - - private MethodComparator(Comparator typeComparator, boolean strict) { + private MethodComparator(Comparator typeComparator) { this.typeComparator = typeComparator; - this.strict = strict; } @Override @@ -579,12 +571,7 @@ public int compare(HostedMethod o1, HostedMethod o2) { return result; } - /* - * Note that result can still be 0 at this point. This in only allowed during - * HostedMethod name collision handling in HostedMethod#create. - */ - VMError.guarantee(!strict, "HostedMethod objects not distinguishable: " + o1 + ", " + o2); - return result; + throw VMError.shouldNotReachHere("HostedMethod objects not distinguishable: " + o1 + ", " + o2); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 147925431e6c..57ade8549793 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -180,6 +180,9 @@ public void build(DebugContext debug) { processFieldLocations(); + hUniverse.uniqueHostedMethodNames.clear(); + hUniverse.orderedMethods = new ArrayList<>(hUniverse.methods.values()); + Collections.sort(hUniverse.orderedMethods, HostedUniverse.METHOD_COMPARATOR); hUniverse.orderedFields = new ArrayList<>(hUniverse.fields.values()); Collections.sort(hUniverse.orderedFields, HostedUniverse.FIELD_COMPARATOR_RELAXED); profilingInformationBuildTask.join(); From 82a0b09aaca33ecfb63eb99352a7079e279e226c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=B6gerer?= Date: Mon, 11 Jul 2022 14:34:20 +0200 Subject: [PATCH 13/13] Make HostedMethod.create thread-safe --- .../src/com/oracle/svm/hosted/meta/HostedUniverse.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 847db6a5cc8f..43fa6ff94b29 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.StructuredGraph; @@ -293,7 +294,7 @@ public class HostedUniverse implements Universe { protected List orderedFields; protected List orderedMethods; - Map uniqueHostedMethodNames = new HashMap<>(); + Map uniqueHostedMethodNames = new ConcurrentHashMap<>(); public HostedUniverse(Inflation bb) { this.bb = bb;