diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java index ca0ff10fae12..4e0e26bebac3 100644 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java +++ b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/CheckGraalInvariants.java @@ -397,7 +397,6 @@ public boolean add(String s) { verifiers.add(new VerifyLoopInfo()); verifiers.add(new VerifyGuardsStageUsages()); verifiers.add(new VerifyAArch64RegisterUsages()); - verifiers.add(new VerifyAnnotatedElementUsage()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); diff --git a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAnnotatedElementUsage.java b/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAnnotatedElementUsage.java deleted file mode 100644 index 87852eb1ea13..000000000000 --- a/compiler/src/jdk.graal.compiler.test/src/jdk/graal/compiler/core/test/VerifyAnnotatedElementUsage.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2013, 2022, 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 jdk.graal.compiler.core.test; - -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import jdk.graal.compiler.annotation.AnnotationValueSupport; -import jdk.graal.compiler.core.common.type.Stamp; -import jdk.graal.compiler.nodes.NodeView; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.nodes.ValueNode; -import jdk.graal.compiler.nodes.java.MethodCallTargetNode; -import jdk.graal.compiler.nodes.spi.CoreProviders; -import jdk.graal.compiler.nodes.spi.UncheckedInterfaceProvider; -import jdk.graal.compiler.util.EconomicHashMap; -import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; - -/** - * Verifies that calls to methods declared by {@link AnnotatedElement} never have a receiver of type - * {@link ResolvedJavaType}, {@link ResolvedJavaMethod} or {@link ResolvedJavaField}. Once GR-69713, - * is resolved ("Remove AnnotatedElement from JVMCI types"), this verification can be deleted. - */ -public class VerifyAnnotatedElementUsage extends VerifyStringFormatterUsage { - - private volatile Map annotatedElementMethods; - - private static final String JVMCI_META_PACKAGE_PREFIX = "L" + ResolvedJavaType.class.getPackage().getName().replace('.', '/'); - private static final Set ANNOTATED_ELEMENT_METHOD_NAMES = Stream.of(AnnotatedElement.class.getDeclaredMethods()).map(Method::getName).collect(Collectors.toSet()); - - @Override - protected void verify(StructuredGraph graph, CoreProviders context) { - MetaAccessProvider metaAccess = context.getMetaAccess(); - ResolvedJavaType annotatedElementType = metaAccess.lookupJavaType(AnnotatedElement.class); - ResolvedJavaType resolvedJavaTypeType = metaAccess.lookupJavaType(ResolvedJavaType.class); - ResolvedJavaType resolvedJavaMethodType = metaAccess.lookupJavaType(ResolvedJavaMethod.class); - ResolvedJavaType resolvedJavaFieldType = metaAccess.lookupJavaType(ResolvedJavaField.class); - - if (annotatedElementMethods == null) { - Map map = new EconomicHashMap<>(); - for (Method m : AnnotatedElement.class.getDeclaredMethods()) { - map.put(m.getName(), metaAccess.lookupJavaMethod(m).getSignature().toMethodDescriptor()); - } - annotatedElementMethods = map; - } - - for (MethodCallTargetNode t : graph.getNodes(MethodCallTargetNode.TYPE)) { - ResolvedJavaMethod callee = t.targetMethod(); - String descriptor = annotatedElementMethods.get(callee.getName()); - if (descriptor != null && descriptor.equals(callee.getSignature().toMethodDescriptor())) { - if (callee.hasReceiver()) { - ValueNode receiver = t.arguments().getFirst(); - Stamp receiverStamp = receiver.stamp(NodeView.DEFAULT); - if (receiver instanceof UncheckedInterfaceProvider unchecked) { - Stamp uncheckedStamp = unchecked.uncheckedStamp(); - if (uncheckedStamp != null) { - receiverStamp = uncheckedStamp; - } - } - ResolvedJavaType receiverType = receiverStamp.javaType(metaAccess); - if (resolvedJavaTypeType.isAssignableFrom(receiverType) || - resolvedJavaMethodType.isAssignableFrom(receiverType) || - resolvedJavaFieldType.isAssignableFrom(receiverType)) { - - throw new VerificationError( - t, "call to %s with receiver type %s should be replaced by use of %s.%n", - callee.format("%H.%n(%p)"), - receiverType.toClassName(), - AnnotationValueSupport.class.getName()); - } - } - } - } - } -} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java index ee9d740d3a37..f7eef4e66649 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java @@ -109,6 +109,7 @@ import com.oracle.svm.shared.util.ReflectionUtil; import com.oracle.svm.shared.util.StringUtil; import com.oracle.svm.shared.util.VMError; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.HostedModuleSupport; import jdk.graal.compiler.debug.GraalError; @@ -281,6 +282,7 @@ public boolean dynamicAccessSelectorsEmpty() { modulepathModuleFinder = ModuleFinder.of(modulepath().toArray(Path[]::new)); annotationExtractor = new SubstrateAnnotationExtractor(); + AnnotationUtil.installHostedAnnotationExtractor(annotationExtractor); includeConfigSealed = false; diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java index 5038ad080058..9ca723aa60fa 100644 --- a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java @@ -33,11 +33,9 @@ import java.util.function.Function; import org.graalvm.nativeimage.ImageInfo; -import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.AnnotationExtractor; -import org.graalvm.nativeimage.impl.ImageSingletonsSupport; import com.oracle.svm.shared.util.ModuleSupport; @@ -54,8 +52,7 @@ /** * This complements {@link org.graalvm.nativeimage.AnnotationAccess} for use by SVM internal * features and code. It avoids relying on JVMCI types (such as {@link ResolvedJavaType}) - * implementing {@link java.lang.reflect.AnnotatedElement}. This inheritance is planned for removal - * (GR-69713) as part of reducing use of core reflection in Native Image. + * implementing {@link java.lang.reflect.AnnotatedElement}. */ public final class AnnotationUtil { @@ -80,15 +77,38 @@ static class Lazy { @Platforms(Platform.HOSTED_ONLY.class) // private static Boolean instanceIsSingleton; + /** + * The hosted image builder creates the {@link AnnotationExtractor} before publishing it + * globally. Registering it here avoids transient fallback to {@link Lazy} in that startup + * window. + */ + @Platforms(Platform.HOSTED_ONLY.class) // + private static AnnotatedObjectAccess hostedAnnotationExtractor; + + /* + * These accesses do not need synchronization: the hosted extractor is installed during the + * single-threaded image-builder bootstrap, and the fallback path only publishes immutable + * singletons while rejecting any attempt to mix the hosted and lazy variants in one VM. + */ + @Platforms(Platform.HOSTED_ONLY.class) + public static void installHostedAnnotationExtractor(AnnotatedObjectAccess extractor) { + Objects.requireNonNull(extractor); + if (instanceIsSingleton == null) { + instanceIsSingleton = true; + } else if (!instanceIsSingleton) { + throw new GraalError(Lazy.initLocation, "Cannot use image singleton AnnotatedObjectAccess after Lazy.instance initialized"); + } + GraalError.guarantee(hostedAnnotationExtractor == null || hostedAnnotationExtractor == extractor, + "Conflicting hosted AnnotatedObjectAccess instances"); + hostedAnnotationExtractor = extractor; + } + @Platforms(Platform.HOSTED_ONLY.class) private static AnnotatedObjectAccess instance() { - if (ImageSingletonsSupport.isInstalled() && ImageSingletons.contains(AnnotationExtractor.class)) { - if (instanceIsSingleton == null) { - instanceIsSingleton = true; - } else if (!instanceIsSingleton) { - throw new GraalError(Lazy.initLocation, "Cannot use image singleton AnnotatedObjectAccess after Lazy.instance initialized"); - } - return (AnnotatedObjectAccess) ImageSingletons.lookup(AnnotationExtractor.class); + if (hostedAnnotationExtractor != null) { + GraalError.guarantee(instanceIsSingleton == null || instanceIsSingleton, "Cannot use image singleton AnnotatedObjectAccess and Lazy.instance in one process"); + instanceIsSingleton = true; + return hostedAnnotationExtractor; } // Fall back to singleton when no AnnotationExtractor singleton is available (e.g., // running `mx unittest com.oracle.graal.pointsto.standalone.test`).