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 e220a2b68f4c..ee054e3f13a4 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 @@ -51,6 +51,7 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.TargetClass; +import com.oracle.svm.core.util.HostedSubstrateUtil; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.StringUtil; @@ -376,12 +377,14 @@ public static String defaultUniqueShortName(Member m) { * @return A unique identifier for the classloader or the empty string when the loader is one of * the special set whose method names do not need qualification. */ - public static String classLoaderNameAndId(ClassLoader loader) { - if (loader == null) { + public static String runtimeClassLoaderNameAndId(ClassLoader loader) { + ClassLoader runtimeClassLoader = SubstrateUtil.HOSTED ? HostedSubstrateUtil.getRuntimeClassLoader(loader) : loader; + + if (runtimeClassLoader == null) { return ""; } try { - return (String) classLoaderNameAndId.get(loader); + return (String) classLoaderNameAndId.get(runtimeClassLoader); } catch (IllegalAccessException e) { throw VMError.shouldNotReachHere("Cannot reflectively access ClassLoader.nameAndId"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/UniqueShortNameProviderDefaultImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/UniqueShortNameProviderDefaultImpl.java index 247cd2b92b10..6522e7ff0f8c 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/UniqueShortNameProviderDefaultImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/UniqueShortNameProviderDefaultImpl.java @@ -42,7 +42,7 @@ public class UniqueShortNameProviderDefaultImpl implements UniqueShortNameProvider { @Override public String uniqueShortName(ClassLoader loader, ResolvedJavaType declaringClass, String methodName, Signature methodSignature, boolean isConstructor) { - return SubstrateUtil.defaultUniqueShortName(SubstrateUtil.classLoaderNameAndId(loader), declaringClass, methodName, methodSignature, isConstructor); + return SubstrateUtil.defaultUniqueShortName(SubstrateUtil.runtimeClassLoaderNameAndId(loader), declaringClass, methodName, methodSignature, isConstructor); } @Override @@ -52,7 +52,7 @@ public String uniqueShortName(Member m) { @Override public String uniqueShortLoaderName(ClassLoader classLoader) { - return SubstrateUtil.classLoaderNameAndId(classLoader); + return SubstrateUtil.runtimeClassLoaderNameAndId(classLoader); } public static class UseDefault implements BooleanSupplier { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/HostedSubstrateUtil.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/HostedSubstrateUtil.java new file mode 100644 index 000000000000..750e8222a333 --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/util/HostedSubstrateUtil.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.util; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +@Platforms(Platform.HOSTED_ONLY.class) +public interface HostedSubstrateUtil { + + static ClassLoader getRuntimeClassLoader(ClassLoader loader) { + return ImageSingletons.lookup(HostedSubstrateUtil.class).doGetRuntimeClassLoader(loader); + } + + ClassLoader doGetRuntimeClassLoader(ClassLoader loader); +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageBFDNameProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageBFDNameProvider.java index 8b6b69841020..e90a74dd6e52 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageBFDNameProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageBFDNameProvider.java @@ -87,7 +87,7 @@ public String uniqueShortLoaderName(ClassLoader loader) { if (isGraalImageLoader(loader)) { return ""; } - String name = SubstrateUtil.classLoaderNameAndId(loader); + String name = SubstrateUtil.runtimeClassLoaderNameAndId(loader); // name will look like "org.foo.bar.FooBarClassLoader @1234" // trim it down to something more manageable // escaping quotes in the classlaoder name does not work in GDB 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 484f152115d5..671a8bc00044 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 @@ -34,7 +34,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.util.function.Function; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.infrastructure.OriginalMethodProvider; @@ -150,20 +149,30 @@ static HostedMethod create(HostedUniverse universe, AnalysisMethod wrapped, Host private static HostedMethod create0(AnalysisMethod wrapped, HostedType holder, ResolvedSignature signature, ConstantPool constantPool, ExceptionHandler[] handlers, MultiMethodKey key, Map multiMethodMap, LocalVariableTable localVariableTable) { - Function nameGenerator = (collisionCount) -> { - String name = wrapped.wrapped.getName(); // want name w/o any multimethodkey suffix - if (key != ORIGINAL_METHOD) { - name += StableMethodNameFormatter.MULTI_METHOD_KEY_SEPARATOR + key; - } - if (collisionCount > 0) { - name = name + METHOD_NAME_COLLISION_SEPARATOR + collisionCount; + var generator = new HostedMethodNameFactory.NameGenerator() { + + @Override + public HostedMethodNameFactory.MethodNameInfo generateMethodNameInfo(int collisionCount) { + String name = wrapped.wrapped.getName(); // want name w/o any multimethodkey suffix + if (key != ORIGINAL_METHOD) { + name += StableMethodNameFormatter.MULTI_METHOD_KEY_SEPARATOR + key; + } + if (collisionCount > 0) { + name = name + METHOD_NAME_COLLISION_SEPARATOR + collisionCount; + } + + String uniqueShortName = generateUniqueName(name); + + return new HostedMethodNameFactory.MethodNameInfo(name, uniqueShortName); } - String uniqueShortName = SubstrateUtil.uniqueShortName(holder.getJavaClass().getClassLoader(), holder, name, signature, wrapped.isConstructor()); - return new HostedMethodNameFactory.MethodNameInfo(name, uniqueShortName); + @Override + public String generateUniqueName(String name) { + return SubstrateUtil.uniqueShortName(holder.getJavaClass().getClassLoader(), holder, name, signature, wrapped.isConstructor()); + } }; - HostedMethodNameFactory.MethodNameInfo names = HostedMethodNameFactory.singleton().createNames(nameGenerator, wrapped); + HostedMethodNameFactory.MethodNameInfo names = HostedMethodNameFactory.singleton().createNames(generator, wrapped); return new HostedMethod(wrapped, holder, signature, constantPool, handlers, names.name(), names.uniqueShortName(), localVariableTable, key, multiMethodMap); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java index 9ca4a1169ad0..cc4fbcd36665 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethodNameFactory.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Function; import org.graalvm.nativeimage.ImageSingletons; @@ -35,27 +34,49 @@ import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport; +import com.oracle.svm.core.option.HostedOptionKey; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.imagelayer.HostedDynamicLayerInfo; +import com.oracle.svm.util.LogUtils; + +import jdk.graal.compiler.options.Option; @AutomaticallyRegisteredFeature public class HostedMethodNameFactory implements InternalFeature { + public static final class Options { + @Option(help = "Log unique names which do not match across layers. This is an experimental option which will be removed.") // + public static final HostedOptionKey LogUniqueNameInconsistencies = new HostedOptionKey<>(false); + } + private Map methodNameCount = new ConcurrentHashMap<>(); private Set uniqueShortNames = ConcurrentHashMap.newKeySet(); private final boolean buildingExtensionLayer = ImageLayerBuildingSupport.buildingExtensionLayer(); private Set reservedUniqueShortNames = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().getReservedNames() : null; + private final boolean logUniqueNameInconsistencies = Options.LogUniqueNameInconsistencies.getValue(); public record MethodNameInfo(String name, String uniqueShortName) { } + public interface NameGenerator { + MethodNameInfo generateMethodNameInfo(int collisionCount); + + String generateUniqueName(String name); + } + public static HostedMethodNameFactory singleton() { return ImageSingletons.lookup(HostedMethodNameFactory.class); } - MethodNameInfo createNames(Function nameGenerator, AnalysisMethod aMethod) { + MethodNameInfo createNames(NameGenerator generator, AnalysisMethod aMethod) { MethodNameInfo result = buildingExtensionLayer ? HostedDynamicLayerInfo.singleton().loadMethodNameInfo(aMethod) : null; if (result != null) { assert reservedUniqueShortNames.contains(result.uniqueShortName()) : result; + if (logUniqueNameInconsistencies) { + boolean consistentNames = generator.generateUniqueName(result.name()).equals(result.uniqueShortName); + if (!consistentNames) { + LogUtils.warning("Unique names are inconsistent for %s", aMethod.getQualifiedName()); + } + } boolean added = uniqueShortNames.add(result.uniqueShortName()); if (added) { @@ -67,13 +88,13 @@ MethodNameInfo createNames(Function nameGenerator, Anal } } - MethodNameInfo initialName = nameGenerator.apply(0); + MethodNameInfo initialName = generator.generateMethodNameInfo(0); result = initialName; do { int collisionCount = methodNameCount.merge(initialName.uniqueShortName(), 0, (oldValue, value) -> oldValue + 1); if (collisionCount != 0) { - result = nameGenerator.apply(collisionCount); + result = generator.generateMethodNameInfo(collisionCount); } /* * Redo if the short name is reserved. 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 e284b03539db..ade7c8c7cbe1 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 @@ -671,7 +671,7 @@ public int compare(HostedType o1, HostedType 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)); + result = SubstrateUtil.runtimeClassLoaderNameAndId(l1).compareTo(SubstrateUtil.runtimeClassLoaderNameAndId(l2)); VMError.guarantee(result != 0, "HostedType objects not distinguishable by name and classloader: %s, %s", o1, o2); return result; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/HostedSubstrateUtilDefaultImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/HostedSubstrateUtilDefaultImpl.java new file mode 100644 index 000000000000..f08d656a0de6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/util/HostedSubstrateUtilDefaultImpl.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.hosted.util; + +import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; +import com.oracle.svm.core.util.HostedSubstrateUtil; +import com.oracle.svm.hosted.ClassLoaderFeature; + +@AutomaticallyRegisteredImageSingleton(value = HostedSubstrateUtil.class) +public class HostedSubstrateUtilDefaultImpl implements HostedSubstrateUtil { + + @Override + public ClassLoader doGetRuntimeClassLoader(ClassLoader loader) { + return ClassLoaderFeature.getRuntimeClassLoader(loader); + } +}