From 3cce525e1f75f28767a819c5e59a80d6af58e62b Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 14 Oct 2025 15:51:23 +0200 Subject: [PATCH 1/2] replaced uses of AnnotationAccess with AnnotationUtil --- .../core/test/CheckGraalInvariants.java | 11 +- .../annotation/AnnotationValueParser.java | 18 +- .../annotation/AnnotationValueType.java | 23 ++ substratevm/mx.substratevm/suite.py | 7 + .../graal/pointsto/PointsToAnalysis.java | 7 +- .../pointsto/flow/MethodTypeFlowBuilder.java | 5 +- .../graal/pointsto/meta/AnalysisElement.java | 7 +- .../graal/pointsto/meta/AnalysisField.java | 3 +- .../pointsto/results/TypeFlowSimplifier.java | 4 +- .../DirectMethodProcessingHandler.java | 5 +- .../SimpleInMemoryMethodSummaryProvider.java | 4 +- .../.checkstyle_checks.xml | 2 +- .../com/oracle/svm/core/Uninterruptible.java | 49 ++-- .../oracle/svm/core/config/ObjectLayout.java | 4 +- .../graal/code/StubCallingConvention.java | 6 +- .../core/graal/meta/DynamicHubOffsets.java | 4 +- .../graal/meta/SubstrateReplacements.java | 10 +- .../SubstrateSafepointInsertionPhase.java | 14 +- .../core/graal/word/SubstrateWordTypes.java | 6 +- .../com/oracle/svm/core/hub/DynamicHub.java | 4 +- .../svm/core/jdk/LambdaFormHiddenMethod.java | 9 - .../oracle/svm/core/jdk/StackTraceUtils.java | 12 +- .../svm/core/snippets/SnippetRuntime.java | 3 +- .../svm/graal/meta/SubstrateMethod.java | 7 +- .../svm/hosted/foreign/DowncallStub.java | 14 +- .../foreign/ForeignFunctionsFeature.java | 6 +- .../oracle/svm/hosted/foreign/UpcallStub.java | 19 +- .../com/oracle/svm/hosted/FeatureImpl.java | 6 +- .../svm/hosted/HostedConfiguration.java | 3 +- .../hosted/NativeImageClassLoaderSupport.java | 3 +- .../svm/hosted/NativeImageGenerator.java | 7 +- .../src/com/oracle/svm/hosted/SVMHost.java | 46 ++-- .../oracle/svm/hosted/SharedArenaSupport.java | 6 +- .../ameta/AnalysisConstantFieldProvider.java | 4 +- .../ameta/FieldValueInterceptionSupport.java | 15 +- .../svm/hosted/analysis/CallChecker.java | 8 +- .../hosted/annotation/AnnotationWrapper.java | 11 + .../annotation/CustomSubstitutionType.java | 13 +- .../SubstrateAnnotationExtractor.java | 46 +++- .../hosted/c/CConstantValueSupportImpl.java | 3 +- .../oracle/svm/hosted/c/NativeLibraries.java | 17 +- .../hosted/c/codegen/CSourceCodeWriter.java | 3 +- .../svm/hosted/c/info/InfoTreeBuilder.java | 19 +- .../oracle/svm/hosted/c/info/StructInfo.java | 6 +- .../c/query/RawStructureLayoutPlanner.java | 3 +- .../c/query/SizeAndSignednessVerifier.java | 10 +- .../hosted/cenum/CEnumCallWrapperMethod.java | 21 +- ...CEnumCallWrapperSubstitutionProcessor.java | 6 +- .../SimulateClassInitializerPolicy.java | 7 +- .../code/CEntryPointCallStubMethod.java | 5 +- .../svm/hosted/code/CEntryPointData.java | 3 +- .../code/CEntryPointJavaCallStubMethod.java | 3 +- .../code/CEntryPointLiteralFeature.java | 3 +- .../hosted/code/CFunctionCallStubMethod.java | 3 +- .../svm/hosted/code/CFunctionLinkages.java | 11 +- .../code/CFunctionPointerCallStubMethod.java | 3 +- .../code/CFunctionSubstitutionProcessor.java | 10 +- .../oracle/svm/hosted/code/CompileQueue.java | 19 +- .../svm/hosted/code/DeoptimizationUtils.java | 5 +- .../hosted/code/EntryPointCallStubMethod.java | 15 +- .../oracle/svm/hosted/code/FactoryMethod.java | 12 +- .../NativeMethodSubstitutionProcessor.java | 8 +- .../code/RestrictHeapAccessCalleesImpl.java | 11 +- .../UninterruptibleAnnotationChecker.java | 18 +- .../hosted/config/HybridLayoutSupport.java | 5 +- .../StrictDynamicAccessInferenceFeature.java | 13 +- .../heap/PodFactorySubstitutionMethod.java | 9 +- .../oracle/svm/hosted/image/NativeImage.java | 5 +- .../image/NativeImageDebugInfoProvider.java | 5 +- .../LayeredFieldValueTransformerSupport.java | 5 +- .../imagelayer/LoadImageSingletonFeature.java | 4 +- .../imagelayer/SVMImageLayerLoader.java | 6 +- .../imagelayer/SVMImageLayerWriter.java | 4 +- .../oracle/svm/hosted/jvmti/JvmtiFeature.java | 3 +- .../hosted/lambda/LambdaSubstitutionType.java | 4 +- .../oracle/svm/hosted/meta/HostedElement.java | 8 +- .../oracle/svm/hosted/meta/HostedField.java | 2 +- .../oracle/svm/hosted/meta/HostedMethod.java | 11 +- .../oracle/svm/hosted/meta/HostedType.java | 2 +- .../meta/SharedConstantFieldProvider.java | 3 +- .../svm/hosted/meta/UniverseBuilder.java | 11 +- .../phases/CInterfaceInvocationPlugin.java | 27 ++- .../phases/ImplicitAssertionsPhase.java | 13 +- .../phases/InjectedAccessorsPlugin.java | 3 +- .../InlineBeforeAnalysisPolicyUtils.java | 13 +- .../phases/SharedGraphBuilderPhase.java | 11 +- .../pltgot/HostedPLTGOTConfiguration.java | 30 +-- .../SubstrateGraphBuilderPlugins.java | 6 +- .../svm/hosted/substitute/AnnotatedField.java | 6 +- .../hosted/substitute/AnnotatedMethod.java | 7 +- .../AnnotationSubstitutionProcessor.java | 9 +- .../substitute/DeletedFieldsPlugin.java | 8 +- .../svm/hosted/substitute/DeletedMethod.java | 4 +- .../SubstitutionReflectivityFilter.java | 11 +- .../HostedTruffleConstantFieldProvider.java | 5 +- .../svm/truffle/TruffleBaseFeature.java | 7 +- .../oracle/svm/truffle/TruffleFeature.java | 17 +- .../com/oracle/svm/util/AnnotationUtil.java | 221 ++++++++++++++++++ web-image/mx.web-image/suite.py | 9 +- .../svm/hosted/webimage/WebImageFeature.java | 6 +- .../webimage/codegen/JSBodyFeature.java | 4 +- .../webimage/codegen/JSCodeGenTool.java | 4 +- .../webimage/codegen/WebImageJSCodeGen.java | 8 +- .../webimage/codegen/oop/ClassLowerer.java | 7 +- .../codegen/oop/ClassWithMirrorLowerer.java | 15 +- .../svm/hosted/webimage/js/JSStubMethod.java | 8 +- .../webimage/js/JSSubstitutionProcessor.java | 4 +- .../phases/WebImageHostedGraphKit.java | 4 +- .../hosted/webimage/util/AnnotationUtil.java | 59 ----- .../wasm/codegen/WebImageWasmCodeGen.java | 7 +- .../phases/StackPointerVerificationPhase.java | 5 +- .../webimage/thirdparty/JSBodyStubMethod.java | 3 +- .../thirdparty/JavaScriptBodyFeature.java | 16 +- 113 files changed, 758 insertions(+), 554 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java delete mode 100644 web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util/AnnotationUtil.java 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 6013f06049d2..7eef3b5557f1 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 @@ -215,13 +215,6 @@ public boolean shouldVerifyFoldableMethods() { return true; } - /** - * Determines if {@link VerifyAnnotatedElementUsage} is to be checked. - */ - public boolean shouldVerifyAnnotatedElementUsages() { - return true; - } - public void verifyCurrentTimeMillis(MetaAccessProvider meta, MethodCallTargetNode t, ResolvedJavaType declaringClass) { final ResolvedJavaType services = meta.lookupJavaType(GraalServices.class); if (!declaringClass.equals(services)) { @@ -385,6 +378,7 @@ public static void runTest(InvariantsTool tool) { verifiers.add(new VerifyLoopInfo()); verifiers.add(new VerifyGuardsStageUsages()); verifiers.add(new VerifyAArch64RegisterUsages()); + verifiers.add(new VerifyAnnotatedElementUsage()); VerifyAssertionUsage assertionUsages = null; boolean checkAssertions = tool.checkAssertions(); @@ -403,9 +397,6 @@ public static void runTest(InvariantsTool tool) { if (tool.shouldVerifyFoldableMethods()) { verifiers.add(foldableMethodsVerifier); } - if (tool.shouldVerifyAnnotatedElementUsages()) { - verifiers.add(new VerifyAnnotatedElementUsage()); - } verifiers.add(new VerifyCurrentTimeMillisUsage(tool)); diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueParser.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueParser.java index 980ea82e0a10..dd60f528c736 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueParser.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueParser.java @@ -151,7 +151,7 @@ public static Object parseMemberValue(ResolvedJavaType memberType, result = new ElementTypeMismatch(memberType.toJavaName()); } else if (tag != '[' && !(result instanceof ErrorElement) && - !matchesMemberType(result, memberType)) { + !AnnotationValueType.matchesElementType(result, memberType)) { if (result instanceof AnnotationValue) { result = new ElementTypeMismatch(result.toString()); } else { @@ -161,22 +161,6 @@ public static Object parseMemberValue(ResolvedJavaType memberType, return result; } - private static boolean matchesMemberType(Object result, ResolvedJavaType memberType) { - if (result instanceof AnnotationValue av) { - return memberType.equals(av.getAnnotationType()); - } - if (result instanceof ResolvedJavaType) { - return memberType.getName().equals("Ljava/lang/Class;"); - } - if (result instanceof EnumElement ee) { - return ee.enumType.equals(memberType); - } - if (memberType.isPrimitive()) { - return result.getClass() == memberType.getJavaKind().toBoxedJavaClass(); - } - return memberType.toJavaName().equals(result.getClass().getName()); - } - private static Object parsePrimitiveConst(char tag, ByteBuffer buf, ConstantPool constPool) { int constIndex = buf.getShort() & 0xFFFF; diff --git a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueType.java b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueType.java index 951419b91d14..d6ccc3b6c0e8 100644 --- a/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueType.java +++ b/compiler/src/jdk.graal.compiler/src/jdk/graal/compiler/annotation/AnnotationValueType.java @@ -77,6 +77,29 @@ private AnnotationValueType(ResolvedJavaType annotationClass) { } } + /** + * Determines if the type of {@code elementValue} matches {@code elementType}. + * + * @param elementValue a value of a type returned by {@link AnnotationValue#get} + * @param elementType an annotation element type (i.e. the return type of an annotation + * interface method) + */ + public static boolean matchesElementType(Object elementValue, ResolvedJavaType elementType) { + if (elementValue instanceof AnnotationValue av) { + return elementType.equals(av.getAnnotationType()); + } + if (elementValue instanceof ResolvedJavaType) { + return elementType.getName().equals("Ljava/lang/Class;"); + } + if (elementValue instanceof EnumElement ee) { + return ee.enumType.equals(elementType); + } + if (elementType.isPrimitive()) { + return elementValue.getClass() == elementType.getJavaKind().toBoxedJavaClass(); + } + return elementType.toJavaName().equals(elementValue.getClass().getName()); + } + /** * Gets the element types for the annotation represented by this object. * diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index c5c8ff7e2d03..96ceeb3e64bf 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -231,6 +231,7 @@ "java.base" : ["jdk.internal.module"], "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", "jdk.vm.ci.code", "jdk.vm.ci.runtime" ] @@ -242,6 +243,10 @@ "checkstyle": "com.oracle.svm.core", "workingSets": "SVM", "jacoco" : "include", + + # Direct reference to jdk.vm.ci.meta.annotation.Annotated + # causes spotbugs analysis to fail with "missing class" error. + "spotbugs": "false", }, "com.oracle.svm.common": { @@ -378,6 +383,7 @@ ], "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", "jdk.vm.ci.code", "jdk.vm.ci.aarch64", "jdk.vm.ci.amd64", @@ -1373,6 +1379,7 @@ "jdk.internal.vm.ci": [ "jdk.vm.ci.aarch64", "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", "jdk.vm.ci.code", "jdk.vm.ci.code.stack" ] diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java index 733c830e00bc..1dc9d9511bee 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/PointsToAnalysis.java @@ -42,8 +42,6 @@ import java.util.function.Consumer; import java.util.stream.StreamSupport; -import org.graalvm.nativeimage.AnnotationAccess; - import com.oracle.graal.pointsto.api.HostVM; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.constraints.UnsupportedFeatures; @@ -77,6 +75,7 @@ import com.oracle.graal.pointsto.util.Timer.StopTimer; import com.oracle.graal.pointsto.util.TimerCollection; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ClassUtil; import jdk.graal.compiler.api.replacements.Fold; @@ -166,7 +165,7 @@ public PointsToAnalysis(OptionValues options, AnalysisUniverse universe, HostVM * this type cannot be extended outside the observable universe. *
  • In closed type world all types are considered closed.
  • * - * + * * This method is conservative, it returns false in cases where we are not sure, and further * refining when a type is closed will improve analysis. For example GR-59311 will also define * when a sealed type can be treated as a closed type. @@ -394,7 +393,7 @@ public AnalysisMethod addRootMethod(AnalysisMethod aMethod, boolean invokeSpecia assert !universe.sealed() : "Cannot register root methods after analysis universe is sealed."; validateRootMethodRegistration(aMethod, invokeSpecial); AnalysisError.guarantee(aMethod.isOriginalMethod()); - AnalysisError.guarantee(!AnnotationAccess.isAnnotationPresent(aMethod, Fold.class), "@Fold annotated method cannot be a root method."); + AnalysisError.guarantee(!AnnotationUtil.isAnnotationPresent(aMethod, Fold.class), "@Fold annotated method cannot be a root method."); boolean isStatic = aMethod.isStatic(); int paramCount = aMethod.getSignature().getParameterCount(!isStatic); PointsToAnalysisMethod originalPTAMethod = assertPointsToAnalysisMethod(aMethod); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java index bfd551c454a2..7a32717faf11 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/flow/MethodTypeFlowBuilder.java @@ -34,8 +34,6 @@ import java.util.Map; import java.util.Optional; -import org.graalvm.nativeimage.AnnotationAccess; - import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.ObjectScanner.EmbeddedRootScan; import com.oracle.graal.pointsto.PointsToAnalysis; @@ -62,6 +60,7 @@ import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.core.common.SuppressFBWarnings; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; @@ -509,7 +508,7 @@ private static void registerForeignCall(AbstractAnalysisEngine bb, ForeignCallsP } private boolean handleNodeIntrinsic() { - if (AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class)) { + if (AnnotationUtil.isAnnotationPresent(method, NodeIntrinsic.class)) { graph.getDebug().log("apply MethodTypeFlow on node intrinsic %s", method); AnalysisType returnType = method.getSignature().getReturnType(); if (bb.isSupportedJavaKind(returnType.getJavaKind())) { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java index 9566599ad60b..a1acc1e60a80 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisElement.java @@ -48,6 +48,7 @@ import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.AtomicUtils; import com.oracle.graal.pointsto.util.ConcurrentLightHashSet; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.code.BytecodePosition; @@ -86,17 +87,17 @@ public AnnotationsInfo getTypeAnnotationInfo() { @Override public final boolean isAnnotationPresent(Class annotationClass) { - return getUniverse().getAnnotationExtractor().hasAnnotation(getWrapped(), annotationClass); + return AnnotationUtil.isAnnotationPresent((Annotated) getWrapped(), annotationClass); } @Override public final T getAnnotation(Class annotationClass) { - return getUniverse().getAnnotationExtractor().extractAnnotation(getWrapped(), annotationClass, false); + return AnnotationUtil.getAnnotation((Annotated) getWrapped(), annotationClass); } @Override public final T getDeclaredAnnotation(Class annotationClass) { - return getUniverse().getAnnotationExtractor().extractAnnotation(getWrapped(), annotationClass, true); + throw GraalError.shouldNotReachHere("The getDeclaredAnnotation method is not supported"); } @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java index 6bce6ad1bdf3..60061ad0b470 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisField.java @@ -36,6 +36,7 @@ import com.oracle.graal.pointsto.util.AnalysisFuture; import com.oracle.graal.pointsto.util.AtomicUtils; import com.oracle.svm.common.meta.GuaranteeFolded; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.util.OriginalFieldProvider; @@ -257,7 +258,7 @@ public void injectDeclaredType() { } public boolean isGuaranteeFolded() { - return getAnnotation(GuaranteeFolded.class) != null; + return AnnotationUtil.getAnnotation(this, GuaranteeFolded.class) != null; } public void checkGuaranteeFolded() { diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/TypeFlowSimplifier.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/TypeFlowSimplifier.java index 1e4dad3f2b38..7067a78a710a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/TypeFlowSimplifier.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/results/TypeFlowSimplifier.java @@ -29,7 +29,6 @@ import java.util.List; import org.graalvm.collections.EconomicSet; -import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.PointsToAnalysis; import com.oracle.graal.pointsto.flow.InvokeTypeFlow; @@ -45,6 +44,7 @@ import com.oracle.graal.pointsto.typestate.TypeState; import com.oracle.graal.pointsto.util.AnalysisError; import com.oracle.svm.core.annotate.Delete; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ImageBuildStatistics; import jdk.graal.compiler.core.common.type.IntegerStamp; @@ -376,7 +376,7 @@ private void handleInvoke(Invoke invoke, SimplifierTool tool) { AnalysisMethod singleCallee = callees.iterator().next(); assert targetMethod.equals(singleCallee) : "Direct invoke target mismatch: " + targetMethod + " != " + singleCallee + ". Called from " + graph.method().format("%H.%n"); } - } else if (AnnotationAccess.isAnnotationPresent(targetMethod, Delete.class)) { + } else if (AnnotationUtil.isAnnotationPresent(targetMethod, Delete.class)) { /* We de-virtualize invokes to deleted methods since the callee must be unique. */ AnalysisError.guarantee(callees.size() == 1, "@Delete methods should have a single callee."); AnalysisMethod singleCallee = callees.iterator().next(); diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java index e356c9269c30..d3c8dfff8cb1 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/DirectMethodProcessingHandler.java @@ -26,12 +26,11 @@ import java.lang.reflect.Modifier; -import org.graalvm.nativeimage.AnnotationAccess; - import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisType; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.graph.Node; import jdk.graal.compiler.nodes.CallTargetNode; @@ -128,7 +127,7 @@ private static void analyzeStructuredGraph(ReachabilityAnalysisEngine bb, Reacha private static void processInvoke(ReachabilityAnalysisEngine bb, ReachabilityAnalysisMethod method, ReachabilityAnalysisMethod targetMethod, CallTargetNode.InvokeKind kind, ValueNodeInterface node) { - if (targetMethod == null || AnnotationAccess.isAnnotationPresent(targetMethod, Node.NodeIntrinsic.class)) { + if (targetMethod == null || AnnotationUtil.isAnnotationPresent(targetMethod, Node.NodeIntrinsic.class)) { return; } BytecodePosition reason = AbstractAnalysisEngine.sourcePosition(node.asNode()); diff --git a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java index 68aaa5a8547f..ec6126cb4367 100644 --- a/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java +++ b/substratevm/src/com.oracle.graal.reachability/src/com/oracle/graal/reachability/SimpleInMemoryMethodSummaryProvider.java @@ -28,13 +28,13 @@ import java.util.Optional; import org.graalvm.collections.EconomicSet; -import org.graalvm.nativeimage.AnnotationAccess; import com.oracle.graal.pointsto.AbstractAnalysisEngine; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.svm.common.meta.MultiMethod; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor; import jdk.graal.compiler.core.common.spi.ForeignCallSignature; @@ -148,7 +148,7 @@ private static MethodSummary createSummaryFromGraph(ReachabilityAnalysisEngine b Invoke node = (Invoke) n; CallTargetNode.InvokeKind kind = node.getInvokeKind(); ReachabilityAnalysisMethod targetMethod = (ReachabilityAnalysisMethod) node.getTargetMethod(); - if (targetMethod == null || AnnotationAccess.isAnnotationPresent(targetMethod, Node.NodeIntrinsic.class)) { + if (targetMethod == null || AnnotationUtil.isAnnotationPresent(targetMethod, Node.NodeIntrinsic.class)) { continue; } if (method != null) { diff --git a/substratevm/src/com.oracle.svm.core/.checkstyle_checks.xml b/substratevm/src/com.oracle.svm.core/.checkstyle_checks.xml index 848c872c9c82..1bfe3dddc821 100644 --- a/substratevm/src/com.oracle.svm.core/.checkstyle_checks.xml +++ b/substratevm/src/com.oracle.svm.core/.checkstyle_checks.xml @@ -13,7 +13,7 @@ - + diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Uninterruptible.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Uninterruptible.java index fc641e957551..831a6c448077 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Uninterruptible.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/Uninterruptible.java @@ -28,11 +28,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Executable; -import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunction; @@ -40,8 +37,7 @@ import org.graalvm.word.WordBase; import com.oracle.svm.core.snippets.KnownIntrinsics; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.ReflectionUtil; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.api.replacements.Fold; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -128,18 +124,11 @@ boolean mayBeInlined() default false; class Utils { - private static final int SYNTHETIC = 0x00001000; /** - * Defines the {@link Uninterruptible} annotation returned for C function calls with - * NO_TRANSITION. + * The {@link Uninterruptible} annotation returned for C function calls with NO_TRANSITION. */ - @Uninterruptible(reason = "@CFunction / @InvokeCFunctionPointer with Transition.NO_TRANSITION") - @SuppressWarnings("unused") - private static void noTransitionHolder() { - } - - private static final Uninterruptible NO_TRANSITION = Objects.requireNonNull(getAnnotation(ReflectionUtil.lookupMethod(Utils.class, "noTransitionHolder"))); + private static final AtomicReference NO_TRANSITION = new AtomicReference<>(); /** * Returns the {@link Uninterruptible} annotation of the method. Note that there are certain @@ -148,16 +137,8 @@ private static void noTransitionHolder() { * the method must not be uninterruptible. So always use this method and never look up the * annotation directly on a method. */ - public static Uninterruptible getAnnotation(AnnotatedElement method) { - boolean isSynthetic; - if (method instanceof Executable) { - isSynthetic = (((Executable) method).getModifiers() & SYNTHETIC) != 0; - } else if (method instanceof ResolvedJavaMethod) { - isSynthetic = ((ResolvedJavaMethod) method).isSynthetic(); - } else { - throw VMError.shouldNotReachHere("Unexpected method implementation class: " + method.getClass().getTypeName()); - } - if (isSynthetic) { + public static Uninterruptible getAnnotation(ResolvedJavaMethod method) { + if (method.isSynthetic()) { /* * Java compilers differ how annotations are inherited for synthetic methods: javac * annotates synthetic bridge methods for covariant return types, but ECJ does not. @@ -167,14 +148,14 @@ public static Uninterruptible getAnnotation(AnnotatedElement method) { return null; } - Uninterruptible annotation = AnnotationAccess.getAnnotation(method, Uninterruptible.class); + Uninterruptible annotation = AnnotationUtil.getAnnotation(method, Uninterruptible.class); if (annotation != null) { /* Explicit annotated method. */ return annotation; } - CFunction cFunctionAnnotation = AnnotationAccess.getAnnotation(method, CFunction.class); - InvokeCFunctionPointer cFunctionPointerAnnotation = AnnotationAccess.getAnnotation(method, InvokeCFunctionPointer.class); + CFunction cFunctionAnnotation = AnnotationUtil.getAnnotation(method, CFunction.class); + InvokeCFunctionPointer cFunctionPointerAnnotation = AnnotationUtil.getAnnotation(method, InvokeCFunctionPointer.class); if ((cFunctionAnnotation != null && cFunctionAnnotation.transition() == CFunction.Transition.NO_TRANSITION) || (cFunctionPointerAnnotation != null && cFunctionPointerAnnotation.transition() == CFunction.Transition.NO_TRANSITION)) { /* @@ -182,7 +163,11 @@ public static Uninterruptible getAnnotation(AnnotatedElement method) { * treated as uninterruptible. This avoids annotating many methods with multiple * annotations. */ - return NO_TRANSITION; + if (NO_TRANSITION.get() == null) { + NO_TRANSITION.compareAndExchange(null, AnnotationUtil.newAnnotation(Uninterruptible.class, + "reason", "@CFunction / @InvokeCFunctionPointer with Transition.NO_TRANSITION")); + } + return NO_TRANSITION.get(); } /* No relevant annotation found, so not uninterruptible. */ @@ -194,12 +179,12 @@ public static Uninterruptible getAnnotation(AnnotatedElement method) { * the method or implicitly due to other annotations. */ @Platforms(Platform.HOSTED_ONLY.class) - public static boolean isUninterruptible(AnnotatedElement method) { + public static boolean isUninterruptible(ResolvedJavaMethod method) { return getAnnotation(method) != null; } @Platforms(Platform.HOSTED_ONLY.class) - public static boolean inliningAllowed(AnnotatedElement caller, AnnotatedElement callee) { + public static boolean inliningAllowed(ResolvedJavaMethod caller, ResolvedJavaMethod callee) { boolean callerUninterruptible = isUninterruptible(caller); boolean calleeUninterruptible = isUninterruptible(callee); @@ -220,7 +205,7 @@ public static boolean inliningAllowed(AnnotatedElement caller, AnnotatedElement if (!calleeUninterruptible) { return true; } - Uninterruptible calleeUninterruptibleAnnotation = AnnotationAccess.getAnnotation(callee, Uninterruptible.class); + Uninterruptible calleeUninterruptibleAnnotation = AnnotationUtil.getAnnotation(callee, Uninterruptible.class); if (calleeUninterruptibleAnnotation != null && calleeUninterruptibleAnnotation.mayBeInlined()) { return true; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java index 8a10cb42703e..5b9b83b2e5d8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/config/ObjectLayout.java @@ -29,7 +29,6 @@ import java.util.List; import java.util.function.Predicate; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.c.constant.CEnum; import org.graalvm.word.WordBase; @@ -47,6 +46,7 @@ import com.oracle.svm.core.traits.SingletonTraitKind; import com.oracle.svm.core.traits.SingletonTraits; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.api.directives.GraalDirectives; import jdk.graal.compiler.api.replacements.Fold; @@ -316,7 +316,7 @@ public static JavaKind getCallSignatureKind(boolean isEntryPoint, JavaType type, if (metaAccess != null && metaAccess.lookupJavaType(WordBase.class).isAssignableFrom(resolvedJavaType)) { return target.wordJavaKind; } - if (isEntryPoint && AnnotationAccess.isAnnotationPresent(resolvedJavaType, CEnum.class)) { + if (isEntryPoint && AnnotationUtil.isAnnotationPresent(resolvedJavaType, CEnum.class)) { return JavaKind.Int; } return type.getJavaKind(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/StubCallingConvention.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/StubCallingConvention.java index fae450689a06..ce76231c5ae1 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/StubCallingConvention.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/StubCallingConvention.java @@ -29,13 +29,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import com.oracle.svm.core.CalleeSavedRegisters; import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.util.AnnotationUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -55,11 +55,11 @@ class Utils { public static boolean hasStubCallingConvention(ResolvedJavaMethod method) { boolean result = false; if (CalleeSavedRegisters.supportedByPlatform()) { - SubstrateForeignCallTarget foreignCallTargetAnnotation = AnnotationAccess.getAnnotation(method, SubstrateForeignCallTarget.class); + SubstrateForeignCallTarget foreignCallTargetAnnotation = AnnotationUtil.getAnnotation(method, SubstrateForeignCallTarget.class); if (foreignCallTargetAnnotation != null && foreignCallTargetAnnotation.stubCallingConvention()) { result = true; } else { - result = AnnotationAccess.isAnnotationPresent(method, StubCallingConvention.class); + result = AnnotationUtil.isAnnotationPresent(method, StubCallingConvention.class); } } if (result && !method.isStatic()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java index 1486ebe0193f..1e225e070c56 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/DynamicHubOffsets.java @@ -27,7 +27,6 @@ import java.lang.reflect.Field; import java.util.Arrays; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; @@ -37,6 +36,7 @@ import com.oracle.svm.core.heap.UnknownPrimitiveField; import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.api.replacements.Fold; @@ -115,7 +115,7 @@ public void initializeOffsets(MetaAccessProvider metaAccess) { continue; } - if (AnnotationAccess.isAnnotationPresent(field, InjectAccessors.class)) { + if (AnnotationUtil.isAnnotationPresent(field, InjectAccessors.class)) { continue; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java index 9de9e3447a7d..bb4225fcb013 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java @@ -40,9 +40,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import jdk.graal.compiler.nodes.NodeClassMap; import org.graalvm.collections.EconomicSet; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.hosted.Feature.BeforeHeapLayoutAccess; @@ -53,6 +51,7 @@ import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.api.replacements.Snippet; import jdk.graal.compiler.bytecode.BytecodeProvider; @@ -66,6 +65,7 @@ import jdk.graal.compiler.nodes.EncodedGraph; import jdk.graal.compiler.nodes.GraphEncoder; import jdk.graal.compiler.nodes.Invoke; +import jdk.graal.compiler.nodes.NodeClassMap; import jdk.graal.compiler.nodes.StructuredGraph; import jdk.graal.compiler.nodes.StructuredGraph.AllowAssumptions; import jdk.graal.compiler.nodes.ValueNode; @@ -142,7 +142,7 @@ public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod m } @Platforms(Platform.HOSTED_ONLY.class)// - private Builder builder; + private final Builder builder; private InvocationPlugins snippetInvocationPlugins; private byte[] snippetEncoding; @@ -234,7 +234,7 @@ public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, bool PEGraphDecoder graphDecoder = new PEGraphDecoder(ConfigurationValues.getTarget().arch, result, providers, null, snippetInvocationPlugins, new InlineInvokePlugin[0], parameterPlugin, null, null, null, new ConcurrentHashMap<>(), new ConcurrentHashMap<>(), true, false) { - private IntrinsicContext intrinsic = new IntrinsicContext(method, null, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING, false); + private final IntrinsicContext intrinsic = new IntrinsicContext(method, null, providers.getReplacements().getDefaultReplacementBytecodeProvider(), INLINE_AFTER_PARSING, false); @Override protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod lookupMethod, BytecodeProvider intrinsicBytecodeProvider) { @@ -270,7 +270,7 @@ protected Object readObject(MethodScope methodScope) { @Platforms(Platform.HOSTED_ONLY.class) @Override public void registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean trackNodeSourcePosition, OptionValues options) { - assert AnnotationAccess.isAnnotationPresent(method, Snippet.class) : "Snippet must be annotated with @" + Snippet.class.getSimpleName() + " " + method; + assert AnnotationUtil.isAnnotationPresent(method, Snippet.class) : "Snippet must be annotated with @" + Snippet.class.getSimpleName() + " " + method; assert method.hasBytecodes() : "Snippet must not be abstract or native"; assert builder.graphs.get(method) == null : "snippet registered twice: " + method.getName(); assert builder.registered.add(method) : "snippet registered twice: " + method.getName(); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/SubstrateSafepointInsertionPhase.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/SubstrateSafepointInsertionPhase.java index 1a6e0b22378a..f7e6767be8ed 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/SubstrateSafepointInsertionPhase.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/phases/SubstrateSafepointInsertionPhase.java @@ -24,12 +24,6 @@ */ package com.oracle.svm.core.graal.phases; -import jdk.graal.compiler.nodes.ReturnNode; -import jdk.graal.compiler.nodes.SafepointNode; -import jdk.graal.compiler.nodes.StructuredGraph; -import jdk.graal.compiler.phases.common.LoopSafepointInsertionPhase; -import jdk.graal.compiler.phases.tiers.MidTierContext; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunction; @@ -38,7 +32,13 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.meta.SharedMethod; +import com.oracle.svm.util.AnnotationUtil; +import jdk.graal.compiler.nodes.ReturnNode; +import jdk.graal.compiler.nodes.SafepointNode; +import jdk.graal.compiler.nodes.StructuredGraph; +import jdk.graal.compiler.phases.common.LoopSafepointInsertionPhase; +import jdk.graal.compiler.phases.tiers.MidTierContext; import jdk.vm.ci.meta.ResolvedJavaMethod; /** @@ -52,7 +52,7 @@ public static boolean needSafepointCheck(ResolvedJavaMethod method) { /* Uninterruptible methods must not have a safepoint inserted. */ return false; } - if (AnnotationAccess.isAnnotationPresent(method, CFunction.class) || AnnotationAccess.isAnnotationPresent(method, InvokeCFunctionPointer.class)) { + if (AnnotationUtil.isAnnotationPresent(method, CFunction.class) || AnnotationUtil.isAnnotationPresent(method, InvokeCFunctionPointer.class)) { /* * Methods transferring from Java to C have an implicit safepoint check as part of the * transition from C back to Java. So no explicit end-of-method safepoint check needs to diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordTypes.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordTypes.java index 709dbddc8023..9a9b36380b42 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordTypes.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/word/SubstrateWordTypes.java @@ -24,12 +24,12 @@ */ package com.oracle.svm.core.graal.word; -import jdk.graal.compiler.word.WordTypes; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.util.AnnotationUtil; +import jdk.graal.compiler.word.WordTypes; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -42,7 +42,7 @@ public SubstrateWordTypes(MetaAccessProvider metaAccess, JavaKind wordKind) { @Override public boolean isWordOperation(ResolvedJavaMethod targetMethod) { - if (AnnotationAccess.isAnnotationPresent(targetMethod, InvokeCFunctionPointer.class)) { + if (AnnotationUtil.isAnnotationPresent(targetMethod, InvokeCFunctionPointer.class)) { return false; // handled by CInterfaceInvocationPlugin } return super.isWordOperation(targetMethod); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java index dde80eed9806..f2aeb8bd652a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/DynamicHub.java @@ -140,6 +140,8 @@ import com.oracle.svm.core.util.BasedOnJDKFile; import com.oracle.svm.core.util.LazyFinalReference; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotationUtil; +import com.oracle.svm.util.GraalAccess; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; @@ -1915,7 +1917,7 @@ public String getPackageName() { private boolean isHybrid() { if (SubstrateUtil.HOSTED) { - return AnnotationAccess.isAnnotationPresent(hostedJavaClass, Hybrid.class); + return AnnotationUtil.isAnnotationPresent(GraalAccess.lookupType(hostedJavaClass), Hybrid.class); } else { return LayoutEncoding.isHybrid(getLayoutEncoding()); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LambdaFormHiddenMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LambdaFormHiddenMethod.java index a0f0ffb585ae..4d04f4ba50e7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LambdaFormHiddenMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/LambdaFormHiddenMethod.java @@ -29,8 +29,6 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.graalvm.nativeimage.AnnotationAccess; - /** * Annotation for types whose methods are synthetic methods for lambda invocations, and ignored for * certain user-visible stack traces such as exception stack traces. All methods in the annotated @@ -40,11 +38,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface LambdaFormHiddenMethod { - - @LambdaFormHiddenMethod() - class Holder { - - /** Instance of the annotation, useful when the annotation is manually injected. */ - public static final LambdaFormHiddenMethod INSTANCE = AnnotationAccess.getAnnotation(Holder.class, LambdaFormHiddenMethod.class); - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java index b13f678a9fd0..7176acabb2a0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java @@ -33,7 +33,6 @@ import java.util.ArrayList; import java.util.Arrays; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.IsolateThread; import org.graalvm.nativeimage.c.function.CodePointer; import org.graalvm.word.Pointer; @@ -63,6 +62,7 @@ import com.oracle.svm.core.thread.Target_jdk_internal_vm_Continuation; import com.oracle.svm.core.thread.VMOperation; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.word.Word; @@ -230,11 +230,11 @@ public static boolean shouldShowFrame(MetaAccessProvider metaAccess, ResolvedJav } ResolvedJavaType clazz = method.getDeclaringClass(); - if (AnnotationAccess.isAnnotationPresent(clazz, InternalVMMethod.class)) { + if (AnnotationUtil.isAnnotationPresent(clazz, InternalVMMethod.class)) { return false; } - if (!showLambdaFrames && AnnotationAccess.isAnnotationPresent(clazz, LambdaFormHiddenMethod.class)) { + if (!showLambdaFrames && AnnotationUtil.isAnnotationPresent(clazz, LambdaFormHiddenMethod.class)) { return false; } @@ -299,7 +299,7 @@ protected void operate() { * instruction pointer. * *

    Uncompressed References

    - * + * *
      *                      backtrace content      |   Number of Java frames
      *                    ---------------------------------------------------
    @@ -315,7 +315,7 @@ protected void operate() {
      * 
    * *

    Compressed References

    - * + * *
      *                      backtrace content                                   |   Number of Java frames
      *                    --------------------------------------------------------------------------------
    @@ -520,7 +520,7 @@ static void writeSourceReference(long[] backtrace, int pos, int sourceLineNumber
         /**
          * Return the source line number of a source reference entry created by
          * {@link #writeSourceReference}.
    -     * 
    +     *
          * @param backtrace the backtrace array
          * @param pos the start position of the source reference entry
          * @return the source line number
    diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java
    index 0eca9dab356f..c3ff5b7ba63e 100644
    --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java
    +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/SnippetRuntime.java
    @@ -35,6 +35,7 @@
     import com.oracle.svm.core.Uninterruptible;
     import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.GraalAccess;
     
     import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor;
     import jdk.graal.compiler.core.common.spi.ForeignCallDescriptor.CallSideEffect;
    @@ -76,7 +77,7 @@ public static SubstrateForeignCallDescriptor findForeignCall(Class declaringC
             SubstrateForeignCallTarget foreignCallTargetAnnotation = AnnotationAccess.getAnnotation(method, SubstrateForeignCallTarget.class);
             VMError.guarantee(foreignCallTargetAnnotation != null, "Add missing @SubstrateForeignCallTarget to %s.%s", declaringClass.getName(), methodName);
     
    -        boolean isUninterruptible = Uninterruptible.Utils.isUninterruptible(method);
    +        boolean isUninterruptible = Uninterruptible.Utils.isUninterruptible(GraalAccess.lookupMethod(method));
             boolean isFullyUninterruptible = foreignCallTargetAnnotation.fullyUninterruptible();
             return findForeignCall(methodName, method, callSideEffect, isUninterruptible, isFullyUninterruptible, additionalKilledLocations);
         }
    diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java
    index e8a95144ba47..3c5e7a7200ec 100644
    --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java
    +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java
    @@ -55,6 +55,7 @@
     import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
     import com.oracle.svm.core.util.HostedStringDeduplication;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.api.replacements.Snippet;
     import jdk.graal.compiler.core.common.util.TypeConversion;
    @@ -123,7 +124,7 @@ public SubstrateMethod(AnalysisMethod original, ImageCodeInfo codeInfo, HostedSt
             imageCodeInfo = codeInfo;
             encodedLineNumberTable = EncodedLineNumberTable.encode(original.getLineNumberTable());
     
    -        assert original.getAnnotation(CEntryPoint.class) == null : "Can't compile entry point method";
    +        assert AnnotationUtil.getAnnotation(original, CEntryPoint.class) == null : "Can't compile entry point method";
     
             modifiers = original.getModifiers();
             name = stringTable.deduplicate(original.getName(), true);
    @@ -144,8 +145,8 @@ public SubstrateMethod(AnalysisMethod original, ImageCodeInfo codeInfo, HostedSt
                             makeFlag(Uninterruptible.Utils.isUninterruptible(original), FLAG_BIT_UNINTERRUPTIBLE) |
                             makeFlag(SubstrateSafepointInsertionPhase.needSafepointCheck(original), FLAG_BIT_NEEDS_SAFEPOINT_CHECK) |
                             makeFlag(original.isNativeEntryPoint(), FLAG_BIT_ENTRY_POINT) |
    -                        makeFlag(original.isAnnotationPresent(Snippet.class), FLAG_BIT_SNIPPET) |
    -                        makeFlag(original.isAnnotationPresent(SubstrateForeignCallTarget.class), FLAG_BIT_FOREIGN_CALL_TARGET) |
    +                        makeFlag(AnnotationUtil.isAnnotationPresent(original, Snippet.class), FLAG_BIT_SNIPPET) |
    +                        makeFlag(AnnotationUtil.isAnnotationPresent(original, SubstrateForeignCallTarget.class), FLAG_BIT_FOREIGN_CALL_TARGET) |
                             makeFlag(callingConventionKind.ordinal(), FLAG_BIT_CALLING_CONVENTION_KIND, NUM_BITS_CALLING_CONVENTION_KIND) |
                             makeFlag(StubCallingConvention.Utils.hasStubCallingConvention(original), FLAG_BIT_CALLEE_SAVED_REGISTERS);
         }
    diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java
    index 2204d4b2e9e3..6c3a25473076 100644
    --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java
    +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java
    @@ -24,6 +24,8 @@
      */
     package com.oracle.svm.hosted.foreign;
     
    +import static com.oracle.svm.util.AnnotationUtil.newAnnotationValue;
    +
     import java.util.List;
     
     import org.graalvm.nativeimage.c.function.CFunction;
    @@ -42,7 +44,6 @@
     import com.oracle.svm.core.graal.snippets.CFunctionSnippets;
     import com.oracle.svm.core.thread.VMThreads;
     import com.oracle.svm.core.util.BasedOnJDKFile;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
     import com.oracle.svm.hosted.code.NonBytecodeMethod;
     import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
     import com.oracle.svm.util.ReflectionUtil;
    @@ -104,13 +105,10 @@ public static Signature createSignature(MetaAccessProvider metaAccess) {
             this.nep = nep;
         }
     
    -    @Uninterruptible(reason = "See DowncallStub.getInjectedAnnotations.", calleeMustBe = false)
    -    @SuppressWarnings("unused")
    -    private static void uninterruptibleAnnotationForAllowHeapAccessHolder() {
    -    }
    -
    -    private static final List INJECTED_ANNOTATIONS_FOR_ALLOW_HEAP_ACCESS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(
    -                    Uninterruptible.Utils.getAnnotation(ReflectionUtil.lookupMethod(DowncallStub.class, "uninterruptibleAnnotationForAllowHeapAccessHolder")));
    +    private static final List INJECTED_ANNOTATIONS_FOR_ALLOW_HEAP_ACCESS = List.of(
    +                    newAnnotationValue(Uninterruptible.class,
    +                                    "reason", "See DowncallStub.getInjectedAnnotations.",
    +                                    "calleeMustBe", false));
     
         @Override
         public List getInjectedAnnotations() {
    diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java
    index 46120f818d77..1a344a03fb7d 100644
    --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java
    +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/ForeignFunctionsFeature.java
    @@ -48,9 +48,7 @@
     import java.util.function.Supplier;
     import java.util.function.UnaryOperator;
     
    -import com.oracle.svm.core.thread.JavaThreads;
     import org.graalvm.collections.EconomicSet;
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.Platform;
     import org.graalvm.nativeimage.Platforms;
    @@ -96,6 +94,7 @@
     import com.oracle.svm.core.jdk.VectorAPIEnabled;
     import com.oracle.svm.core.meta.MethodPointer;
     import com.oracle.svm.core.nodes.SubstrateMethodCallTargetNode;
    +import com.oracle.svm.core.thread.JavaThreads;
     import com.oracle.svm.core.util.BasedOnJDKFile;
     import com.oracle.svm.core.util.UserError;
     import com.oracle.svm.core.util.VMError;
    @@ -109,6 +108,7 @@
     import com.oracle.svm.hosted.config.ConfigurationParserUtils;
     import com.oracle.svm.hosted.meta.HostedMethod;
     import com.oracle.svm.hosted.meta.HostedType;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.LogUtils;
     import com.oracle.svm.util.ModuleSupport;
     import com.oracle.svm.util.ReflectionUtil;
    @@ -837,7 +837,7 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, Va
                     if (MultiMethod.isOriginalMethod(b.getMethod())) { // not for hosted compilation
                         return false;
                     }
    -                if (!AnnotationAccess.isAnnotationPresent(b.getMethod(), SharedArenaSupport.SCOPED_ANNOTATION)) {
    +                if (!AnnotationUtil.isAnnotationPresent(b.getMethod(), SharedArenaSupport.SCOPED_ANNOTATION)) {
                         return false;
                     }
                     MethodCallTargetNode mt = b.add(new SubstrateMethodCallTargetNode(InvokeKind.Static, checkValidStateRawInRuntimeCompiledCode, args, b.getInvokeReturnStamp(b.getAssumptions())));
    diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
    index 535bd58d5356..da8151a0db10 100644
    --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
    +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/UpcallStub.java
    @@ -25,6 +25,7 @@
     package com.oracle.svm.hosted.foreign;
     
     import static com.oracle.graal.pointsto.infrastructure.ResolvedSignature.fromMethodType;
    +import static com.oracle.svm.util.AnnotationUtil.newAnnotationValue;
     import static jdk.graal.compiler.nodes.extended.BranchProbabilityNode.VERY_FAST_PATH_PROBABILITY;
     
     import java.lang.invoke.MethodHandle;
    @@ -33,7 +34,6 @@
     import java.util.ArrayList;
     import java.util.List;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.word.LocationIdentity;
     
    @@ -63,7 +63,6 @@
     import com.oracle.svm.core.graal.stackvalue.StackValueNode;
     import com.oracle.svm.core.util.BasedOnJDKFile;
     import com.oracle.svm.core.util.VMError;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
     import com.oracle.svm.hosted.code.NonBytecodeMethod;
     import com.oracle.svm.util.ReflectionUtil;
     
    @@ -259,16 +258,12 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
             return kit.finalizeGraph();
         }
     
    -    @Uninterruptible(reason = "Directly accesses registers and IsolateThread might not be correctly set up", calleeMustBe = false)
    -    @ExplicitCallingConvention(SubstrateCallingConventionKind.Custom)
    -    private static void annotationsHolder() {
    -    }
    -
    -    private static final Method ANNOTATIONS_HOLDER = ReflectionUtil.lookupMethod(LowLevelUpcallStub.class, "annotationsHolder");
    -
    -    private static final List INJECTED_ANNOTATIONS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(
    -                    AnnotationAccess.getAnnotation(ANNOTATIONS_HOLDER, ExplicitCallingConvention.class),
    -                    Uninterruptible.Utils.getAnnotation(ANNOTATIONS_HOLDER));
    +    private static final List INJECTED_ANNOTATIONS = List.of(
    +                    newAnnotationValue(ExplicitCallingConvention.class,
    +                                    "value", SubstrateCallingConventionKind.Custom),
    +                    newAnnotationValue(Uninterruptible.class,
    +                                    "calleeMustBe", false,
    +                                    "reason", "Directly accesses registers and IsolateThread might not be correctly set up"));
     
         @Override
         public List getInjectedAnnotations() {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java
    index a58728ef199b..b346ba36f3ef 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/FeatureImpl.java
    @@ -47,7 +47,7 @@
     import java.util.stream.Collectors;
     
     import org.graalvm.collections.Pair;
    -import org.graalvm.nativeimage.AnnotationAccess;
    +import org.graalvm.nativeimage.dynamicaccess.AccessCondition;
     import org.graalvm.nativeimage.dynamicaccess.ForeignAccess;
     import org.graalvm.nativeimage.dynamicaccess.JNIAccess;
     import org.graalvm.nativeimage.dynamicaccess.ReflectiveAccess;
    @@ -55,7 +55,6 @@
     import org.graalvm.nativeimage.hosted.Feature;
     import org.graalvm.nativeimage.hosted.Feature.DuringAnalysisAccess;
     import org.graalvm.nativeimage.hosted.FieldValueTransformer;
    -import org.graalvm.nativeimage.dynamicaccess.AccessCondition;
     import org.graalvm.nativeimage.hosted.RuntimeReflection;
     
     import com.oracle.graal.pointsto.BigBang;
    @@ -100,6 +99,7 @@
     import com.oracle.svm.hosted.meta.HostedMethod;
     import com.oracle.svm.hosted.meta.HostedUniverse;
     import com.oracle.svm.hosted.option.HostedOptionProvider;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.debug.Assertions;
    @@ -477,7 +477,7 @@ public void registerAsUnsafeAccessed(Field field, Object reason) {
             }
     
             public boolean registerAsUnsafeAccessed(AnalysisField aField, Object reason) {
    -            assert !AnnotationAccess.isAnnotationPresent(aField, Delete.class);
    +            assert !AnnotationUtil.isAnnotationPresent(aField, Delete.class);
                 return aField.registerAsUnsafeAccessed(reason);
             }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    index c52bcce85ea8..4a6ae9e2451f 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/HostedConfiguration.java
    @@ -82,6 +82,7 @@
     import com.oracle.svm.hosted.meta.HostedType;
     import com.oracle.svm.hosted.meta.HostedUniverse;
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.core.common.CompressEncoding;
    @@ -352,7 +353,7 @@ protected void processedSynchronizedTypes(BigBang bb, HostedUniverse hUniverse,
          * Types that must be immutable cannot have a monitor field.
          */
         protected static void maybeSetMonitorField(HostedUniverse hUniverse, Set immutableTypes, AnalysisType type) {
    -        if (!type.isArray() && !immutableTypes.contains(type) && !type.isAnnotationPresent(ValueBased.class)) {
    +        if (!type.isArray() && !immutableTypes.contains(type) && !AnnotationUtil.isAnnotationPresent(type, ValueBased.class)) {
                 setMonitorField(hUniverse, type);
             }
         }
    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 b255031a1d39..03cc1e58f670 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
    @@ -85,7 +85,6 @@
     import org.graalvm.collections.EconomicMap;
     import org.graalvm.collections.EconomicSet;
     import org.graalvm.collections.MapCursor;
    -import org.graalvm.nativeimage.impl.AnnotationExtractor;
     import org.graalvm.nativeimage.libgraal.hosted.LibGraalLoader;
     
     import com.oracle.svm.core.NativeImageClassLoaderOptions;
    @@ -145,7 +144,7 @@ public final class NativeImageClassLoaderSupport {
         public final ModuleLayer moduleLayerForImageBuild;
         public final ModuleFinder modulepathModuleFinder;
     
    -    public final AnnotationExtractor annotationExtractor;
    +    public final SubstrateAnnotationExtractor annotationExtractor;
     
         private Path layerFile;
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java
    index 82f15f2f2563..737413e92d7b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java
    @@ -106,7 +106,6 @@
     import com.oracle.graal.pointsto.reports.AnalysisReporter;
     import com.oracle.graal.pointsto.typestate.DefaultAnalysisPolicy;
     import com.oracle.graal.pointsto.util.AnalysisError;
    -import com.oracle.svm.util.GraalAccess;
     import com.oracle.graal.pointsto.util.Timer.StopTimer;
     import com.oracle.graal.pointsto.util.TimerCollection;
     import com.oracle.graal.reachability.DirectMethodProcessingHandler;
    @@ -262,7 +261,9 @@
     import com.oracle.svm.hosted.util.CPUTypeAArch64;
     import com.oracle.svm.hosted.util.CPUTypeAMD64;
     import com.oracle.svm.hosted.util.CPUTypeRISCV64;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
    +import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.ImageBuildStatistics;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
    @@ -1196,7 +1197,7 @@ public static AnalysisUniverse createAnalysisUniverse(OptionValues options, Targ
             } else {
                 analysisFactory = new PointsToAnalysisFactory();
             }
    -        SubstrateAnnotationExtractor annotationExtractor = (SubstrateAnnotationExtractor) loader.classLoaderSupport.annotationExtractor;
    +        SubstrateAnnotationExtractor annotationExtractor = loader.classLoaderSupport.annotationExtractor;
             return new AnalysisUniverse(hostVM, target.wordJavaKind, analysisPolicy, aSubstitutions, originalMetaAccess, analysisFactory, annotationExtractor);
         }
     
    @@ -1779,7 +1780,7 @@ private static boolean addAssertionLIRPhases(LIRSuites lirSuites, boolean hosted
         private void checkUniverse() {
             if (SubstrateOptions.VerifyNamingConventions.getValue()) {
                 for (AnalysisMethod method : aUniverse.getMethods()) {
    -                if ((method.isInvoked() || method.isReachable()) && method.getAnnotation(Fold.class) == null) {
    +                if ((method.isInvoked() || method.isReachable()) && AnnotationUtil.getAnnotation(method, Fold.class) == null) {
                         checkName(bb, method);
                     }
                 }
    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 21dc317e8565..7213e51c2a16 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
    @@ -143,6 +143,7 @@
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
     import com.oracle.svm.hosted.substitute.AutomaticUnsafeTransformationSupport;
     import com.oracle.svm.hosted.util.IdentityHashCodeUtil;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.LogUtils;
     import com.oracle.svm.util.OriginalClassProvider;
    @@ -611,8 +612,8 @@ private DynamicHub createHub(AnalysisType type) {
             boolean isRecord = javaClass.isRecord();
             boolean assertionStatus = RuntimeAssertionsSupport.singleton().desiredAssertionStatus(javaClass);
             boolean isSealed = javaClass.isSealed();
    -        boolean isVMInternal = type.isAnnotationPresent(InternalVMMethod.class);
    -        boolean isLambdaFormHidden = type.isAnnotationPresent(LambdaFormHiddenMethod.class);
    +        boolean isVMInternal = AnnotationUtil.isAnnotationPresent(type, InternalVMMethod.class);
    +        boolean isLambdaFormHidden = AnnotationUtil.isAnnotationPresent(type, LambdaFormHiddenMethod.class);
             boolean isLinked = type.isLinked();
     
             nestHost = PredefinedClassesSupport.maybeAdjustLambdaNestHost(className, javaClass, classLoader, nestHost);
    @@ -691,7 +692,7 @@ private String getSimpleBinaryName(Class javaClass) {
         }
     
         public static boolean isUnknownClass(ResolvedJavaType resolvedJavaType) {
    -        return resolvedJavaType.getAnnotation(UnknownClass.class) != null;
    +        return AnnotationUtil.getAnnotation(resolvedJavaType, UnknownClass.class) != null;
         }
     
         public ClassInitializationSupport getClassInitializationSupport() {
    @@ -896,11 +897,11 @@ public boolean isAnalysisTrivialMethod(AnalysisMethod method) {
     
         @Override
         public boolean hasNeverInlineDirective(ResolvedJavaMethod method) {
    -        if (AnnotationAccess.isAnnotationPresent(method, NeverInline.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, NeverInline.class)) {
                 return true;
             }
     
    -        if (AnnotationAccess.isAnnotationPresent(method, DontInline.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, DontInline.class)) {
                 return true;
             }
     
    @@ -915,7 +916,7 @@ public boolean hasNeverInlineDirective(ResolvedJavaMethod method) {
     
         @Override
         public boolean hasAlwaysInlineDirective(ResolvedJavaMethod method) {
    -        return AnnotationAccess.isAnnotationPresent(method, AlwaysInline.class) || AnnotationAccess.isAnnotationPresent(method, ForceInline.class);
    +        return AnnotationUtil.isAnnotationPresent(method, AlwaysInline.class) || AnnotationUtil.isAnnotationPresent(method, ForceInline.class);
         }
     
         private InlineBeforeAnalysisPolicy inlineBeforeAnalysisPolicy(MultiMethod.MultiMethodKey multiMethodKey) {
    @@ -956,8 +957,7 @@ public boolean skipInterface(AnalysisUniverse universe, ResolvedJavaType interfa
     
         @Override
         public boolean platformSupported(AnnotatedElement element) {
    -        if (element instanceof ResolvedJavaType) {
    -            ResolvedJavaType javaType = (ResolvedJavaType) element;
    +        if (element instanceof ResolvedJavaType javaType) {
                 Package p = OriginalClassProvider.getJavaClass(javaType).getPackage();
                 if (p != null && !platformSupported(p)) {
                     return false;
    @@ -972,8 +972,7 @@ public boolean platformSupported(AnnotatedElement element) {
                     return false;
                 }
             }
    -        if (element instanceof Class) {
    -            Class clazz = (Class) element;
    +        if (element instanceof Class clazz) {
                 Package p = clazz.getPackage();
                 if (p != null && !platformSupported(p)) {
                     return false;
    @@ -1085,7 +1084,7 @@ public boolean isSupportedOriginalType(BigBang bb, ResolvedJavaType type) {
             }
     
             /* Substitution types should never be reachable directly. */
    -        if (AnnotationAccess.isAnnotationPresent(type, TargetClass.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(type, TargetClass.class)) {
                 return false;
             }
     
    @@ -1094,7 +1093,7 @@ public boolean isSupportedOriginalType(BigBang bb, ResolvedJavaType type) {
     
         /**
          * Check if an {@link AnalysisMethod} should be included in the image. For checking its
    -     * annotations we rely on the {@link AnnotationAccess} unwrapping mechanism to include any
    +     * annotations we rely on the {@link AnnotationUtil} unwrapping mechanism to include any
          * annotations injected in the substitution layer.
          */
         @Override
    @@ -1140,12 +1139,12 @@ private boolean isSupportedMethod(BigBang bb, ResolvedJavaMethod method) {
              * replaced by the invocation plugin with a constant. If reachable in an extension image,
              * the plugin will replace it again.
              */
    -        if (AnnotationAccess.isAnnotationPresent(method, Fold.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, Fold.class)) {
                 return false;
             }
     
             /* Deleted methods should not be included in the image. */
    -        if (AnnotationAccess.isAnnotationPresent(method, Delete.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, Delete.class)) {
                 return false;
             }
     
    @@ -1153,8 +1152,8 @@ private boolean isSupportedMethod(BigBang bb, ResolvedJavaMethod method) {
              * Methods whose graph cannot be created should not be in the image. Those methods are
              * compiled in a different way and cannot be included in the same way as normal methods.
              */
    -        if (AnnotationAccess.isAnnotationPresent(method, CConstant.class) || AnnotationAccess.isAnnotationPresent(method, Operation.class) ||
    -                        AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class) || AnnotationAccess.isAnnotationPresent(method, HotSpotOperation.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, CConstant.class) || AnnotationUtil.isAnnotationPresent(method, Operation.class) ||
    +                        AnnotationUtil.isAnnotationPresent(method, NodeIntrinsic.class) || AnnotationUtil.isAnnotationPresent(method, HotSpotOperation.class)) {
                 return false;
             }
     
    @@ -1188,13 +1187,13 @@ private boolean isSupportedMethod(BigBang bb, ResolvedJavaMethod method) {
             }
     
             /* CEntryPoint methods should not be included according to their predicate. */
    -        CEntryPoint cEntryPoint = AnnotationAccess.getAnnotation(method, CEntryPoint.class);
    +        CEntryPoint cEntryPoint = AnnotationUtil.getAnnotation(method, CEntryPoint.class);
             return cEntryPoint == null || ReflectionUtil.newInstance(cEntryPoint.include()).getAsBoolean();
         }
     
         /**
          * Check if an {@link AnalysisField} should be included in the image. For checking its
    -     * annotations we rely on the {@link AnnotationAccess} unwrapping mechanism to include any
    +     * annotations we rely on the {@link AnnotationUtil} unwrapping mechanism to include any
          * annotations injected in the substitution layer.
          */
         @Override
    @@ -1214,7 +1213,7 @@ public boolean isSupportedAnalysisField(BigBang bb, AnalysisField field) {
             }
     
             /* Fields that are deleted or substituted should not be in the image. */
    -        if (field.getAnnotation(Delete.class) != null || field.getAnnotation(InjectAccessors.class) != null) {
    +        if (AnnotationUtil.getAnnotation(field, Delete.class) != null || AnnotationUtil.getAnnotation(field, InjectAccessors.class) != null) {
                 return false;
             }
     
    @@ -1250,7 +1249,7 @@ public boolean isSupportedOriginalField(BigBang bb, ResolvedJavaField field) {
             }
     
             /* Fields that are always folded don't need to be included. */
    -        if (AnnotationAccess.isAnnotationPresent(field, GuaranteeFolded.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(field, GuaranteeFolded.class)) {
                 return false;
             }
     
    @@ -1317,8 +1316,8 @@ public boolean neverInlineTrivial(AnalysisMethod caller, AnalysisMethod callee)
             if (!callee.canBeInlined()) {
                 return true;
             }
    -        if (AnnotationAccess.isAnnotationPresent(callee, NeverInlineTrivial.class)) {
    -            Class[] onlyWith = AnnotationAccess.getAnnotation(callee, NeverInlineTrivial.class).onlyWith();
    +        if (AnnotationUtil.isAnnotationPresent(callee, NeverInlineTrivial.class)) {
    +            Class[] onlyWith = AnnotationUtil.getAnnotation(callee, NeverInlineTrivial.class).onlyWith();
                 if (shouldEvaluateNeverInlineTrivialOnlyWith(onlyWith)) {
                     return evaluateOnlyWith(onlyWith, callee.toString(), null);
                 }
    @@ -1430,7 +1429,8 @@ public void checkWellKnownStableFieldsBeforeAnalysis(BigBang bb) {
          */
         public boolean allowConstantFolding(ResolvedJavaField field) {
             AnalysisField aField = field instanceof HostedField ? ((HostedField) field).getWrapped() : (AnalysisField) field;
    -        if (!BuildPhaseProvider.isAnalysisFinished() && !aField.isFinal() && aField.isAnnotationPresent(Stable.class)) {
    +        if (!BuildPhaseProvider.isAnalysisFinished() && !aField.isFinal() &&
    +                        AnnotationUtil.isAnnotationPresent(aField, Stable.class)) {
                 return stableFieldsToFoldBeforeAnalysis.contains(aField);
             }
             return !finalFieldsInitializedOutsideOfConstructor.contains(aField);
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedArenaSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedArenaSupport.java
    index 4be86a774f02..5900efc85bbe 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedArenaSupport.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SharedArenaSupport.java
    @@ -27,11 +27,11 @@
     import java.lang.annotation.Annotation;
     import java.util.function.Function;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     
    -import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.api.replacements.Fold;
    @@ -64,6 +64,6 @@ static SharedArenaSupport singleton() {
     
         static boolean isScopedMethod(ResolvedJavaMethod method) {
             ResolvedJavaMethod originalMethod = OriginalMethodProvider.getOriginalMethod(method);
    -        return originalMethod != null && AnnotationAccess.isAnnotationPresent(originalMethod, SCOPED_ANNOTATION);
    +        return originalMethod != null && AnnotationUtil.isAnnotationPresent(originalMethod, SCOPED_ANNOTATION);
         }
     }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java
    index ff32113c469d..ea7db9229684 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantFieldProvider.java
    @@ -38,6 +38,7 @@
     import com.oracle.svm.hosted.jdk.JDKInitializationFeature;
     import com.oracle.svm.hosted.jdk.VarHandleFeature;
     import com.oracle.svm.hosted.meta.SharedConstantFieldProvider;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.virtual.phases.ea.PartialEscapePhase;
     import jdk.internal.vm.annotation.Stable;
    @@ -93,7 +94,8 @@ public  T readConstantField(ResolvedJavaField f, ConstantFieldTool analysi
          */
         @Override
         protected void onStableFieldRead(ResolvedJavaField field, JavaConstant value, ConstantFieldTool tool) {
    -        if (value.isDefaultForKind() && !BuildPhaseProvider.isAnalysisFinished() && !field.isFinal() && field.isAnnotationPresent(Stable.class)) {
    +        if (value.isDefaultForKind() && !BuildPhaseProvider.isAnalysisFinished() && !field.isFinal() &&
    +                        AnnotationUtil.isAnnotationPresent(field, Stable.class)) {
                 if (field.getName().equals("enableNativeAccess") && field.getDeclaringClass().getName().equals("Ljava/lang/Module;")) {
                     /* Edge case 1) */
                     return;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java
    index 9053c573aa30..39a65667fe2e 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/FieldValueInterceptionSupport.java
    @@ -38,11 +38,8 @@
     import org.graalvm.nativeimage.hosted.FieldValueTransformer;
     
     import com.oracle.graal.pointsto.heap.ImageHeapConstant;
    -import com.oracle.svm.util.OriginalClassProvider;
    -import com.oracle.svm.util.OriginalFieldProvider;
     import com.oracle.graal.pointsto.meta.AnalysisField;
     import com.oracle.graal.pointsto.meta.AnalysisType;
    -import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.core.RuntimeAssertionsSupport;
     import com.oracle.svm.core.annotate.Alias;
     import com.oracle.svm.core.annotate.InjectAccessors;
    @@ -62,7 +59,11 @@
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
     import com.oracle.svm.hosted.substitute.AutomaticUnsafeTransformationSupport;
     import com.oracle.svm.hosted.substitute.FieldValueTransformation;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
    +import com.oracle.svm.util.GraalAccess;
    +import com.oracle.svm.util.OriginalClassProvider;
    +import com.oracle.svm.util.OriginalFieldProvider;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.debug.Assertions;
    @@ -375,7 +376,7 @@ private static JavaConstant interceptValue(AnalysisField field, JavaConstant val
          * intercept the value and return 0 / null.
          */
         private static JavaConstant filterInjectedAccessor(AnalysisField field, JavaConstant value) {
    -        if (field.getAnnotation(InjectAccessors.class) != null) {
    +        if (AnnotationUtil.getAnnotation(field, InjectAccessors.class) != null) {
                 assert !field.isAccessed();
                 return JavaConstant.defaultForKind(value.getJavaKind());
             }
    @@ -410,7 +411,7 @@ private static JavaConstant interceptWordField(AnalysisField field, JavaConstant
         }
     
         private FieldValueTransformation createLayeredFieldValueTransformation(ResolvedJavaField oField, AnalysisField aField) {
    -        LayeredFieldValue layeredFieldValue = aField.getAnnotation(LayeredFieldValue.class);
    +        LayeredFieldValue layeredFieldValue = AnnotationUtil.getAnnotation(aField, LayeredFieldValue.class);
             if (layeredFieldValue != null) {
                 var transformer = layeredSupport.createTransformer(aField, layeredFieldValue);
                 return new FieldValueTransformation(OriginalClassProvider.getJavaClass(oField.getType()), transformer);
    @@ -419,7 +420,7 @@ private FieldValueTransformation createLayeredFieldValueTransformation(ResolvedJ
         }
     
         private static FieldValueComputer createFieldValueComputer(AnalysisField field) {
    -        UnknownObjectField unknownObjectField = field.getAnnotation(UnknownObjectField.class);
    +        UnknownObjectField unknownObjectField = AnnotationUtil.getAnnotation(field, UnknownObjectField.class);
             if (unknownObjectField != null) {
                 checkMisplacedAnnotation(field.getStorageKind().isObject(), field);
                 return new FieldValueComputer(
    @@ -427,7 +428,7 @@ private static FieldValueComputer createFieldValueComputer(AnalysisField field)
                                 extractAnnotationTypes(field, unknownObjectField.types(), unknownObjectField.fullyQualifiedTypes()),
                                 unknownObjectField.canBeNull());
             }
    -        UnknownPrimitiveField unknownPrimitiveField = field.getAnnotation(UnknownPrimitiveField.class);
    +        UnknownPrimitiveField unknownPrimitiveField = AnnotationUtil.getAnnotation(field, UnknownPrimitiveField.class);
             if (unknownPrimitiveField != null) {
                 checkMisplacedAnnotation(field.getStorageKind().isPrimitive(), field);
                 return new FieldValueComputer(
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CallChecker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CallChecker.java
    index 123d974da314..7244376031d5 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CallChecker.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/CallChecker.java
    @@ -26,12 +26,12 @@
     
     import java.util.regex.Pattern;
     
    -import jdk.graal.compiler.core.common.SuppressSVMWarnings;
    -
     import com.oracle.graal.pointsto.BigBang;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
     import com.oracle.graal.pointsto.meta.AnalysisType;
    +import com.oracle.svm.util.AnnotationUtil;
     
    +import jdk.graal.compiler.core.common.SuppressSVMWarnings;
     import jdk.vm.ci.code.BytecodePosition;
     
     public class CallChecker {
    @@ -70,10 +70,10 @@ public boolean isCallAllowed(BigBang bb, AnalysisMethod caller, AnalysisMethod c
             if (illegalCalleesPattern.matcher(calleeName).find()) {
                 String callerName = caller.getQualifiedName();
                 if (targetCallersPattern.matcher(callerName).find()) {
    -                SuppressSVMWarnings suppress = caller.getAnnotation(SuppressSVMWarnings.class);
    +                SuppressSVMWarnings suppress = AnnotationUtil.getAnnotation(caller, SuppressSVMWarnings.class);
                     AnalysisType callerType = caller.getDeclaringClass();
                     while (suppress == null && callerType != null) {
    -                    suppress = callerType.getAnnotation(SuppressSVMWarnings.class);
    +                    suppress = AnnotationUtil.getAnnotation(callerType, SuppressSVMWarnings.class);
                         callerType = callerType.getEnclosingType();
                     }
                     if (suppress != null) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java
    index de2b876ebf27..be7a64b56f9b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java
    @@ -66,4 +66,15 @@ default Annotation[] getAnnotations() {
         default Annotation[] getDeclaredAnnotations() {
             throw VMError.shouldNotReachHere("Getting all annotations is not supported because it initializes all annotation classes and their dependencies");
         }
    +
    +    @Override
    +    default  T[] getAnnotationsByType(Class annotationClass) {
    +        throw VMError.shouldNotReachHere("Getting all annotations is not supported because it initializes all annotation classes and their dependencies");
    +    }
    +
    +    @Override
    +    default  T[] getDeclaredAnnotationsByType(Class annotationClass) {
    +        throw VMError.shouldNotReachHere("Getting all annotations is not supported because it initializes all annotation classes and their dependencies");
    +    }
    +
     }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java
    index d32ad834596e..f4322daa06ce 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java
    @@ -24,12 +24,11 @@
      */
     package com.oracle.svm.hosted.annotation;
     
    -import java.lang.annotation.Annotation;
     import java.lang.reflect.AnnotatedElement;
     import java.util.List;
     
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.OriginalClassProvider;
     
     import jdk.vm.ci.meta.Assumptions.AssumptionResult;
     import jdk.vm.ci.meta.JavaConstant;
    @@ -407,16 +406,6 @@ public boolean isConcrete() {
             return original.isConcrete();
         }
     
    -    @Override
    -    public  T[] getAnnotationsByType(Class annotationClass) {
    -        return original.getAnnotationsByType(annotationClass);
    -    }
    -
    -    @Override
    -    public  T[] getDeclaredAnnotationsByType(Class annotationClass) {
    -        return original.getDeclaredAnnotationsByType(annotationClass);
    -    }
    -
         public ResolvedJavaType getOriginal() {
             return original;
         }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java
    index f548db0f26c1..1083a77ca7af 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java
    @@ -41,17 +41,19 @@
     import java.util.Map;
     import java.util.Objects;
     import java.util.concurrent.ConcurrentHashMap;
    -import java.util.stream.Stream;
     
     import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.impl.AnnotationExtractor;
     
     import com.oracle.graal.pointsto.infrastructure.WrappedElement;
     import com.oracle.graal.pointsto.meta.BaseLayerElement;
    +import com.oracle.graal.pointsto.reports.ReportUtils;
     import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly;
     import com.oracle.svm.core.traits.BuiltinTraits.NoLayeredCallbacks;
     import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent;
     import com.oracle.svm.core.traits.SingletonTraits;
    +import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.util.ReflectionUtil;
    @@ -85,7 +87,7 @@
      * their dependencies.
      */
     @SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class, layeredInstallationKind = Independent.class)
    -public class SubstrateAnnotationExtractor implements AnnotationExtractor {
    +public class SubstrateAnnotationExtractor implements AnnotationExtractor, AnnotationUtil.Access {
         private final Map> annotationCache = new ConcurrentHashMap<>();
         private final Map> declaredAnnotationCache = new ConcurrentHashMap<>();
         private final Map>> parameterAnnotationCache = new ConcurrentHashMap<>();
    @@ -95,6 +97,17 @@ public class SubstrateAnnotationExtractor implements AnnotationExtractor {
     
         private static final Method packageGetPackageInfo = ReflectionUtil.lookupMethod(Package.class, "getPackageInfo");
     
    +    @Override
    +    public  T getAnnotation(Annotated element, Class annotationType) {
    +        Inherited inherited = annotationType.getAnnotation(Inherited.class);
    +        Map annotationValues = getAnnotationValues(element, inherited == null);
    +        AnnotationValue annotationValue = annotationValues.get(GraalAccess.lookupType(annotationType));
    +        if (annotationValue != null) {
    +            return asAnnotation(annotationValue, annotationType);
    +        }
    +        return null;
    +    }
    +
         /**
          * Gets the annotation of type {@code annotationType} from {@code annotated}.
          */
    @@ -264,13 +277,6 @@ private static  T toAnnotation(AnnotationValue annotationV
             return type.cast(AnnotationParser.annotationForMap(type, memberValues));
         }
     
    -    public static List prepareInjectedAnnotations(Annotation... annotations) {
    -        if (annotations == null || annotations.length == 0) {
    -            return List.of();
    -        }
    -        return Stream.of(annotations).map(SubstrateAnnotationExtractor::toAnnotationValue).toList();
    -    }
    -
         @SuppressWarnings("unchecked")
         private  T extractAnnotation(Annotated element, Class annotationType, boolean declaredOnly) {
             Map annotationValues = getAnnotationValues(element, declaredOnly);
    @@ -281,6 +287,23 @@ private  T extractAnnotation(Annotated element, Class a
             return null;
         }
     
    +    @Override
    +    public  T asAnnotation(AnnotationValue annotationValue, Class annotationType) {
    +        T res = annotationType.cast(resolvedAnnotationsCache.computeIfAbsent(annotationValue, value -> toAnnotation(value, annotationType)));
    +        Class resType = res.annotationType();
    +        if (!resType.equals(annotationType)) {
    +            throw VMError.shouldNotReachHere("Conversion failed: expected %s (loader: %s), got %s (loader: %s)",
    +                            annotationType.getName(), ReportUtils.loaderName(annotationType.getClassLoader()),
    +                            resType.getName(), ReportUtils.loaderName(resType.getClassLoader()));
    +        }
    +        return res;
    +    }
    +
    +    @Override
    +    public AnnotationValue asAnnotationValue(Annotation annotation) {
    +        return toAnnotationValue(annotation);
    +    }
    +
         @Override
         public  T extractAnnotation(AnnotatedElement element, Class annotationType, boolean declaredOnly) {
             try {
    @@ -376,6 +399,11 @@ public Map getDeclaredAnnotationValues(Annota
             return getAnnotationValues(toAnnotated(element), true);
         }
     
    +    @Override
    +    public Map getDeclaredAnnotationValues(Annotated element) {
    +        return getAnnotationValues(element, true);
    +    }
    +
         private Map getAnnotationValues(Annotated element, boolean declaredOnly) {
             Annotated cur = element;
             while (cur instanceof WrappedElement wrapped) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CConstantValueSupportImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CConstantValueSupportImpl.java
    index 3cb28c01587f..c695aac1ce0e 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CConstantValueSupportImpl.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/CConstantValueSupportImpl.java
    @@ -42,6 +42,7 @@
     import com.oracle.svm.hosted.c.info.ConstantInfo;
     import com.oracle.svm.hosted.c.info.EnumInfo;
     import com.oracle.svm.hosted.phases.CInterfaceInvocationPlugin;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
    @@ -134,7 +135,7 @@ private ResolvedJavaMethod getAnnotatedMethod(Class declaringClass, String me
                 throw VMError.shouldNotReachHere("Method not found: " + declaringClass.getName() + "." + methodName);
             }
     
    -        if (method.getAnnotation(annotationClass) == null) {
    +        if (AnnotationUtil.getAnnotation(method, annotationClass) == null) {
                 throw VMError.shouldNotReachHere("Method " + declaringClass.getName() + "." + methodName + " is not annotated with @" + ClassUtil.getUnqualifiedName(annotationClass));
             }
             return method;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
    index 8059b87250d2..3b5c01b77a34 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/NativeLibraries.java
    @@ -80,6 +80,7 @@
     import com.oracle.svm.hosted.c.info.ElementInfo;
     import com.oracle.svm.hosted.c.libc.HostedLibCBase;
     import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
     
    @@ -413,9 +414,9 @@ public void loadJavaMethod(ResolvedJavaMethod method) {
     
             if (!context.isInConfiguration()) {
                 /* Nothing to do, all elements in context are ignored. */
    -        } else if (method.getAnnotation(CConstant.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(method, CConstant.class) != null) {
                 context.appendConstantAccessor(method);
    -        } else if (method.getAnnotation(CFunction.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(method, CFunction.class) != null) {
                 /* Nothing to do, handled elsewhere but the NativeCodeContext above is important. */
             } else {
                 addError("Method is not annotated with supported C interface annotation", method);
    @@ -427,15 +428,15 @@ public void loadJavaType(ResolvedJavaType type) {
     
             if (!context.isInConfiguration()) {
                 /* Nothing to do, all elements in context are ignored. */
    -        } else if (type.getAnnotation(CStruct.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(type, CStruct.class) != null) {
                 context.appendStructType(type);
    -        } else if (type.getAnnotation(RawStructure.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(type, RawStructure.class) != null) {
                 context.appendRawStructType(type);
    -        } else if (type.getAnnotation(CPointerTo.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(type, CPointerTo.class) != null) {
                 context.appendCPointerToType(type);
    -        } else if (type.getAnnotation(RawPointerTo.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(type, RawPointerTo.class) != null) {
                 context.appendRawPointerToType(type);
    -        } else if (type.getAnnotation(CEnum.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(type, CEnum.class) != null) {
                 context.appendEnumType(type);
             } else {
                 addError("Type is not annotated with supported C interface annotation", type);
    @@ -574,7 +575,7 @@ private Class getDirectives(ResolvedJavaMethod me
         }
     
         private Class getDirectives(ResolvedJavaType type) {
    -        CContext useUnit = type.getAnnotation(CContext.class);
    +        CContext useUnit = AnnotationUtil.getAnnotation(type, CContext.class);
             if (useUnit != null) {
                 return getDirectives(useUnit);
             } else if (type.getEnclosingType() != null) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java
    index 42614394ce60..8aa9289c920b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java
    @@ -56,6 +56,7 @@
     import com.oracle.svm.hosted.c.info.InfoTreeBuilder;
     import com.oracle.svm.hosted.c.info.PointerToInfo;
     import com.oracle.svm.hosted.c.info.StructInfo;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.meta.JavaKind;
     import jdk.vm.ci.meta.MetaAccessProvider;
    @@ -257,7 +258,7 @@ private static boolean isUnsigned(AnnotatedType type) {
     
         private static boolean isFunctionPointer(MetaAccessProvider metaAccess, ResolvedJavaType type) {
             boolean functionPointer = metaAccess.lookupJavaType(CFunctionPointer.class).isAssignableFrom(type);
    -        return functionPointer && Arrays.stream(type.getDeclaredMethods(false)).anyMatch(v -> v.getDeclaredAnnotation(InvokeCFunctionPointer.class) != null);
    +        return functionPointer && Arrays.stream(type.getDeclaredMethods(false)).anyMatch(v -> AnnotationUtil.getAnnotation(v, InvokeCFunctionPointer.class) != null);
         }
     
         /**
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java
    index 58e138aaa30c..aaddb28119b5 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/InfoTreeBuilder.java
    @@ -66,6 +66,7 @@
     import com.oracle.svm.hosted.c.info.SizableInfo.ElementKind;
     import com.oracle.svm.hosted.cenum.CEnumCallWrapperMethod;
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
     import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.OriginalMethodProvider;
    @@ -214,7 +215,7 @@ private static AccessorKind getAccessorKind(ResolvedJavaMethod accessor) {
         }
     
         public static String getTypedefName(ResolvedJavaType type) {
    -        CTypedef typedefAnnotation = type.getAnnotation(CTypedef.class);
    +        CTypedef typedefAnnotation = AnnotationUtil.getAnnotation(type, CTypedef.class);
             return typedefAnnotation != null ? typedefAnnotation.name() : null;
         }
     
    @@ -228,7 +229,7 @@ private void createStructInfo(ResolvedJavaType type) {
             List structAccessorInfos = new ArrayList<>();
     
             for (ResolvedJavaMethod method : type.getDeclaredMethods(false)) {
    -            if (!AnnotationSubstitutionProcessor.isIncluded(method.getAnnotation(TargetElement.class), ((AnalysisType) method.getDeclaringClass()).getJavaClass(), method)) {
    +            if (!AnnotationSubstitutionProcessor.isIncluded(AnnotationUtil.getAnnotation(method, TargetElement.class), ((AnalysisType) method.getDeclaringClass()).getJavaClass(), method)) {
                     continue;
                 }
     
    @@ -522,7 +523,7 @@ private boolean checkObjectType(ResolvedJavaType type, ResolvedJavaMethod method
         }
     
         private boolean validInterfaceDefinition(ResolvedJavaType type, Class annotationClass) {
    -        assert type.getAnnotation(annotationClass) != null;
    +        assert AnnotationUtil.getAnnotation(type, annotationClass) != null;
     
             if (!type.isInterface() || !nativeLibs.isPointerBase(type)) {
                 nativeLibs.addError("Annotation @" + ClassUtil.getUnqualifiedName(annotationClass) + " can only be used on an interface that extends " + PointerBase.class.getSimpleName(), type);
    @@ -555,7 +556,7 @@ private static String getConstantName(ResolvedJavaMethod method) {
         }
     
         private String getCPointerToTypeName(ResolvedJavaType type) {
    -        CPointerTo pointerToAnnotation = type.getAnnotation(CPointerTo.class);
    +        CPointerTo pointerToAnnotation = AnnotationUtil.getAnnotation(type, CPointerTo.class);
             Class pointerToType = pointerToAnnotation.value();
             String nameOfCType = pointerToAnnotation.nameOfCType();
     
    @@ -589,7 +590,7 @@ private String getCPointerToTypeName(ResolvedJavaType type) {
         }
     
         private String getRawPointerToTypeName(ResolvedJavaType type) {
    -        RawPointerTo pointerToAnnotation = type.getAnnotation(RawPointerTo.class);
    +        RawPointerTo pointerToAnnotation = AnnotationUtil.getAnnotation(type, RawPointerTo.class);
             Class pointerToType = pointerToAnnotation.value();
     
             RawStructure pointerToRawStructAnnotation;
    @@ -620,10 +621,10 @@ private String getRawPointerToTypeName(ResolvedJavaType type) {
         }
     
         private static String getStructName(ResolvedJavaType type) {
    -        CStruct structAnnotation = type.getAnnotation(CStruct.class);
    +        CStruct structAnnotation = AnnotationUtil.getAnnotation(type, CStruct.class);
     
             if (structAnnotation == null) {
    -            RawStructure rsanno = type.getAnnotation(RawStructure.class);
    +            RawStructure rsanno = AnnotationUtil.getAnnotation(type, RawStructure.class);
                 assert rsanno != null : "Unexpected struct type " + type;
                 return getSimpleJavaName(type);
             }
    @@ -664,7 +665,7 @@ private void createEnumInfo(ResolvedJavaType type) {
                 return;
             }
     
    -        CEnum annotation = type.getAnnotation(CEnum.class);
    +        CEnum annotation = AnnotationUtil.getAnnotation(type, CEnum.class);
             String name = annotation.value();
             if (name.isEmpty()) {
                 name = "int";
    @@ -706,7 +707,7 @@ private void createEnumConstantInfo(EnumInfo enumInfo, ResolvedJavaField field)
             ResolvedJavaType originalType = originalProviders.getMetaAccess().lookupJavaType(enumValue);
             assert enumValue.isNonNull() && originalType.equals(((WrappedElement) enumInfo.getAnnotatedElement()).getWrapped());
     
    -        CEnumConstant fieldAnnotation = field.getAnnotation(CEnumConstant.class);
    +        CEnumConstant fieldAnnotation = AnnotationUtil.getAnnotation(field, CEnumConstant.class);
             String name = "";
             boolean includeInLookup = true;
             if (fieldAnnotation != null) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/StructInfo.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/StructInfo.java
    index 77d3e4a3ac91..8dea096fb226 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/StructInfo.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/info/StructInfo.java
    @@ -27,6 +27,8 @@
     import org.graalvm.nativeimage.c.struct.CStruct;
     import org.graalvm.nativeimage.c.struct.RawStructure;
     
    +import com.oracle.svm.util.AnnotationUtil;
    +
     import jdk.vm.ci.meta.ResolvedJavaType;
     
     public class StructInfo extends SizableInfo {
    @@ -38,10 +40,10 @@ public class StructInfo extends SizableInfo {
     
         public static StructInfo create(String typeName, ResolvedJavaType annotatedType) {
             String typedefAnnotation = InfoTreeBuilder.getTypedefName(annotatedType);
    -        if (annotatedType.getAnnotation(RawStructure.class) != null) {
    +        if (AnnotationUtil.getAnnotation(annotatedType, RawStructure.class) != null) {
                 return new RawStructureInfo(typeName, typedefAnnotation, annotatedType);
             } else {
    -            return new StructInfo(typeName, typedefAnnotation, annotatedType, annotatedType.getAnnotation(CStruct.class).isIncomplete());
    +            return new StructInfo(typeName, typedefAnnotation, annotatedType, AnnotationUtil.getAnnotation(annotatedType, CStruct.class).isIncomplete());
             }
         }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/RawStructureLayoutPlanner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/RawStructureLayoutPlanner.java
    index 5d49627caff3..d3d5f11f2ad4 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/RawStructureLayoutPlanner.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/RawStructureLayoutPlanner.java
    @@ -45,6 +45,7 @@
     import com.oracle.svm.hosted.c.info.SizableInfo.SignednessValue;
     import com.oracle.svm.hosted.c.info.StructBitfieldInfo;
     import com.oracle.svm.hosted.c.info.StructFieldInfo;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
     
    @@ -176,7 +177,7 @@ private static void planLayout(RawStructureInfo info) {
             }
     
             int totalSize;
    -        Class sizeProviderClass = info.getAnnotatedElement().getAnnotation(RawStructure.class).sizeProvider();
    +        Class sizeProviderClass = AnnotationUtil.getAnnotation(info.getAnnotatedElement(), RawStructure.class).sizeProvider();
             if (sizeProviderClass == IntUnaryOperator.class) {
                 /* No sizeProvider specified in the annotation, so no adjustment necessary. */
                 totalSize = currentOffset;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/SizeAndSignednessVerifier.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/SizeAndSignednessVerifier.java
    index 8c3b4db14d0d..1a8b188c3ddc 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/SizeAndSignednessVerifier.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/query/SizeAndSignednessVerifier.java
    @@ -30,7 +30,6 @@
     import java.util.List;
     import java.util.Map;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.c.constant.CEnum;
     import org.graalvm.nativeimage.c.constant.CEnumConstant;
     import org.graalvm.nativeimage.c.struct.AllowNarrowingCast;
    @@ -54,6 +53,7 @@
     import com.oracle.svm.hosted.c.info.SizableInfo.ElementKind;
     import com.oracle.svm.hosted.c.info.StructBitfieldInfo;
     import com.oracle.svm.hosted.c.info.StructFieldInfo;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
     
     import jdk.graal.compiler.core.common.NumUtil;
    @@ -190,7 +190,7 @@ private CEnumRuntimeData createCEnumRuntimeData(EnumInfo enumInfo) {
             long[] javaToCArray = new long[javaToC.size()];
             for (Map.Entry, Long> entry : javaToC.entrySet()) {
                 int idx = entry.getKey().ordinal();
    -            assert idx >= 0 && idx < javaToCArray.length && javaToCArray[idx] == 0 : "ordinal values are defined as unique and consecutive";
    +            assert idx < javaToCArray.length && javaToCArray[idx] == 0 : "ordinal values are defined as unique and consecutive";
                 javaToCArray[idx] = entry.getValue();
             }
     
    @@ -241,7 +241,7 @@ private void verifyCEnumLookupMethodArguments(EnumInfo enumInfo) {
         private void verifySize(SizableInfo sizableInfo, ResolvedJavaType type, ResolvedJavaMethod method, boolean isReturn) {
             int declaredSize = getSizeInBytes(type);
     
    -        boolean allowNarrowingCast = AnnotationAccess.isAnnotationPresent(method, AllowNarrowingCast.class);
    +        boolean allowNarrowingCast = AnnotationUtil.isAnnotationPresent(method, AllowNarrowingCast.class);
             if (allowNarrowingCast) {
                 if (sizableInfo.isObject()) {
                     addError(ClassUtil.getUnqualifiedName(AllowNarrowingCast.class) + " cannot be used on fields that have an object type.", method);
    @@ -250,7 +250,7 @@ private void verifySize(SizableInfo sizableInfo, ResolvedJavaType type, Resolved
                 }
             }
     
    -        boolean allowWideningCast = AnnotationAccess.isAnnotationPresent(method, AllowWideningCast.class);
    +        boolean allowWideningCast = AnnotationUtil.isAnnotationPresent(method, AllowWideningCast.class);
             if (allowWideningCast) {
                 if (sizableInfo.isObject()) {
                     addError(ClassUtil.getUnqualifiedName(AllowWideningCast.class) + " cannot be used on fields that have an object type.", method);
    @@ -267,7 +267,7 @@ private void verifySize(SizableInfo sizableInfo, ResolvedJavaType type, Resolved
                 }
     
                 Class suppressionAnnotation = narrow ? AllowNarrowingCast.class : AllowWideningCast.class;
    -            if (method.getAnnotation(suppressionAnnotation) == null) {
    +            if (AnnotationUtil.getAnnotation(method, suppressionAnnotation) == null) {
                     addError("Type " + type.toJavaName(false) + " has a size of " + declaredSize + " bytes, but accessed C value has a size of " + actualSize +
                                     " bytes; to suppress this error, use the annotation @" + ClassUtil.getUnqualifiedName(suppressionAnnotation), method);
                 }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
    index e47b491e93d7..051bdad4442f 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java
    @@ -25,6 +25,7 @@
     package com.oracle.svm.hosted.cenum;
     
     import static com.oracle.svm.core.Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE;
    +import static com.oracle.svm.util.AnnotationUtil.newAnnotationValue;
     
     import java.lang.reflect.Modifier;
     import java.util.List;
    @@ -38,13 +39,12 @@
     import com.oracle.svm.core.Uninterruptible;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
     import com.oracle.svm.hosted.c.NativeLibraries;
     import com.oracle.svm.hosted.c.info.EnumInfo;
     import com.oracle.svm.hosted.phases.CInterfaceEnumTool;
     import com.oracle.svm.hosted.phases.CInterfaceInvocationPlugin;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    -import com.oracle.svm.util.ReflectionUtil;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.graal.compiler.debug.DebugContext;
    @@ -59,8 +59,10 @@
      * or {@link CEnumValue}.
      */
     public class CEnumCallWrapperMethod extends CustomSubstitutionMethod {
    -    private static final List INJECTED_ANNOTATIONS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(
    -                    Uninterruptible.Utils.getAnnotation(ReflectionUtil.lookupMethod(CEnumCallWrapperMethod.class, "uninterruptibleAnnotationHolder")));
    +    private static final List INJECTED_ANNOTATIONS = List.of(
    +                    newAnnotationValue(Uninterruptible.class,
    +                                    "reason", CALLED_FROM_UNINTERRUPTIBLE_CODE,
    +                                    "mayBeInlined", true));
     
         private final NativeLibraries nativeLibraries;
     
    @@ -77,7 +79,7 @@ public int getModifiers() {
         @Override
         public List getInjectedAnnotations() {
             /* Annotate @CEnumValue methods with @Uninterruptible. */
    -        if (original.getAnnotation(CEnumValue.class) != null) {
    +        if (AnnotationUtil.getAnnotation(original, CEnumValue.class) != null) {
                 return INJECTED_ANNOTATIONS;
             }
             return null;
    @@ -99,11 +101,11 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
         }
     
         private ValueNode createInvoke(AnalysisMethod method, HostedGraphKit kit, AnalysisType returnType, ValueNode arg) {
    -        if (method.getAnnotation(CEnumLookup.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, CEnumLookup.class) != null) {
                 /* Call a method that converts the primitive value to a Java enum. */
                 EnumInfo enumInfo = (EnumInfo) nativeLibraries.findElementInfo(returnType);
                 return CInterfaceEnumTool.singleton().createInvokeLookupEnum(kit, returnType, enumInfo, arg, true);
    -        } else if (method.getAnnotation(CEnumValue.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(method, CEnumValue.class) != null) {
                 /* Call a method that converts a Java enum to a primitive value. */
                 ResolvedJavaType declaringType = method.getDeclaringClass();
                 EnumInfo enumInfo = (EnumInfo) nativeLibraries.findElementInfo(declaringType);
    @@ -112,9 +114,4 @@ private ValueNode createInvoke(AnalysisMethod method, HostedGraphKit kit, Analys
     
             throw VMError.shouldNotReachHereUnexpectedInput(method); // ExcludeFromJacocoGeneratedReport
         }
    -
    -    @Uninterruptible(reason = CALLED_FROM_UNINTERRUPTIBLE_CODE, mayBeInlined = true)
    -    @SuppressWarnings("unused")
    -    private static void uninterruptibleAnnotationHolder() {
    -    }
     }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
    index 68b423f16a96..f055fc12e0d2 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
    @@ -27,12 +27,12 @@
     import java.util.Map;
     import java.util.concurrent.ConcurrentHashMap;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.c.constant.CEnumLookup;
     import org.graalvm.nativeimage.c.constant.CEnumValue;
     
     import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
     import com.oracle.svm.hosted.c.NativeLibraries;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
    @@ -51,8 +51,8 @@ public CEnumCallWrapperSubstitutionProcessor() {
     
         @Override
         public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
    -        if (AnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
    -                        AnnotationAccess.isAnnotationPresent(method, CEnumValue.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, CEnumLookup.class) ||
    +                        AnnotationUtil.isAnnotationPresent(method, CEnumValue.class)) {
                 return callWrappers.computeIfAbsent(method, v -> new CEnumCallWrapperMethod(nativeLibraries, v));
             } else {
                 return method;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java
    index 9afb8f6617d2..516268973cce 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/SimulateClassInitializerPolicy.java
    @@ -24,8 +24,6 @@
      */
     package com.oracle.svm.hosted.classinitialization;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
    -
     import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
     import com.oracle.graal.pointsto.phases.InlineBeforeAnalysis;
    @@ -35,6 +33,7 @@
     import com.oracle.svm.hosted.SVMHost;
     import com.oracle.svm.hosted.phases.ConstantFoldLoadFieldPlugin;
     import com.oracle.svm.hosted.phases.InlineBeforeAnalysisPolicyUtils;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.graph.Node;
     import jdk.graal.compiler.graph.NodeSourcePosition;
    @@ -50,7 +49,7 @@
      * This class is necessary because simulation of class initializer is based on
      * {@link InlineBeforeAnalysis}. The scope keeps track of the number of bytes that were allocated in
      * the image heap.
    - * 
    + *
      * See {@link SimulateClassInitializerSupport} for an overview of class initializer simulation.
      */
     public final class SimulateClassInitializerPolicy extends InlineBeforeAnalysisPolicy {
    @@ -115,7 +114,7 @@ protected boolean shouldInlineInvoke(GraphBuilderContext b, AbstractPolicyScope
                 /* Safeguard against excessive inlining, for example endless recursion. */
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), FactoryMethodMarker.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), FactoryMethodMarker.class)) {
                 /*
                  * Synthetic factory methods are annotated as "never inline before analysis" because
                  * they would all be inlined immediately. But for the class initializer analysis, we
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
    index 07325c40019a..3b2b3cb01a46 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubMethod.java
    @@ -46,7 +46,6 @@
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
     import com.oracle.graal.pointsto.meta.AnalysisType;
     import com.oracle.graal.pointsto.meta.HostedProviders;
    -import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.core.SubstrateUtil;
     import com.oracle.svm.core.Uninterruptible;
     import com.oracle.svm.core.c.function.CEntryPointBuiltins;
    @@ -68,6 +67,8 @@
     import com.oracle.svm.hosted.c.info.EnumInfo;
     import com.oracle.svm.hosted.phases.CInterfaceEnumTool;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.GraalAccess;
     
     import jdk.graal.compiler.core.common.calc.FloatConvert;
     import jdk.graal.compiler.core.common.type.StampFactory;
    @@ -331,7 +332,7 @@ private StructuredGraph buildBuiltinGraph(DebugContext debug, AnalysisMethod met
             CEntryPoint.Builtin builtin = entryPointData.getBuiltin();
             AnalysisMethod builtinCallee = null;
             for (AnalysisMethod candidate : kit.getMetaAccess().lookupJavaType(CEntryPointBuiltins.class).getDeclaredMethods(false)) {
    -            CEntryPointBuiltinImplementation annotation = candidate.getAnnotation(CEntryPointBuiltinImplementation.class);
    +            CEntryPointBuiltinImplementation annotation = AnnotationUtil.getAnnotation(candidate, CEntryPointBuiltinImplementation.class);
                 if (annotation != null && annotation.builtin().equals(builtin)) {
                     VMError.guarantee(builtinCallee == null, "More than one candidate for @%s built-in %s", CEntryPoint.class.getSimpleName(), builtin);
                     builtinCallee = candidate;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointData.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointData.java
    index 6c0c54d7f75b..7a32f2d25708 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointData.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointData.java
    @@ -38,6 +38,7 @@
     import com.oracle.svm.core.c.function.CEntryPointSetup;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.image.NativeImage;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
    @@ -52,7 +53,7 @@ public final class CEntryPointData {
         public static final Class DEFAULT_EXCEPTION_HANDLER = CEntryPoint.FatalExceptionHandler.class;
     
         public static CEntryPointData create(ResolvedJavaMethod method) {
    -        return create(method.getAnnotation(CEntryPoint.class), method.getAnnotation(CEntryPointOptions.class),
    +        return create(AnnotationUtil.getAnnotation(method, CEntryPoint.class), AnnotationUtil.getAnnotation(method, CEntryPointOptions.class),
                             () -> NativeImage.globalSymbolNameForMethod(method));
         }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java
    index d384b6831f03..c804cd9d810c 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java
    @@ -37,6 +37,7 @@
     import com.oracle.svm.core.thread.VMThreads.StatusSupport;
     import com.oracle.svm.core.util.UserError;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.nodes.CallTargetNode;
     import jdk.graal.compiler.nodes.ConstantNode;
    @@ -79,7 +80,7 @@ protected String getCorrespondingAnnotationName() {
     
         @Override
         protected void emitCallerEpilogue(HostedGraphKit kit) {
    -        CEntryPointOptions options = getOriginal().getAnnotation(CEntryPointOptions.class);
    +        CEntryPointOptions options = AnnotationUtil.getAnnotation(getOriginal(), CEntryPointOptions.class);
             if (options != null && options.callerEpilogue() != null && options.callerEpilogue() != CEntryPointOptions.NoCallerEpilogue.class) {
                 AnalysisType epilogue = kit.getMetaAccess().lookupJavaType(options.callerEpilogue());
                 AnalysisMethod[] epilogueMethods = epilogue.getDeclaredMethods(false);
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java
    index 11f679e1d366..632d4e6ce55e 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java
    @@ -43,6 +43,7 @@
     import com.oracle.svm.hosted.FeatureImpl.CompilationAccessImpl;
     import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
     import com.oracle.svm.hosted.meta.HostedMethod;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
    @@ -66,7 +67,7 @@ public Object apply(Object source) {
                     ResolvedJavaMethod javaMethod = metaAccess.lookupJavaMethod(reflectionMethod);
                     if (javaMethod instanceof AnalysisMethod) {
                         AnalysisMethod aMethod = (AnalysisMethod) javaMethod;
    -                    CEntryPoint annotation = aMethod.getAnnotation(CEntryPoint.class);
    +                    CEntryPoint annotation = AnnotationUtil.getAnnotation(aMethod, CEntryPoint.class);
                         UserError.guarantee(annotation != null, "Method referenced by %s must be annotated with @%s: %s", CEntryPointLiteral.class.getSimpleName(),
                                         CEntryPoint.class.getSimpleName(), javaMethod);
                         CEntryPointCallStubSupport.singleton().registerStubForMethod(aMethod, () -> CEntryPointData.create(aMethod));
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java
    index 15ed29fed1c4..2fbaed888e9b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionCallStubMethod.java
    @@ -39,6 +39,7 @@
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.c.NativeLibraries;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
     
     import jdk.graal.compiler.debug.DebugContext;
    @@ -63,7 +64,7 @@ protected String getCorrespondingAnnotationName() {
         }
     
         private Class getAnnotationClass() {
    -        if (original.getAnnotation(CFunction.class) != null) {
    +        if (AnnotationUtil.getAnnotation(original, CFunction.class) != null) {
                 return CFunction.class;
             } else {
                 throw VMError.shouldNotReachHere("Method is not annotated with @" + CFunction.class.getSimpleName());
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionLinkages.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionLinkages.java
    index bfc4e4c31dc9..f3f6117ed27b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionLinkages.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionLinkages.java
    @@ -27,18 +27,19 @@
     import java.util.Map;
     import java.util.concurrent.ConcurrentHashMap;
     
    -import jdk.graal.compiler.graph.Node.NodeIntrinsic;
    -import jdk.graal.compiler.word.Word;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.c.function.CFunction;
     import org.graalvm.nativeimage.c.function.CFunctionPointer;
     
     import com.oracle.svm.core.c.CGlobalData;
     import com.oracle.svm.core.c.CGlobalDataFactory;
    -import com.oracle.svm.core.graal.code.CGlobalDataInfo;
     import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
    +import com.oracle.svm.core.graal.code.CGlobalDataInfo;
     import com.oracle.svm.hosted.c.CGlobalDataFeature;
    +import com.oracle.svm.util.AnnotationUtil;
     
    +import jdk.graal.compiler.graph.Node.NodeIntrinsic;
    +import jdk.graal.compiler.word.Word;
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
     @AutomaticallyRegisteredImageSingleton
    @@ -53,7 +54,7 @@ public static CFunctionLinkages singleton() {
         }
     
         public CGlobalDataInfo addOrLookupMethod(ResolvedJavaMethod method) {
    -        if (method.getAnnotation(NodeIntrinsic.class) != null || method.getAnnotation(Word.Operation.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, NodeIntrinsic.class) != null || AnnotationUtil.getAnnotation(method, Word.Operation.class) != null) {
                 return null;
             }
             return nameToFunction.computeIfAbsent(linkageName(method), symbolName -> {
    @@ -71,7 +72,7 @@ private static String linkageName(ResolvedJavaMethod method) {
         }
     
         private static String getLinkageNameFromAnnotation(ResolvedJavaMethod method) {
    -        CFunction cFunctionAnnotation = method.getAnnotation(CFunction.class);
    +        CFunction cFunctionAnnotation = AnnotationUtil.getAnnotation(method, CFunction.class);
             if (cFunctionAnnotation != null) {
                 return cFunctionAnnotation.value();
             }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java
    index ba2af8a72645..f3c87a18280e 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionPointerCallStubMethod.java
    @@ -37,6 +37,7 @@
     import com.oracle.svm.core.thread.VMThreads.StatusSupport;
     import com.oracle.svm.hosted.c.NativeLibraries;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.debug.DebugContext;
     import jdk.graal.compiler.nodes.StructuredGraph;
    @@ -55,7 +56,7 @@ public final class CFunctionPointerCallStubMethod extends CCallStubMethod {
         static CFunctionPointerCallStubMethod create(AnalysisMethod aMethod) {
             assert !aMethod.isSynthetic() : "Creating a stub for a stub? " + aMethod;
             ResolvedJavaMethod method = aMethod.getWrapped();
    -        int newThreadStatus = StatusSupport.getNewThreadStatus(aMethod.getAnnotation(InvokeCFunctionPointer.class).transition());
    +        int newThreadStatus = StatusSupport.getNewThreadStatus(AnnotationUtil.getAnnotation(aMethod, InvokeCFunctionPointer.class).transition());
             return new CFunctionPointerCallStubMethod(method, newThreadStatus);
         }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionSubstitutionProcessor.java
    index 4f37018be348..62ef915746c3 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionSubstitutionProcessor.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CFunctionSubstitutionProcessor.java
    @@ -27,7 +27,6 @@
     import java.util.Map;
     import java.util.concurrent.ConcurrentHashMap;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.c.function.CFunction;
     
     import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
    @@ -36,6 +35,7 @@
     import com.oracle.svm.core.graal.code.CGlobalDataInfo;
     import com.oracle.svm.core.thread.VMThreads.StatusSupport;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
    @@ -45,8 +45,8 @@ public class CFunctionSubstitutionProcessor extends SubstitutionProcessor {
         @Override
         public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
             ResolvedJavaMethod wrapper = method;
    -        if (method.isNative() && method.isAnnotationPresent(CFunction.class)) {
    -            if (AnnotationAccess.isAnnotationPresent(method, Uninterruptible.class)) {
    +        if (method.isNative() && AnnotationUtil.isAnnotationPresent(method, CFunction.class)) {
    +            if (AnnotationUtil.isAnnotationPresent(method, Uninterruptible.class)) {
                     throw VMError.shouldNotReachHere("Native method '%s' incorrectly annotated with @Uninterruptible. Please use @CFunction(transition = NO_TRANSITION) instead.",
                                     method.format("%H.%n(%p)"));
                 }
    @@ -60,12 +60,12 @@ public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
         }
     
         private static int getNewThreadStatus(ResolvedJavaMethod method) {
    -        CFunctionOptions cFunctionOptions = method.getAnnotation(CFunctionOptions.class);
    +        CFunctionOptions cFunctionOptions = AnnotationUtil.getAnnotation(method, CFunctionOptions.class);
             if (cFunctionOptions != null) {
                 return StatusSupport.getNewThreadStatus(cFunctionOptions.transition());
             }
     
    -        CFunction cFunctionAnnotation = method.getAnnotation(CFunction.class);
    +        CFunction cFunctionAnnotation = AnnotationUtil.getAnnotation(method, CFunction.class);
             if (cFunctionAnnotation != null) {
                 return StatusSupport.getNewThreadStatus(cFunctionAnnotation.transition());
             }
    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 eb362d695998..b094e92c15e6 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
    @@ -42,11 +42,9 @@
     
     import com.oracle.graal.pointsto.api.PointstoOptions;
     import com.oracle.graal.pointsto.flow.AnalysisParsedGraph;
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.graal.pointsto.meta.HostedProviders;
     import com.oracle.graal.pointsto.util.CompletionExecutor;
     import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable;
    -import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.common.meta.MultiMethod;
     import com.oracle.svm.core.SubstrateOptions;
     import com.oracle.svm.core.Uninterruptible;
    @@ -81,8 +79,11 @@
     import com.oracle.svm.hosted.meta.HostedUniverse;
     import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase;
     import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.ImageBuildStatistics;
     import com.oracle.svm.util.LogUtils;
    +import com.oracle.svm.util.OriginalClassProvider;
     
     import jdk.graal.compiler.api.replacements.Fold;
     import jdk.graal.compiler.asm.Assembler;
    @@ -931,7 +932,7 @@ private static boolean mustNotAllocate(HostedMethod method) {
              * to @Uninterruptible or mark them as @NeverInline, so that no-allocation does not need any
              * more inlining restrictions and this code can be removed.
              */
    -        RestrictHeapAccess annotation = method.getAnnotation(RestrictHeapAccess.class);
    +        RestrictHeapAccess annotation = AnnotationUtil.getAnnotation(method, RestrictHeapAccess.class);
             return annotation != null && annotation.access() == RestrictHeapAccess.Access.NO_ALLOCATION;
         }
     
    @@ -942,7 +943,7 @@ public static boolean callerAnnotatedWith(Invoke invoke, Class T getCallerAnnotation(Invoke invoke, Class annotationClass) {
             for (FrameState state = invoke.stateAfter(); state != null; state = state.outerFrameState()) {
                 assert state.getMethod() != null : state;
    -            T annotation = state.getMethod().getAnnotation(annotationClass);
    +            T annotation = AnnotationUtil.getAnnotation(state.getMethod(), annotationClass);
                 if (annotation != null) {
                     return annotation;
                 }
    @@ -1051,7 +1052,7 @@ protected void ensureParsed(HostedMethod method, HostedMethod callerMethod, Comp
                 return;
             }
     
    -        if (!allowFoldMethods && method.getAnnotation(Fold.class) != null && !isFoldInvocationPluginMethod(callerMethod)) {
    +        if (!allowFoldMethods && AnnotationUtil.getAnnotation(method, Fold.class) != null && !isFoldInvocationPluginMethod(callerMethod)) {
                 throw VMError.shouldNotReachHere("Parsing method annotated with @%s: %s. " +
                                 "This could happen if either: the Graal annotation processor was not executed on the parent-project of the method's declaring class, " +
                                 "the arguments passed to the method were not compile-time constants, or the plugin was disabled by the corresponding %s.",
    @@ -1105,7 +1106,7 @@ private static void loadPriorStrengthenedGraph(HostedMethod method) {
         }
     
         private void defaultParseFunction(DebugContext debug, HostedMethod method, CompileReason reason, RuntimeConfiguration config, ParseHooks hooks) {
    -        if (method.getAnnotation(NodeIntrinsic.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, NodeIntrinsic.class) != null) {
                 throw VMError.shouldNotReachHere("Parsing method annotated with @" + NodeIntrinsic.class.getSimpleName() + ": " +
                                 method.format("%H.%n(%p)") +
                                 ". Make sure you have used Graal annotation processors on the parent-project of the method's declaring class.");
    @@ -1211,10 +1212,10 @@ protected boolean canBeUsedForInlining(Invoke invoke) {
                 return false;
             }
     
    -        if (callee.getAnnotation(Specialize.class) != null) {
    +        if (AnnotationUtil.getAnnotation(callee, Specialize.class) != null) {
                 return false;
             }
    -        if (callerAnnotatedWith(invoke, Specialize.class) && callee.getAnnotation(DeoptTest.class) != null) {
    +        if (callerAnnotatedWith(invoke, Specialize.class) && AnnotationUtil.getAnnotation(callee, DeoptTest.class) != null) {
                 return false;
             }
     
    @@ -1235,7 +1236,7 @@ protected boolean canBeUsedForInlining(Invoke invoke) {
         }
     
         private static void handleSpecialization(final HostedMethod method, CallTargetNode targetNode, HostedMethod invokeTarget, HostedMethod invokeImplementation) {
    -        if (method.getAnnotation(Specialize.class) != null && !method.isDeoptTarget() && invokeTarget.getAnnotation(DeoptTest.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, Specialize.class) != null && !method.isDeoptTarget() && AnnotationUtil.getAnnotation(invokeTarget, DeoptTest.class) != null) {
                 /*
                  * Collect the constant arguments to a method which should be specialized.
                  */
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java
    index 974f513fd64c..8ba009f4d3b1 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java
    @@ -54,6 +54,7 @@
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.meta.HostedMethod;
     import com.oracle.svm.hosted.meta.HostedUniverse;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.code.CompilationResult;
     import jdk.graal.compiler.graph.Node;
    @@ -136,7 +137,7 @@ public static boolean canDeoptForTesting(AnalysisMethod method, boolean deoptimi
                 return false;
             }
     
    -        if (method.getAnnotation(DeoptTest.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, DeoptTest.class) != null) {
                 return true;
             }
     
    @@ -169,7 +170,7 @@ public static boolean canDeoptForTesting(AnalysisMethod method, boolean deoptimi
             if (Uninterruptible.Utils.isUninterruptible(method)) {
                 return false;
             }
    -        if (method.getAnnotation(RestrictHeapAccess.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, RestrictHeapAccess.class) != null) {
                 return false;
             }
             if (StubCallingConvention.Utils.hasStubCallingConvention(method)) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/EntryPointCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/EntryPointCallStubMethod.java
    index b0bfb4373023..ecd6090af7b7 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/EntryPointCallStubMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/EntryPointCallStubMethod.java
    @@ -24,11 +24,11 @@
      */
     package com.oracle.svm.hosted.code;
     
    +import static com.oracle.svm.util.AnnotationUtil.newAnnotationValue;
    +
     import java.util.List;
     
     import com.oracle.svm.core.Uninterruptible;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
    -import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.vm.ci.meta.ConstantPool;
    @@ -47,13 +47,10 @@ protected EntryPointCallStubMethod(String name, ResolvedJavaType declaringClass,
          * they must be uninterruptible. The method then called by the stub does not need to be
          * uninterruptible itself.
          */
    -    @Uninterruptible(reason = "Entry point", calleeMustBe = false)
    -    @SuppressWarnings("unused")
    -    private static void uninterruptibleAnnotationHolder() {
    -    }
    -
    -    private static final List INJECTED_ANNOTATIONS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(
    -                    Uninterruptible.Utils.getAnnotation(ReflectionUtil.lookupMethod(EntryPointCallStubMethod.class, "uninterruptibleAnnotationHolder")));
    +    private static final List INJECTED_ANNOTATIONS = List.of(
    +                    newAnnotationValue(Uninterruptible.class,
    +                                    "reason", "Entry point",
    +                                    "calleeMustBe", false));
     
         @Override
         public List getInjectedAnnotations() {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java
    index 0b7f6322f40f..bc0849aca483 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java
    @@ -24,6 +24,8 @@
      */
     package com.oracle.svm.hosted.code;
     
    +import static com.oracle.svm.util.AnnotationUtil.newAnnotationValue;
    +
     import java.util.List;
     
     import org.graalvm.nativeimage.ImageSingletons;
    @@ -32,10 +34,8 @@
     import com.oracle.graal.pointsto.meta.AnalysisType;
     import com.oracle.graal.pointsto.meta.HostedProviders;
     import com.oracle.svm.core.NeverInlineTrivial;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
     import com.oracle.svm.hosted.meta.HostedMethod;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    -import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.graal.compiler.debug.DebugContext;
    @@ -72,13 +72,7 @@ public final class FactoryMethod extends NonBytecodeMethod {
          * machine code for allocations is large. Note that this does not preclude later inlining of the
          * method as part of the regular AOT compilation pipeline.
          */
    -    @NeverInlineTrivial(reason = "FactoryMethod")
    -    @SuppressWarnings("unused")
    -    private static void annotationHolder() {
    -    }
    -
    -    private static final List INJECTED_ANNOTATIONS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(
    -                    ReflectionUtil.lookupMethod(FactoryMethod.class, "annotationHolder").getAnnotation(NeverInlineTrivial.class));
    +    private static final List INJECTED_ANNOTATIONS = List.of(newAnnotationValue(NeverInlineTrivial.class, "reason", "FactoryMethod"));
     
         @Override
         public List getInjectedAnnotations() {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NativeMethodSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NativeMethodSubstitutionProcessor.java
    index c440263f9386..65d1ee47429d 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NativeMethodSubstitutionProcessor.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NativeMethodSubstitutionProcessor.java
    @@ -24,7 +24,6 @@
      */
     package com.oracle.svm.hosted.code;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.c.constant.CConstant;
     import org.graalvm.nativeimage.c.function.CFunction;
     
    @@ -32,6 +31,7 @@
     import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
     import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod;
     import com.oracle.svm.core.option.HostedOptionValues;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.graph.Node.NodeIntrinsic;
     import jdk.graal.compiler.nodes.graphbuilderconf.InvocationPlugin;
    @@ -64,9 +64,9 @@ public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
                 assert !(method instanceof WrappedJavaMethod) : "Must not see AnalysisMethod or HostedMethod here";
                 return method;
             }
    -        assert !AnnotationAccess.isAnnotationPresent(method, CFunction.class) : "CFunction must have been handled by another SubstitutionProcessor";
    -        if (AnnotationAccess.isAnnotationPresent(method, NodeIntrinsic.class) || AnnotationAccess.isAnnotationPresent(method, Operation.class) ||
    -                        AnnotationAccess.isAnnotationPresent(method, CConstant.class)) {
    +        assert !AnnotationUtil.isAnnotationPresent(method, CFunction.class) : "CFunction must have been handled by another SubstitutionProcessor";
    +        if (AnnotationUtil.isAnnotationPresent(method, NodeIntrinsic.class) || AnnotationUtil.isAnnotationPresent(method, Operation.class) ||
    +                        AnnotationUtil.isAnnotationPresent(method, CConstant.class)) {
                 return method;
             }
             boolean isHandledByPlugin = replacements.getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(method, HostedOptionValues.singleton()) != null;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RestrictHeapAccessCalleesImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RestrictHeapAccessCalleesImpl.java
    index 157c79bd7745..24d08b46be07 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RestrictHeapAccessCalleesImpl.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RestrictHeapAccessCalleesImpl.java
    @@ -31,7 +31,6 @@
     import java.util.Map;
     import java.util.Set;
     
    -import com.oracle.svm.hosted.DeadlockWatchdog;
     import org.graalvm.collections.EconomicSet;
     import org.graalvm.collections.UnmodifiableEconomicSet;
     import org.graalvm.nativeimage.ImageSingletons;
    @@ -44,8 +43,10 @@
     import com.oracle.svm.core.heap.RestrictHeapAccess.Access;
     import com.oracle.svm.core.heap.RestrictHeapAccessCallees;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.hosted.DeadlockWatchdog;
     import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl;
     import com.oracle.svm.hosted.meta.HostedMethod;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.code.BytecodePosition;
     import jdk.vm.ci.meta.ResolvedJavaMethod;
    @@ -111,7 +112,7 @@ public void aggregateMethods(Collection methods) {
             DeadlockWatchdog watchdog = DeadlockWatchdog.singleton();
             watchdog.recordActivity();
             for (AnalysisMethod method : methods) {
    -            if (method.isAnnotationPresent(RestrictHeapAccess.class)) {
    +            if (AnnotationUtil.isAnnotationPresent(method, RestrictHeapAccess.class)) {
                     setMethodRestrictionInfo(method, aggregation);
                 }
             }
    @@ -132,19 +133,19 @@ public void aggregateMethods(Collection methods) {
          * same annotation as the method.
          */
         private static void setMethodRestrictionInfo(AnalysisMethod method, Map aggregation) {
    -        assert method.isAnnotationPresent(RestrictHeapAccess.class);
    +        assert AnnotationUtil.isAnnotationPresent(method, RestrictHeapAccess.class);
             if (aggregation.get(method) != null) {
                 return;
             }
             Set implementations = method.collectMethodImplementations(false);
             for (AnalysisMethod impl : implementations) {
    -            if (impl.isAnnotationPresent(RestrictHeapAccess.class) && !impl.equals(method)) {
    +            if (AnnotationUtil.isAnnotationPresent(impl, RestrictHeapAccess.class) && !impl.equals(method)) {
                     /* Annotated overrides take precedence, so process them first. */
                     setMethodRestrictionInfo(impl, aggregation);
                 }
             }
             assert aggregation.get(method) == null;
    -        Access access = method.getAnnotation(RestrictHeapAccess.class).access();
    +        Access access = AnnotationUtil.getAnnotation(method, RestrictHeapAccess.class).access();
             aggregation.put(method, new RestrictionInfo(access, null, null, method));
             for (AnalysisMethod impl : implementations) {
                 aggregation.putIfAbsent(impl, new RestrictionInfo(access, null, null, impl));
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java
    index f5ccebf38230..9792c36b8545 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/UninterruptibleAnnotationChecker.java
    @@ -28,7 +28,6 @@
     import java.util.Set;
     import java.util.TreeSet;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.c.function.CFunction;
     
    @@ -40,6 +39,7 @@
     import com.oracle.svm.core.option.HostedOptionKey;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.meta.HostedMethod;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.graph.Node;
     import jdk.graal.compiler.nodes.StructuredGraph;
    @@ -115,7 +115,7 @@ private void checkSpecifiedOptions(HostedMethod method, Uninterruptible annotati
             }
     
             if (annotation.reason().equals(Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE)) {
    -            if (!annotation.mayBeInlined() && !AnnotationAccess.isAnnotationPresent(method, NeverInline.class)) {
    +            if (!annotation.mayBeInlined() && !AnnotationUtil.isAnnotationPresent(method, NeverInline.class)) {
                     violations.add("Method " + method.format("%H.%n(%p)") +
                                     " uses an unspecific reason but prevents inlining into interruptible code. " +
                                     "If the method has an inherent reason for being uninterruptible, besides being called from uninterruptible code, then please improve the reason. " +
    @@ -138,7 +138,7 @@ private void checkSpecifiedOptions(HostedMethod method, Uninterruptible annotati
             }
     
             if (annotation.mayBeInlined()) {
    -            if (AnnotationAccess.isAnnotationPresent(method, NeverInline.class)) {
    +            if (AnnotationUtil.isAnnotationPresent(method, NeverInline.class)) {
                     violations.add("Method " + method.format("%H.%n(%p)") +
                                     " is annotated with conflicting annotations: @Uninterruptible('mayBeInlined = true') and @NeverInline");
                 }
    @@ -150,14 +150,14 @@ private void checkSpecifiedOptions(HostedMethod method, Uninterruptible annotati
             }
     
             if (annotation.mayBeInlined() && annotation.calleeMustBe()) {
    -            if (!annotation.reason().equals(Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE) && !AnnotationAccess.isAnnotationPresent(method, AlwaysInline.class)) {
    +            if (!annotation.reason().equals(Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE) && !AnnotationUtil.isAnnotationPresent(method, AlwaysInline.class)) {
                     violations.add("Method " + method.format("%H.%n(%p)") + " is annotated with @Uninterruptible('mayBeInlined = true') which allows the method to be inlined into interruptible code. " +
                                     "If the method has an inherent reason for being uninterruptible, besides being called from uninterruptible code, then please remove 'mayBeInlined = true'. " +
                                     "Otherwise, use the following reason: '" + Uninterruptible.CALLED_FROM_UNINTERRUPTIBLE_CODE + "'");
                 }
             }
     
    -        if (!annotation.mayBeInlined() && !annotation.callerMustBe() && AnnotationAccess.isAnnotationPresent(method, AlwaysInline.class)) {
    +        if (!annotation.mayBeInlined() && !annotation.callerMustBe() && AnnotationUtil.isAnnotationPresent(method, AlwaysInline.class)) {
                 violations.add("Method " + method.format("%H.%n(%p)") +
                                 " is annotated with @Uninterruptible and @AlwaysInline. If the method may be inlined into interruptible code, please specify 'mayBeInlined = true'. Otherwise, specify 'callerMustBe = true'.");
             }
    @@ -280,13 +280,13 @@ public static boolean isAllocationNode(Node node) {
         }
     
         private static boolean isCallerMustBe(HostedMethod method) {
    -        Uninterruptible uninterruptibleAnnotation = Uninterruptible.Utils.getAnnotation(method);
    -        return uninterruptibleAnnotation != null && uninterruptibleAnnotation.callerMustBe();
    +        Uninterruptible annotation = Uninterruptible.Utils.getAnnotation(method);
    +        return annotation != null && annotation.callerMustBe();
         }
     
         private static boolean isCalleeMustBe(HostedMethod method) {
    -        Uninterruptible uninterruptibleAnnotation = Uninterruptible.Utils.getAnnotation(method);
    -        return uninterruptibleAnnotation != null && uninterruptibleAnnotation.calleeMustBe();
    +        Uninterruptible annotation = Uninterruptible.Utils.getAnnotation(method);
    +        return annotation != null && annotation.calleeMustBe();
         }
     
         private static void printDotGraphEdge(HostedMethod caller, HostedMethod callee) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java
    index 89a320ecd33a..1b573fd15d2a 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/HybridLayoutSupport.java
    @@ -32,6 +32,7 @@
     import com.oracle.svm.hosted.meta.HostedField;
     import com.oracle.svm.hosted.meta.HostedInstanceClass;
     import com.oracle.svm.hosted.meta.HostedType;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.api.replacements.Fold;
     import jdk.vm.ci.meta.MetaAccessProvider;
    @@ -44,7 +45,7 @@ public static HybridLayoutSupport singleton() {
         }
     
         public boolean isHybrid(ResolvedJavaType clazz) {
    -        return clazz.isAnnotationPresent(Hybrid.class);
    +        return AnnotationUtil.isAnnotationPresent(clazz, Hybrid.class);
         }
     
         @SuppressWarnings("unused")
    @@ -75,7 +76,7 @@ public boolean canInstantiateAsInstance(HostedType clazz) {
         protected HybridInfo inspectHybrid(HostedInstanceClass hybridClass, MetaAccessProvider metaAccess) {
             assert Modifier.isFinal(hybridClass.getModifiers()) : "Hybrid class must be final " + hybridClass;
     
    -        Class componentType = hybridClass.getAnnotation(Hybrid.class).componentType();
    +        Class componentType = AnnotationUtil.getAnnotation(hybridClass, Hybrid.class).componentType();
             assert componentType != void.class : "@Hybrid.componentType cannot be void";
             return new HybridInfo((HostedType) metaAccess.lookupJavaType(componentType), null);
         }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dynamicaccessinference/StrictDynamicAccessInferenceFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dynamicaccessinference/StrictDynamicAccessInferenceFeature.java
    index 0757e6760492..fd0c4dd5c17b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dynamicaccessinference/StrictDynamicAccessInferenceFeature.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/dynamicaccessinference/StrictDynamicAccessInferenceFeature.java
    @@ -26,7 +26,6 @@
     
     import java.lang.invoke.MethodHandles;
     import java.lang.invoke.MethodType;
    -import java.lang.reflect.AnnotatedElement;
     import java.lang.reflect.Executable;
     import java.lang.reflect.Field;
     import java.lang.reflect.InvocationHandler;
    @@ -48,24 +47,25 @@
     import org.graalvm.nativeimage.hosted.RuntimeReflection;
     import org.graalvm.nativeimage.hosted.RuntimeResourceAccess;
     
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.graal.pointsto.meta.AnalysisUniverse;
    -import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.core.ParsingReason;
     import com.oracle.svm.core.annotate.Delete;
     import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
     import com.oracle.svm.core.feature.InternalFeature;
    -import com.oracle.svm.core.option.HostedOptionKey;
     import com.oracle.svm.core.hub.ClassForNameSupport;
     import com.oracle.svm.core.hub.PredefinedClassesSupport;
     import com.oracle.svm.core.hub.RuntimeClassLoading;
    +import com.oracle.svm.core.option.HostedOptionKey;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.ExceptionSynthesizer;
     import com.oracle.svm.hosted.FeatureImpl;
     import com.oracle.svm.hosted.ImageClassLoader;
     import com.oracle.svm.hosted.ReachabilityCallbackNode;
     import com.oracle.svm.hosted.substitute.DeletedElementException;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.GraalAccess;
     import com.oracle.svm.util.LogUtils;
    +import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.TypeResult;
     
    @@ -84,6 +84,7 @@
     import jdk.vm.ci.meta.JavaKind;
     import jdk.vm.ci.meta.MetaAccessProvider;
     import jdk.vm.ci.meta.ResolvedJavaMethod;
    +import jdk.vm.ci.meta.annotation.Annotated;
     
     /**
      * Feature for controlling the optimization independent inference of invocations which would
    @@ -465,7 +466,7 @@ private  T getIntrinsic(GraphBuilderContext context, T element) {
             }
     
             private static  boolean isDeleted(T element, MetaAccessProvider metaAccess) {
    -            AnnotatedElement annotated = null;
    +            Annotated annotated = null;
                 try {
                     if (element instanceof Executable) {
                         annotated = metaAccess.lookupJavaMethod((Executable) element);
    @@ -483,7 +484,7 @@ private static  boolean isDeleted(T element, MetaAccessProvider metaAccess) {
                  * If ReportUnsupportedElementsAtRuntime is set looking up a @Delete-ed element will
                  * return a substitution method that has the @Delete annotation.
                  */
    -            return annotated != null && annotated.isAnnotationPresent(Delete.class);
    +            return annotated != null && AnnotationUtil.isAnnotationPresent(annotated, Delete.class);
             }
     
             private void registerBulkPlugin(InvocationPlugins invocationPlugins, ParsingReason reason, String methodName, Consumer> registrationCallback) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java
    index 28a5190107da..978f91daa5ad 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/heap/PodFactorySubstitutionMethod.java
    @@ -29,8 +29,6 @@
     import java.util.concurrent.ConcurrentHashMap;
     import java.util.concurrent.ConcurrentMap;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
    -
     import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor;
     import com.oracle.graal.pointsto.meta.AnalysisField;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
    @@ -50,6 +48,7 @@
     import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
     import com.oracle.svm.hosted.nodes.DeoptProxyNode;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.core.common.type.StampFactory;
     import jdk.graal.compiler.debug.DebugContext;
    @@ -75,7 +74,7 @@ final class PodFactorySubstitutionProcessor extends SubstitutionProcessor {
     
         @Override
         public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
    -        if (method.isSynthetic() && AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), PodFactory.class) && !method.isConstructor()) {
    +        if (method.isSynthetic() && AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), PodFactory.class) && !method.isConstructor()) {
                 assert !(method instanceof CustomSubstitutionMethod);
                 return substitutions.computeIfAbsent(method, PodFactorySubstitutionMethod::new);
             }
    @@ -120,7 +119,7 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
             }
     
             AnalysisType factoryType = method.getDeclaringClass();
    -        PodFactory annotation = factoryType.getAnnotation(PodFactory.class);
    +        PodFactory annotation = AnnotationUtil.getAnnotation(factoryType, PodFactory.class);
             AnalysisType podConcreteType = kit.getMetaAccess().lookupJavaType(annotation.podClass());
             AnalysisMethod targetCtor = findMatchingConstructor(method, podConcreteType.getSuperclass());
     
    @@ -132,7 +131,7 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos
             int instanceLocal = kit.getFrameState().localsSize() - 1; // reserved when generating class
             int nextDeoptIndex = startMethod(kit, deoptInfo, 0);
             instantiatePod(kit, factoryType, podConcreteType, instanceLocal);
    -        if (isAnnotationPresent(DeoptTest.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(this, DeoptTest.class)) {
                 if (!SubstrateCompilationDirectives.isDeoptTarget(method)) {
                     kit.append(new TestDeoptimizeNode());
                 }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java
    index 9eed7db7f65d..ddee04590a95 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java
    @@ -125,6 +125,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.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
     
    @@ -269,7 +270,7 @@ private void writeHeaderFile(Path outDir, Header header, List meth
         private static Class cHeader(HostedMethod entryPointStub) {
             /* check if method is annotated */
             AnalysisMethod entryPoint = CEntryPointCallStubSupport.singleton().getMethodForStub((CEntryPointCallStubMethod) entryPointStub.wrapped.wrapped);
    -        CHeader methodAnnotation = entryPoint.getDeclaredAnnotation(CHeader.class);
    +        CHeader methodAnnotation = AnnotationUtil.getAnnotation(entryPoint, CHeader.class);
             if (methodAnnotation != null) {
                 return methodAnnotation.value();
             }
    @@ -277,7 +278,7 @@ private static Class cHeader(HostedMethod entryPointSt
             /* check if enclosing classes are annotated */
             AnalysisType enclosingType = entryPoint.getDeclaringClass();
             while (enclosingType != null) {
    -            CHeader enclosing = enclosingType.getDeclaredAnnotation(CHeader.class);
    +            CHeader enclosing = AnnotationUtil.getAnnotation(enclosingType, CHeader.class);
                 if (enclosing != null) {
                     return enclosing.value();
                 }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java
    index a22be9d623bd..a6ede3629b70 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageDebugInfoProvider.java
    @@ -97,6 +97,7 @@
     import com.oracle.svm.hosted.substitute.InjectedFieldsType;
     import com.oracle.svm.hosted.substitute.SubstitutionMethod;
     import com.oracle.svm.hosted.substitute.SubstitutionType;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ClassUtil;
     import com.oracle.svm.util.OriginalClassProvider;
     
    @@ -776,11 +777,11 @@ public static TypeEntry processElementInfo(NativeLibraries nativeLibs, AnalysisM
                          * RawPointerTo annotation
                          */
                         AnalysisType pointerTo = null;
    -                    CPointerTo cPointerTo = type.getAnnotation(CPointerTo.class);
    +                    CPointerTo cPointerTo = AnnotationUtil.getAnnotation(type, CPointerTo.class);
                         if (cPointerTo != null) {
                             pointerTo = metaAccess.lookupJavaType(cPointerTo.value());
                         }
    -                    RawPointerTo rawPointerTo = type.getAnnotation(RawPointerTo.class);
    +                    RawPointerTo rawPointerTo = AnnotationUtil.getAnnotation(type, RawPointerTo.class);
                         if (rawPointerTo != null) {
                             pointerTo = metaAccess.lookupJavaType(rawPointerTo.value());
                         }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredFieldValueTransformerSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredFieldValueTransformerSupport.java
    index 4975f6bfa3a1..92eef23b66c2 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredFieldValueTransformerSupport.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LayeredFieldValueTransformerSupport.java
    @@ -59,6 +59,7 @@
     import com.oracle.svm.hosted.FeatureImpl;
     import com.oracle.svm.hosted.image.NativeImageHeap;
     import com.oracle.svm.hosted.meta.HostedField;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.vm.ci.meta.JavaConstant;
    @@ -137,7 +138,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
                 for (var fieldId : fieldsWithUpdatableValues) {
                     var aField = loader.getAnalysisFieldForBaseLayerId(fieldId);
                     List receiverIds = loader.getUpdatableFieldReceiverIds(fieldId);
    -                var proxy = createTransformer(aField, aField.getAnnotation(LayeredFieldValue.class), Set.copyOf(receiverIds));
    +                var proxy = createTransformer(aField, AnnotationUtil.getAnnotation(aField, LayeredFieldValue.class), Set.copyOf(receiverIds));
     
                     for (int receiverId : receiverIds) {
                         ImageHeapConstant constant = loader.getConstant(receiverId);
    @@ -235,7 +236,7 @@ private LayeredFieldValueTransformerImpl createTransformer(AnalysisField aField,
          * Called on all field values before heap layout. Note, that because we cannot fold updatable
          * values, we need to have an explicit call to signal that it is safe to expose updatable
          * values.
    -     * 
    +     *
          * @return whether this receiver needs to be patched.
          */
         public boolean finalizeFieldValue(HostedField hField, JavaConstant receiver) {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java
    index 83d4a3543216..beac6843a608 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/LoadImageSingletonFeature.java
    @@ -382,10 +382,10 @@ private void addInitialObjects(NativeImageHeap heap, HostedUniverse hUniverse) {
     
             /*
              * Record the id of all multilayered image singleton entries which may be referenced.
    -         * 
    +         *
              * In shared layers, we must add and record the id of all multilayered image singletons in
              * case they are referred to in a later layer.
    -         * 
    +         *
              * However, in the application layer we only need to add and record all multilayered image
              * singletons currently referred to.
              */
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java
    index 603fd58fed71..21c8a1caea0e 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerLoader.java
    @@ -55,7 +55,6 @@
     import java.util.stream.IntStream;
     
     import org.graalvm.collections.EconomicMap;
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.c.function.CEntryPoint;
     import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer;
    @@ -73,7 +72,6 @@
     import com.oracle.graal.pointsto.heap.ImageHeapPrimitiveArray;
     import com.oracle.graal.pointsto.heap.ImageHeapRelocatableConstant;
     import com.oracle.graal.pointsto.heap.value.ValueSupplier;
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.graal.pointsto.infrastructure.ResolvedSignature;
     import com.oracle.graal.pointsto.meta.AnalysisField;
     import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
    @@ -131,7 +129,9 @@
     import com.oracle.svm.shaded.org.capnproto.PrimitiveList;
     import com.oracle.svm.shaded.org.capnproto.StructList;
     import com.oracle.svm.shaded.org.capnproto.Text;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.LogUtils;
    +import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.api.replacements.SnippetReflectionProvider;
    @@ -1734,7 +1734,7 @@ private JavaConstant lookupHostedObject(PersistedConstant.Reader baseLayerConsta
     
         private static boolean shouldRelinkField(AnalysisField field) {
             VMError.guarantee(field.isInBaseLayer());
    -        return !(field.getWrapped() instanceof BaseLayerField) && !AnnotationAccess.isAnnotationPresent(field, Delete.class);
    +        return !(field.getWrapped() instanceof BaseLayerField) && !AnnotationUtil.isAnnotationPresent(field, Delete.class);
         }
     
         @SuppressWarnings("unchecked")
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java
    index 52ac11b576bd..dc9b0da4d6e1 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/imagelayer/SVMImageLayerWriter.java
    @@ -69,7 +69,6 @@
     
     import org.graalvm.collections.EconomicMap;
     import org.graalvm.collections.MapCursor;
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.hosted.Feature;
     import org.graalvm.nativeimage.impl.CEntryPointLiteralCodePointer;
    @@ -171,6 +170,7 @@
     import com.oracle.svm.shaded.org.capnproto.Text;
     import com.oracle.svm.shaded.org.capnproto.TextList;
     import com.oracle.svm.shaded.org.capnproto.Void;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.LogUtils;
     import com.oracle.svm.util.OriginalFieldProvider;
     
    @@ -930,7 +930,7 @@ private boolean shouldRelinkConstant(ImageHeapConstant heapConstant) {
         }
     
         private static boolean shouldRelinkField(AnalysisField field) {
    -        return !AnnotationAccess.isAnnotationPresent(field, Delete.class) &&
    +        return !AnnotationUtil.isAnnotationPresent(field, Delete.class) &&
                             ClassInitializationSupport.singleton().maybeInitializeAtBuildTime(field.getDeclaringClass()) &&
                             field.isStatic() && field.isFinal() && field.isTrackedAcrossLayers() && field.installableInLayer();
         }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java
    index 5b6612c8e43c..348ab3ddb223 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jvmti/JvmtiFeature.java
    @@ -57,6 +57,7 @@
     import com.oracle.svm.hosted.code.CEntryPointData;
     import com.oracle.svm.hosted.meta.HostedMethod;
     import com.oracle.svm.hosted.meta.HostedType;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.vm.ci.meta.MetaAccessProvider;
    @@ -131,7 +132,7 @@ private static void fillJvmtiFunctionTable(CompilationAccessImpl access) {
         }
     
         private static boolean isIncluded(HostedMethod method) {
    -        CEntryPoint entryPoint = method.getAnnotation(CEntryPoint.class);
    +        CEntryPoint entryPoint = AnnotationUtil.getAnnotation(method, CEntryPoint.class);
             return ReflectionUtil.newInstance(entryPoint.include()).getAsBoolean();
         }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java
    index 2d105c565421..d7b676ef2ba8 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/lambda/LambdaSubstitutionType.java
    @@ -28,7 +28,7 @@
     
     import com.oracle.svm.core.jdk.LambdaFormHiddenMethod;
     import com.oracle.svm.hosted.annotation.CustomSubstitutionType;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.vm.ci.meta.ResolvedJavaType;
    @@ -49,7 +49,7 @@ public String getName() {
             return stableName;
         }
     
    -    private static final List INJECTED_ANNOTATIONS = SubstrateAnnotationExtractor.prepareInjectedAnnotations(LambdaFormHiddenMethod.Holder.INSTANCE);
    +    private static final List INJECTED_ANNOTATIONS = List.of(AnnotationUtil.newAnnotationValue(LambdaFormHiddenMethod.class));
     
         @Override
         public List getInjectedAnnotations() {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedElement.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedElement.java
    index 2c49eeffbed7..d082dc505a95 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedElement.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedElement.java
    @@ -28,7 +28,9 @@
     import java.lang.reflect.AnnotatedElement;
     
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.AnnotationUtil;
     
    +import jdk.graal.compiler.debug.GraalError;
     import jdk.vm.ci.meta.annotation.Annotated;
     import jdk.vm.ci.meta.annotation.AnnotationsInfo;
     
    @@ -46,17 +48,17 @@ public AnnotationsInfo getTypeAnnotationInfo() {
     
         @Override
         public final boolean isAnnotationPresent(Class annotationClass) {
    -        return getWrapped().isAnnotationPresent(annotationClass);
    +        return AnnotationUtil.isAnnotationPresent((Annotated) getWrapped(), annotationClass);
         }
     
         @Override
         public final  T getAnnotation(Class annotationClass) {
    -        return getWrapped().getAnnotation(annotationClass);
    +        return AnnotationUtil.getAnnotation((Annotated) getWrapped(), annotationClass);
         }
     
         @Override
         public final  T getDeclaredAnnotation(Class annotationClass) {
    -        return getWrapped().getDeclaredAnnotation(annotationClass);
    +        throw GraalError.shouldNotReachHere("The getDeclaredAnnotation method is not supported");
         }
     
         @Override
    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 ea60c9ddea26..037c4818f877 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
    @@ -26,7 +26,6 @@
     
     import static com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton.LAYER_NUM_UNINSTALLED;
     
    -import com.oracle.svm.util.OriginalFieldProvider;
     import com.oracle.graal.pointsto.infrastructure.WrappedJavaField;
     import com.oracle.graal.pointsto.meta.AnalysisField;
     import com.oracle.svm.core.imagelayer.ImageLayerBuildingSupport;
    @@ -34,6 +33,7 @@
     import com.oracle.svm.core.meta.SharedField;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport;
    +import com.oracle.svm.util.OriginalFieldProvider;
     
     import jdk.graal.compiler.debug.Assertions;
     import jdk.vm.ci.meta.JavaConstant;
    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 fd76abcb2802..5ac61233e951 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
    @@ -37,7 +37,6 @@
     import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
     
     import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
    -import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.graal.pointsto.infrastructure.ResolvedSignature;
     import com.oracle.graal.pointsto.infrastructure.WrappedJavaMethod;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
    @@ -61,6 +60,8 @@
     import com.oracle.svm.hosted.OpenTypeWorldFeature;
     import com.oracle.svm.hosted.code.CompilationInfo;
     import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalMethodProvider;
     
     import jdk.graal.compiler.api.replacements.Snippet;
     import jdk.graal.compiler.debug.Assertions;
    @@ -369,12 +370,12 @@ public boolean needSafepointCheck() {
     
         @Override
         public boolean isForeignCallTarget() {
    -        return isAnnotationPresent(SubstrateForeignCallTarget.class);
    +        return AnnotationUtil.isAnnotationPresent(this, SubstrateForeignCallTarget.class);
         }
     
         @Override
         public boolean isSnippet() {
    -        return isAnnotationPresent(Snippet.class);
    +        return AnnotationUtil.isAnnotationPresent(this, Snippet.class);
         }
     
         public boolean hasVTableIndex() {
    @@ -414,7 +415,7 @@ void finalizeIndirectCallVTableIndex() {
     
         @Override
         public Deoptimizer.StubType getDeoptStubType() {
    -        Deoptimizer.DeoptStub stubAnnotation = getAnnotation(Deoptimizer.DeoptStub.class);
    +        Deoptimizer.DeoptStub stubAnnotation = AnnotationUtil.getAnnotation(this, Deoptimizer.DeoptStub.class);
             if (stubAnnotation != null) {
                 return stubAnnotation.stubType();
             }
    @@ -585,7 +586,7 @@ public boolean hasNeverInlineDirective() {
     
         @Override
         public boolean shouldBeInlined() {
    -        return getAnnotation(AlwaysInline.class) != null || getAnnotation(ForceInline.class) != null;
    +        return AnnotationUtil.getAnnotation(this, AlwaysInline.class) != null || AnnotationUtil.getAnnotation(this, ForceInline.class) != null;
         }
     
         private LineNumberTable lineNumberTable;
    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 eb020e0f6695..77cf62afeeca 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
    @@ -30,7 +30,6 @@
     
     import org.graalvm.word.WordBase;
     
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.graal.pointsto.infrastructure.WrappedJavaType;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
     import com.oracle.graal.pointsto.meta.AnalysisType;
    @@ -39,6 +38,7 @@
     import com.oracle.svm.core.hub.RuntimeClassLoading;
     import com.oracle.svm.core.meta.SharedType;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.OriginalClassProvider;
     
     import jdk.graal.compiler.debug.Assertions;
     import jdk.vm.ci.meta.Assumptions.AssumptionResult;
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java
    index 6fb882bab9a6..7f34ca28025b 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/SharedConstantFieldProvider.java
    @@ -34,6 +34,7 @@
     import com.oracle.svm.core.meta.MethodRef;
     import com.oracle.svm.hosted.SVMHost;
     import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.core.common.spi.JavaConstantFieldProvider;
     import jdk.vm.ci.meta.JavaConstant;
    @@ -69,7 +70,7 @@ public boolean isStableField(ResolvedJavaField field, ConstantFieldTool tool)
              * the class loader of the using class into account. So we look at the annotation directly
              * for now.
              */
    -        if (field.isAnnotationPresent(jdk.internal.vm.annotation.Stable.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(field, jdk.internal.vm.annotation.Stable.class)) {
                 stable = true;
             } else {
                 stable = super.isStableField(field, tool);
    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 907c7719dd99..2d116b943341 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
    @@ -112,6 +112,7 @@
     import com.oracle.svm.hosted.imagelayer.LayeredStaticFieldSupport;
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
     import com.oracle.svm.hosted.substitute.DeletedMethod;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.core.common.NumUtil;
    @@ -380,8 +381,8 @@ private HostedMethod makeMethod(AnalysisMethod aMethod) {
                 HostedDynamicLayerInfo.singleton().registerHostedMethod(hMethod);
             }
     
    -        boolean isCFunction = aMethod.getAnnotation(CFunction.class) != null;
    -        boolean hasCFunctionOptions = aMethod.getAnnotation(CFunctionOptions.class) != null;
    +        boolean isCFunction = AnnotationUtil.getAnnotation(aMethod, CFunction.class) != null;
    +        boolean hasCFunctionOptions = AnnotationUtil.getAnnotation(aMethod, CFunctionOptions.class) != null;
             if (hasCFunctionOptions && !isCFunction) {
                 unsupportedFeatures.addMessage(aMethod.format("%H.%n(%p)"), aMethod,
                                 "Method annotated with @" + CFunctionOptions.class.getSimpleName() + " must also be annotated with @" + CFunction.class);
    @@ -581,8 +582,8 @@ private void layoutInstanceFields(HostedInstanceClass clazz, HostedField[] super
              * Sort so that in each group, Object fields are consecutive, and bigger types come first.
              */
             Object uncontendedSentinel = new Object();
    -        Object unannotatedGroup = clazz.isAnnotationPresent(Contended.class) ? new Object() : uncontendedSentinel;
    -        Function getAnnotationGroup = field -> Optional.ofNullable(field.getAnnotation(Contended.class))
    +        Object unannotatedGroup = AnnotationUtil.isAnnotationPresent(clazz, Contended.class) ? new Object() : uncontendedSentinel;
    +        Function getAnnotationGroup = field -> Optional.ofNullable(AnnotationUtil.getAnnotation(field, Contended.class))
                             .map(a -> "".equals(a.value()) ? new Object() : a.value())
                             .orElse(unannotatedGroup);
             Map> contentionGroups = rawFields.stream()
    @@ -1058,7 +1059,7 @@ private static ReferenceMapEncoder.Input createReferenceMap(HostedType type) {
         }
     
         private static boolean excludeFromReferenceMap(HostedField field) {
    -        ExcludeFromReferenceMap annotation = field.getAnnotation(ExcludeFromReferenceMap.class);
    +        ExcludeFromReferenceMap annotation = AnnotationUtil.getAnnotation(field, ExcludeFromReferenceMap.class);
             if (annotation != null) {
                 return ReflectionUtil.newInstance(annotation.onlyIf()).getAsBoolean();
             }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java
    index ffbd5030f59f..6dddaf1cb64c 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/CInterfaceInvocationPlugin.java
    @@ -29,7 +29,6 @@
     
     import java.util.Arrays;
     
    -import jdk.graal.compiler.word.Word;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.c.function.CEntryPoint;
     import org.graalvm.nativeimage.c.function.CFunctionPointer;
    @@ -63,6 +62,7 @@
     import com.oracle.svm.hosted.code.CEntryPointCallStubSupport;
     import com.oracle.svm.hosted.code.CEntryPointJavaCallStubMethod;
     import com.oracle.svm.hosted.code.CFunctionPointerCallStubSupport;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.core.common.memory.BarrierType;
     import jdk.graal.compiler.core.common.memory.MemoryOrderMode;
    @@ -94,6 +94,7 @@
     import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
     import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin;
     import jdk.graal.compiler.nodes.memory.address.OffsetAddressNode;
    +import jdk.graal.compiler.word.Word;
     import jdk.vm.ci.code.CodeUtil;
     import jdk.vm.ci.meta.JavaKind;
     import jdk.vm.ci.meta.JavaType;
    @@ -133,18 +134,22 @@ public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod m, ValueNo
                 }
             } else if (methodInfo instanceof ConstantInfo) {
                 return replaceConstant(b, method, (ConstantInfo) methodInfo);
    -        } else if (method.getAnnotation(InvokeCFunctionPointer.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(method, InvokeCFunctionPointer.class) != null) {
                 return replaceCFunctionPointerInvoke(b, method, args);
    -        } else if (method.getAnnotation(InvokeJavaFunctionPointer.class) != null) {
    -            return replaceJavaFunctionPointerInvoke(b, method, args);
    -        } else if (method.getAnnotation(CEntryPoint.class) != null) {
    -            assert !(method.getWrapped() instanceof CEntryPointJavaCallStubMethod) : "Call stub should never have a @CEntryPoint annotation";
    -            AnalysisMethod stub = CEntryPointCallStubSupport.singleton().registerJavaStubForMethod(method);
    -            assert !b.getMethod().equals(stub) : "Plugin should not be called for the invoke in the stub itself";
    -            b.handleReplacedInvoke(InvokeKind.Static, stub, args, false);
    -            return true;
             } else {
    -            return false;
    +            if (AnnotationUtil.getAnnotation(method, InvokeJavaFunctionPointer.class) != null) {
    +                return replaceJavaFunctionPointerInvoke(b, method, args);
    +            } else {
    +                if (AnnotationUtil.getAnnotation(method, CEntryPoint.class) != null) {
    +                    assert !(method.getWrapped() instanceof CEntryPointJavaCallStubMethod) : "Call stub should never have a @CEntryPoint annotation";
    +                    AnalysisMethod stub = CEntryPointCallStubSupport.singleton().registerJavaStubForMethod(method);
    +                    assert !b.getMethod().equals(stub) : "Plugin should not be called for the invoke in the stub itself";
    +                    b.handleReplacedInvoke(InvokeKind.Static, stub, args, false);
    +                    return true;
    +                } else {
    +                    return false;
    +                }
    +            }
             }
         }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java
    index ab91140b74d6..d597c1e77b44 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java
    @@ -30,6 +30,11 @@
     import java.util.List;
     import java.util.Set;
     
    +import com.oracle.svm.core.code.FactoryMethodMarker;
    +import com.oracle.svm.core.snippets.ImplicitExceptions;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.ReflectionUtil;
    +
     import jdk.graal.compiler.graph.Node;
     import jdk.graal.compiler.nodes.FixedNode;
     import jdk.graal.compiler.nodes.FrameState;
    @@ -48,13 +53,7 @@
     import jdk.graal.compiler.nodes.java.NewInstanceNode;
     import jdk.graal.compiler.nodes.spi.CoreProviders;
     import jdk.graal.compiler.phases.BasePhase;
    -
    -import com.oracle.svm.core.code.FactoryMethodMarker;
    -import com.oracle.svm.core.snippets.ImplicitExceptions;
    -import com.oracle.svm.util.ReflectionUtil;
    -
     import jdk.vm.ci.meta.ResolvedJavaMethod;
    -import org.graalvm.nativeimage.AnnotationAccess;
     
     /**
      * Code that must be allocation free cannot throw new {@link AssertionError}. Therefore we convert
    @@ -73,7 +72,7 @@ public class ImplicitAssertionsPhase extends BasePhase {
     
         @Override
         protected void run(StructuredGraph graph, CoreProviders context) {
    -        if (AnnotationAccess.isAnnotationPresent(graph.method().getDeclaringClass(), FactoryMethodMarker.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(graph.method().getDeclaringClass(), FactoryMethodMarker.class)) {
                 /*
                  * Factory methods, which includes methods in ImplicitExceptions, are the methods that
                  * actually perform the allocations at run time.
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java
    index acac1156467f..df74691fbd9c 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InjectedAccessorsPlugin.java
    @@ -33,6 +33,7 @@
     import com.oracle.graal.pointsto.meta.AnalysisType;
     import com.oracle.svm.core.annotate.InjectAccessors;
     import com.oracle.svm.core.util.VMError;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind;
     import jdk.graal.compiler.nodes.ValueNode;
    @@ -63,7 +64,7 @@ public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField f
         }
     
         private static boolean handleField(GraphBuilderContext b, AnalysisField field, boolean isStatic, ValueNode receiver, boolean isGet, ValueNode value) {
    -        InjectAccessors injectAccesors = field.getAnnotation(InjectAccessors.class);
    +        InjectAccessors injectAccesors = AnnotationUtil.getAnnotation(field, InjectAccessors.class);
             if (injectAccesors == null) {
                 return false;
             }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java
    index 050fc4d921ff..0dd0dd1333a6 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/InlineBeforeAnalysisPolicyUtils.java
    @@ -28,8 +28,6 @@
     import java.lang.reflect.Executable;
     import java.util.Set;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
    -
     import com.oracle.graal.pointsto.api.PointstoOptions;
     import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
    @@ -46,6 +44,7 @@
     import com.oracle.svm.hosted.SharedArenaSupport;
     import com.oracle.svm.hosted.code.FactoryMethodSupport;
     import com.oracle.svm.hosted.methodhandles.MethodHandleInvokerRenamingSubstitutionProcessor;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.api.replacements.Fold;
    @@ -160,7 +159,7 @@ public static class Options {
                         (Class) ReflectionUtil.lookupClass("java.lang.invoke.LambdaForm$Compiled");
     
         public static boolean isMethodHandleIntrinsificationRoot(ResolvedJavaMethod method) {
    -        return AnnotationAccess.isAnnotationPresent(method, COMPILED_LAMBDA_FORM_ANNOTATION);
    +        return AnnotationUtil.isAnnotationPresent(method, COMPILED_LAMBDA_FORM_ANNOTATION);
         }
     
         public boolean isScopedMethod(ResolvedJavaMethod method) {
    @@ -194,7 +193,7 @@ private boolean shouldInlineInvoke0(GraphBuilderContext b, SVMHost hostVM, Accum
              * other phases.
              */
             if (isScopedMethod(b.getMethod()) &&
    -                        (AnnotationAccess.isAnnotationPresent(method, AlwaysInline.class) || AnnotationAccess.isAnnotationPresent(method, ForceInline.class))) {
    +                        (AnnotationUtil.isAnnotationPresent(method, AlwaysInline.class) || AnnotationUtil.isAnnotationPresent(method, ForceInline.class))) {
                 return false;
             }
     
    @@ -248,14 +247,14 @@ public static boolean inliningAllowed(SVMHost hostVM, GraphBuilderContext b, Ana
             if (hostVM.neverInlineTrivial(caller, callee)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(callee, Fold.class) || AnnotationAccess.isAnnotationPresent(callee, Node.NodeIntrinsic.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(callee, Fold.class) || AnnotationUtil.isAnnotationPresent(callee, Node.NodeIntrinsic.class)) {
                 /*
                  * We should never see a call to such a method. But if we do, do not inline them
                  * otherwise we miss the opportunity later to report it as an error.
                  */
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(callee, RestrictHeapAccess.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(callee, RestrictHeapAccess.class)) {
                 /*
                  * This is conservative. We do not know the caller's heap restriction state yet because
                  * that can only be computed after static analysis (it relies on the call graph produced
    @@ -582,7 +581,7 @@ public String toString() {
                         ReflectionUtil.lookupMethod(ReflectionUtil.lookupClass(false, "java.lang.invoke.DirectMethodHandle$StaticAccessor"), "checkCast", Object.class));
     
         private static boolean inlineForMethodHandleIntrinsification(AnalysisMethod method) {
    -        return AnnotationAccess.isAnnotationPresent(method, ForceInline.class) ||
    +        return AnnotationUtil.isAnnotationPresent(method, ForceInline.class) ||
                             isMethodHandleIntrinsificationRoot(method) ||
                             INLINE_METHOD_HANDLE_CLASSES.contains(method.getDeclaringClass().getJavaClass()) ||
                             isManuallyListed(method.getJavaMethod());
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
    index f860340f4927..d2bf8b63d738 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
    @@ -42,14 +42,10 @@
     import java.util.List;
     import java.util.Objects;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
    -
     import com.oracle.graal.pointsto.constraints.TypeInstantiationException;
     import com.oracle.graal.pointsto.constraints.UnresolvedElementException;
     import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException;
     import com.oracle.graal.pointsto.heap.ImageHeapConstant;
    -import com.oracle.svm.util.OriginalClassProvider;
    -import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.graal.pointsto.meta.AnalysisField;
     import com.oracle.graal.pointsto.meta.AnalysisMetaAccess;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
    @@ -80,6 +76,9 @@
     import com.oracle.svm.hosted.code.SubstrateCompilationDirectives;
     import com.oracle.svm.hosted.nodes.DeoptProxyNode;
     import com.oracle.svm.hosted.substitute.SubstitutionType;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalClassProvider;
    +import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.api.replacements.Fold;
    @@ -270,10 +269,10 @@ protected void build(FixedWithNextNode startInstruction, FrameStateBuilder start
                      */
                     try {
                         graph.getDebug().dump(DebugContext.VERY_DETAILED_LEVEL, graph, "Before instrumenting @Scoped method");
    -                    if (AnnotationAccess.isAnnotationPresent(method, ForeignSupport.Scoped.class) && SharedArenaSupport.isAvailable()) {
    +                    if (AnnotationUtil.isAnnotationPresent(method, ForeignSupport.Scoped.class) && SharedArenaSupport.isAvailable()) {
                             // substituted, only add the scoped node
                             introduceScopeNodes();
    -                    } else if (AnnotationAccess.isAnnotationPresent(method, SharedArenaSupport.SCOPED_ANNOTATION) && SharedArenaSupport.isAvailable()) {
    +                    } else if (AnnotationUtil.isAnnotationPresent(method, SharedArenaSupport.SCOPED_ANNOTATION) && SharedArenaSupport.isAvailable()) {
                             // not substituted, also instrument
                             instrumentScopedMethod();
                         }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java
    index 5e9e5d4bd24b..ff93f8c13b1d 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/pltgot/HostedPLTGOTConfiguration.java
    @@ -26,25 +26,25 @@
     
     import java.lang.reflect.Method;
     
    +import org.graalvm.nativeimage.ImageSingletons;
    +import org.graalvm.nativeimage.c.function.CEntryPoint;
    +import org.graalvm.nativeimage.c.function.CFunction;
    +
    +import com.oracle.objectfile.SectionName;
     import com.oracle.svm.core.Uninterruptible;
     import com.oracle.svm.core.graal.code.ExplicitCallingConvention;
     import com.oracle.svm.core.graal.code.StubCallingConvention;
     import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind;
     import com.oracle.svm.core.jdk.InternalVMMethod;
     import com.oracle.svm.core.meta.SharedMethod;
    -import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
    -import org.graalvm.nativeimage.AnnotationAccess;
    -import org.graalvm.nativeimage.ImageSingletons;
    -
    -import com.oracle.objectfile.SectionName;
     import com.oracle.svm.core.pltgot.PLTGOTConfiguration;
    +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
     import com.oracle.svm.hosted.meta.HostedMetaAccess;
     import com.oracle.svm.hosted.meta.HostedMethod;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.vm.ci.code.Register;
     import jdk.vm.ci.code.RegisterConfig;
    -import org.graalvm.nativeimage.c.function.CEntryPoint;
    -import org.graalvm.nativeimage.c.function.CFunction;
     
     public abstract class HostedPLTGOTConfiguration extends PLTGOTConfiguration {
         public static final SectionName SVM_GOT_SECTION = new SectionName.ProgbitsSectionName("svm_got");
    @@ -65,26 +65,26 @@ public static HostedPLTGOTConfiguration singleton() {
         }
     
         public static boolean canBeCalledViaPLTGOT(SharedMethod method) {
    -        if (AnnotationAccess.isAnnotationPresent(method, CEntryPoint.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, CEntryPoint.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method, CFunction.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, CFunction.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method, StubCallingConvention.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, StubCallingConvention.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method, Uninterruptible.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, Uninterruptible.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method, SubstrateForeignCallTarget.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method, SubstrateForeignCallTarget.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), InternalVMMethod.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), InternalVMMethod.class)) {
                 return false;
             }
    -        if (AnnotationAccess.isAnnotationPresent(method, ExplicitCallingConvention.class) &&
    -                        AnnotationAccess.getAnnotation(method, ExplicitCallingConvention.class).value().equals(SubstrateCallingConventionKind.ForwardReturnValue)) {
    +        ExplicitCallingConvention ecc = AnnotationUtil.getAnnotation(method, ExplicitCallingConvention.class);
    +        if (ecc != null && ecc.value().equals(SubstrateCallingConventionKind.ForwardReturnValue)) {
                 /*
                  * Methods that use ForwardReturnValue calling convention can't be resolved with PLT/GOT
                  * on AMD64 because AMD64MethodAddressResolutionDispatcher.resolveMethodAddress uses the
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java
    index 5b50de31cb92..f8c261280784 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/snippets/SubstrateGraphBuilderPlugins.java
    @@ -38,7 +38,6 @@
     import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
     import java.util.stream.Stream;
     
    -import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageInfo;
     import org.graalvm.nativeimage.ImageSingletons;
     import org.graalvm.nativeimage.Platform;
    @@ -53,7 +52,6 @@
     import org.graalvm.word.UnsignedWord;
     
     import com.oracle.graal.pointsto.AbstractAnalysisEngine;
    -import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.graal.pointsto.meta.AnalysisType;
     import com.oracle.svm.core.ArenaIntrinsics;
     import com.oracle.svm.core.FrameAccess;
    @@ -106,6 +104,8 @@
     import com.oracle.svm.hosted.nodes.DeoptProxyNode;
     import com.oracle.svm.hosted.nodes.ReadReservedRegister;
     import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.core.common.CompressEncoding;
    @@ -1052,7 +1052,7 @@ public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Rec
         }
     
         private static void checkNeverInline(GraphBuilderContext b) {
    -        if (!AnnotationAccess.isAnnotationPresent(b.getMethod(), NeverInline.class)) {
    +        if (!AnnotationUtil.isAnnotationPresent(b.getMethod(), NeverInline.class)) {
                 throw VMError.shouldNotReachHere("Accessing the stack pointer or instruction pointer of the caller frame is only safe and deterministic if the method is not inlined. " +
                                 "Therefore, the method " + b.getMethod().format("%H.%n(%p)") + " must be annotated with @" + NeverInline.class.getSimpleName());
             }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java
    index c4a89a6c3f80..0ad0c3c0a279 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java
    @@ -28,9 +28,9 @@
     import java.lang.reflect.AnnotatedElement;
     import java.util.List;
     
    -import com.oracle.svm.util.OriginalFieldProvider;
     import com.oracle.svm.hosted.annotation.AnnotationWrapper;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalFieldProvider;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.vm.ci.meta.JavaConstant;
    @@ -45,7 +45,7 @@ public class AnnotatedField implements ResolvedJavaField, OriginalFieldProvider,
     
         public AnnotatedField(ResolvedJavaField original, Annotation injectedAnnotation) {
             this.original = original;
    -        this.injectedAnnotations = SubstrateAnnotationExtractor.prepareInjectedAnnotations(injectedAnnotation);
    +        this.injectedAnnotations = List.of(AnnotationUtil.asAnnotationValue(injectedAnnotation));
         }
     
         @Override
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java
    index 2c14e778804d..939d5b447714 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java
    @@ -27,18 +27,19 @@
     import java.lang.annotation.Annotation;
     import java.lang.reflect.AnnotatedElement;
     import java.lang.reflect.Type;
    +import java.util.ArrayList;
     import java.util.Arrays;
     import java.util.List;
     
     import org.graalvm.nativeimage.AnnotationAccess;
     
     import com.oracle.graal.pointsto.infrastructure.GraphProvider;
    -import com.oracle.svm.util.OriginalMethodProvider;
     import com.oracle.graal.pointsto.meta.AnalysisMethod;
     import com.oracle.graal.pointsto.meta.HostedProviders;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.annotation.AnnotationWrapper;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalMethodProvider;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
     import jdk.graal.compiler.debug.DebugContext;
    @@ -63,7 +64,7 @@ public class AnnotatedMethod implements ResolvedJavaMethod, GraphProvider, Origi
         public AnnotatedMethod(ResolvedJavaMethod original, ResolvedJavaMethod annotated) {
             this.original = original;
             this.annotated = annotated;
    -        this.injectedAnnotations = SubstrateAnnotationExtractor.prepareInjectedAnnotations(annotated.getDeclaredAnnotations());
    +        this.injectedAnnotations = new ArrayList<>(AnnotationUtil.getDeclaredAnnotationValues(annotated).values());
         }
     
         public ResolvedJavaMethod getOriginal() {
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
    index 2075422d780d..6fab10d5ae62 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java
    @@ -88,6 +88,7 @@
     import com.oracle.svm.hosted.ameta.FieldValueInterceptionSupport;
     import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
     import com.oracle.svm.hosted.meta.HostedUniverse;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError;
     
    @@ -263,7 +264,7 @@ public boolean hasInjectAccessors(ResolvedJavaField field) {
         private boolean isAnnotationPresent(ResolvedJavaField field, Class annotationClass) {
             ResolvedJavaField substitutionField = fieldSubstitutions.get(field);
             if (substitutionField != null) {
    -            return AnnotationAccess.isAnnotationPresent(substitutionField, annotationClass);
    +            return AnnotationUtil.isAnnotationPresent(substitutionField, annotationClass);
             }
             return false;
         }
    @@ -346,7 +347,7 @@ public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
         public void registerUnsafeAccessedFields(BigBang bb) {
             for (var entry : unsafeAccessedFields.entrySet()) {
                 AnalysisField targetField = bb.getMetaAccess().lookupJavaField(entry.getKey());
    -            assert !AnnotationAccess.isAnnotationPresent(targetField, Delete.class);
    +            assert !AnnotationUtil.isAnnotationPresent(targetField, Delete.class);
                 targetField.registerAsUnsafeAccessed(entry.getValue());
             }
             /* Prevent later additions that would go unnoticed. */
    @@ -500,7 +501,7 @@ private void handleMethodInAliasClass(Executable annotatedMethod, Class origi
                 }
                 registerAsDeleted(annotated, original, deleteAnnotation);
             } else if (substituteAnnotation != null) {
    -            if (AnnotationAccess.isAnnotationPresent(annotated, Uninterruptible.class) && !isEffectivelyFinal(original)) {
    +            if (AnnotationUtil.isAnnotationPresent(annotated, Uninterruptible.class) && !isEffectivelyFinal(original)) {
                     throw UserError.abort("@Uninterruptible may only be combined with @Substitute if the original method is effectively final: %s", annotatedMethod);
                 }
     
    @@ -510,7 +511,7 @@ private void handleMethodInAliasClass(Executable annotatedMethod, Class origi
                 }
                 register(methodSubstitutions, annotated, original, substitution);
             } else if (annotateOriginalAnnotation != null) {
    -            if (AnnotationAccess.isAnnotationPresent(annotated, Uninterruptible.class) && !isEffectivelyFinal(original)) {
    +            if (AnnotationUtil.isAnnotationPresent(annotated, Uninterruptible.class) && !isEffectivelyFinal(original)) {
                     throw UserError.abort("@Uninterruptible may only be combined with @AnnotateOriginal if the original method is effectively final: %s", annotatedMethod);
                 }
     
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java
    index 19611fd151fe..7378952e4523 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedFieldsPlugin.java
    @@ -24,15 +24,15 @@
      */
     package com.oracle.svm.hosted.substitute;
     
    +import com.oracle.svm.core.annotate.Delete;
    +import com.oracle.svm.util.AnnotationUtil;
    +
     import jdk.graal.compiler.nodes.CallTargetNode.InvokeKind;
     import jdk.graal.compiler.nodes.ConstantNode;
     import jdk.graal.compiler.nodes.DeadEndNode;
     import jdk.graal.compiler.nodes.ValueNode;
     import jdk.graal.compiler.nodes.graphbuilderconf.GraphBuilderContext;
     import jdk.graal.compiler.nodes.graphbuilderconf.NodePlugin;
    -
    -import com.oracle.svm.core.annotate.Delete;
    -
     import jdk.vm.ci.meta.ResolvedJavaField;
     import jdk.vm.ci.meta.ResolvedJavaMethod;
     
    @@ -59,7 +59,7 @@ public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField f
         }
     
         private static boolean handleField(GraphBuilderContext b, ResolvedJavaField field, @SuppressWarnings("unused") boolean isLoad) {
    -        Delete deleteAnnotation = field.getAnnotation(Delete.class);
    +        Delete deleteAnnotation = AnnotationUtil.getAnnotation(field, Delete.class);
             if (deleteAnnotation == null) {
                 return false;
             }
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java
    index 5d5bed31a6c6..fc923407703f 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/DeletedMethod.java
    @@ -34,8 +34,8 @@
     import com.oracle.svm.core.option.SubstrateOptionsParser;
     import com.oracle.svm.core.util.VMError;
     import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod;
    -import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor;
     import com.oracle.svm.hosted.phases.HostedGraphKit;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.ReflectionUtil;
     
     import jdk.graal.compiler.annotation.AnnotationValue;
    @@ -59,7 +59,7 @@ public class DeletedMethod extends CustomSubstitutionMethod {
         public DeletedMethod(ResolvedJavaMethod original, Delete deleteAnnotation) {
             super(original);
             this.message = deleteAnnotation.value();
    -        this.injectedAnnotations = SubstrateAnnotationExtractor.prepareInjectedAnnotations(deleteAnnotation);
    +        this.injectedAnnotations = List.of(AnnotationUtil.asAnnotationValue(deleteAnnotation));
         }
     
         @Override
    diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionReflectivityFilter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionReflectivityFilter.java
    index 655202c26473..fa50ac85bf5f 100644
    --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionReflectivityFilter.java
    +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionReflectivityFilter.java
    @@ -41,6 +41,7 @@
     import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature;
     import com.oracle.svm.core.feature.InternalFeature;
     import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl;
    +import com.oracle.svm.util.AnnotationUtil;
     
     import jdk.graal.compiler.api.replacements.Fold;
     import jdk.vm.ci.meta.ResolvedJavaType;
    @@ -83,7 +84,7 @@ public boolean shouldExclude(Class classObj) {
                 ResolvedJavaType analysisClass = metaAccess.lookupJavaType(classObj);
                 if (!hostVM.platformSupported(analysisClass)) {
                     return true;
    -            } else if (analysisClass.isAnnotationPresent(Delete.class)) {
    +            } else if (AnnotationUtil.isAnnotationPresent(analysisClass, Delete.class)) {
                     return true; // accesses would fail at runtime
                 }
             } catch (UnsupportedFeatureException ignored) {
    @@ -103,11 +104,11 @@ public boolean shouldExclude(Executable method) {
                 AnalysisMethod aMethod = metaAccess.lookupJavaMethod(method);
                 if (!hostVM.platformSupported(aMethod)) {
                     return true;
    -            } else if (aMethod.isAnnotationPresent(Delete.class)) {
    +            } else if (AnnotationUtil.isAnnotationPresent(aMethod, Delete.class)) {
                     return true; // accesses would fail at runtime
    -            } else if (aMethod.isAnnotationPresent(Fold.class)) {
    +            } else if (AnnotationUtil.isAnnotationPresent(aMethod, Fold.class)) {
                     return true; // accesses can contain hosted elements
    -            } else if (aMethod.isSynthetic() && aMethod.getDeclaringClass().isAnnotationPresent(TargetClass.class)) {
    +            } else if (aMethod.isSynthetic() && AnnotationUtil.isAnnotationPresent(aMethod.getDeclaringClass(), TargetClass.class)) {
                     /*
                      * Synthetic methods are usually methods injected by javac to provide access to
                      * private fields or methods (access$NNN). In substitution classes, the referenced
    @@ -135,7 +136,7 @@ public boolean shouldExclude(Field field) {
                 if (!hostVM.platformSupported(aField)) {
                     return true;
                 }
    -            if (aField.isAnnotationPresent(Delete.class) || aField.isAnnotationPresent(InjectAccessors.class)) {
    +            if (AnnotationUtil.isAnnotationPresent(aField, Delete.class) || AnnotationUtil.isAnnotationPresent(aField, InjectAccessors.class)) {
                     return true; // accesses would fail at runtime
                 }
             } catch (UnsupportedFeatureException ignored) {
    diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/HostedTruffleConstantFieldProvider.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/HostedTruffleConstantFieldProvider.java
    index fde2fdbb8ab7..16665e58a292 100644
    --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/HostedTruffleConstantFieldProvider.java
    +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/HostedTruffleConstantFieldProvider.java
    @@ -27,6 +27,7 @@
     import org.graalvm.nativeimage.Platform;
     import org.graalvm.nativeimage.Platforms;
     
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
     import com.oracle.truffle.api.nodes.Node.Child;
     import com.oracle.truffle.api.nodes.Node.Children;
    @@ -62,7 +63,9 @@ public HostedTruffleConstantFieldProvider(ConstantFieldProvider wrappedConstantF
          */
         @Override
         public  T readConstantField(ResolvedJavaField field, ConstantFieldTool tool) {
    -        boolean hasTruffleFoldedAnnotation = field.isAnnotationPresent(CompilationFinal.class) || field.isAnnotationPresent(Child.class) || field.isAnnotationPresent(Children.class);
    +        boolean hasTruffleFoldedAnnotation = AnnotationUtil.isAnnotationPresent(field, CompilationFinal.class) ||
    +                        AnnotationUtil.isAnnotationPresent(field, Child.class) ||
    +                        AnnotationUtil.isAnnotationPresent(field, Children.class);
             if (hasTruffleFoldedAnnotation) {
                 return null;
             }
    diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java
    index 588abe8afb80..b3e60e045a13 100644
    --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java
    +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleBaseFeature.java
    @@ -66,7 +66,6 @@
     import java.util.function.Consumer;
     import java.util.stream.Stream;
     
    -import com.oracle.svm.util.OriginalClassProvider;
     import org.graalvm.collections.Pair;
     import org.graalvm.home.HomeFinder;
     import org.graalvm.home.Version;
    @@ -116,6 +115,8 @@
     import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport;
     import com.oracle.svm.hosted.heap.PodSupport;
     import com.oracle.svm.hosted.snippets.SubstrateGraphBuilderPlugins;
    +import com.oracle.svm.util.AnnotationUtil;
    +import com.oracle.svm.util.OriginalClassProvider;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.truffle.api.CompilerAsserts;
     import com.oracle.truffle.api.CompilerDirectives;
    @@ -958,7 +959,7 @@ public void accept(DuringAnalysisAccess t, Class u) {
          * @see #registerTruffleLibrariesAsInHeap
          */
         private void initializeTruffleLibrariesAtBuildTime(DuringAnalysisAccessImpl access, AnalysisType type) {
    -        if (type.isAnnotationPresent(GenerateLibrary.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(type, GenerateLibrary.class)) {
                 /* Eagerly resolve library type. */
                 LibraryFactory factory = LibraryFactory.resolve(type.getJavaClass().asSubclass(Library.class));
                 /* Trigger computation of uncachedDispatch. */
    @@ -966,7 +967,7 @@ private void initializeTruffleLibrariesAtBuildTime(DuringAnalysisAccessImpl acce
                 /* Manually rescan the field since this is during analysis. */
                 access.rescanField(factory, uncachedDispatchField, scanReason);
             }
    -        if (type.isAnnotationPresent(ExportLibrary.class) || type.isAnnotationPresent(ExportLibrary.Repeat.class)) {
    +        if (AnnotationUtil.isAnnotationPresent(type, ExportLibrary.class) || AnnotationUtil.isAnnotationPresent(type, ExportLibrary.Repeat.class)) {
                 /* Eagerly resolve receiver type. */
                 invokeStaticMethod("com.oracle.truffle.api.library.LibraryFactory$ResolvedDispatch", "lookup",
                                 Collections.singleton(Class.class), type.getJavaClass());
    diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
    index 0b7cebb03de4..16336fb96c32 100644
    --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
    +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleFeature.java
    @@ -100,7 +100,6 @@
     import java.util.function.ToLongFunction;
     import java.util.function.UnaryOperator;
     
    -import com.oracle.truffle.api.impl.DefaultTruffleRuntime;
     import org.graalvm.collections.Pair;
     import org.graalvm.nativeimage.AnnotationAccess;
     import org.graalvm.nativeimage.ImageSingletons;
    @@ -142,6 +141,7 @@
     import com.oracle.svm.truffle.api.SubstrateTruffleCompiler;
     import com.oracle.svm.truffle.api.SubstrateTruffleRuntime;
     import com.oracle.svm.truffle.api.SubstrateTruffleUniverseFactory;
    +import com.oracle.svm.util.AnnotationUtil;
     import com.oracle.svm.util.LogUtils;
     import com.oracle.svm.util.ReflectionUtil;
     import com.oracle.svm.util.StringUtil;
    @@ -152,6 +152,7 @@
     import com.oracle.truffle.api.Truffle;
     import com.oracle.truffle.api.TruffleRuntime;
     import com.oracle.truffle.api.frame.Frame;
    +import com.oracle.truffle.api.impl.DefaultTruffleRuntime;
     import com.oracle.truffle.api.nodes.BytecodeOSRNode;
     import com.oracle.truffle.api.nodes.ExplodeLoop;
     import com.oracle.truffle.api.nodes.RootNode;
    @@ -489,13 +490,13 @@ public RuntimeCompilationFeature.AllowInliningPredicate.InlineDecision allowInli
                     return INLINING_DISALLOWED;
                 } else if (invocationPlugins.lookupInvocation(target, builder.getOptions()) != null) {
                     return INLINING_DISALLOWED;
    -            } else if (target.getAnnotation(ExplodeLoop.class) != null) {
    +            } else if (AnnotationUtil.getAnnotation(target, ExplodeLoop.class) != null) {
                     /*
                      * We cannot inline a method annotated with @ExplodeLoop, because then loops are no
                      * longer exploded.
                      */
                     return INLINING_DISALLOWED;
    -            } else if (builder.getMethod().getAnnotation(ExplodeLoop.class) != null) {
    +            } else if (AnnotationUtil.getAnnotation(builder.getMethod(), ExplodeLoop.class) != null) {
                     /*
                      * We cannot inline anything into a method annotated with @ExplodeLoop, because then
                      * loops of the inlined callee are exploded too.
    @@ -547,7 +548,7 @@ private boolean allowRuntimeCompilation(ResolvedJavaMethod method) {
         }
     
         private static boolean runtimeCompilationForbidden(ResolvedJavaMethod method) {
    -        if (method.getAnnotation(CompilerDirectives.TruffleBoundary.class) != null) {
    +        if (AnnotationUtil.getAnnotation(method, TruffleBoundary.class) != null) {
                 return true;
             } else if (Uninterruptible.Utils.isUninterruptible(method)) {
                 Uninterruptible uninterruptibleAnnotation = Uninterruptible.Utils.getAnnotation(method);
    @@ -558,7 +559,7 @@ private static boolean runtimeCompilationForbidden(ResolvedJavaMethod method) {
             }
             if (!method.canBeInlined()) {
                 return true;
    -        } else if (method.getAnnotation(TruffleCallBoundary.class) != null) {
    +        } else if (AnnotationUtil.getAnnotation(method, TruffleCallBoundary.class) != null) {
                 return true;
             }
             return false;
    @@ -577,7 +578,7 @@ private boolean deoptimizeOnException(ResolvedJavaMethod method) {
             if (method == null) {
                 return false;
             }
    -        CompilerDirectives.TruffleBoundary truffleBoundary = method.getAnnotation(CompilerDirectives.TruffleBoundary.class);
    +        TruffleBoundary truffleBoundary = AnnotationUtil.getAnnotation(method, TruffleBoundary.class);
             return truffleBoundary != null && truffleBoundary.transferToInterpreterOnException();
         }
     
    @@ -1040,7 +1041,7 @@ public void afterAnalysis(AfterAnalysisAccess access) {
                     if (!(method instanceof AnalysisMethod)) {
                         throw VMError.shouldNotReachHere("method should be an analysis method");
                     }
    -                if (method.getAnnotation(TruffleBoundary.class) != null) {
    +                if (AnnotationUtil.getAnnotation(method, TruffleBoundary.class) != null) {
                         throw VMError.shouldNotReachHere("method used during runtime compilation must never be annotated with a truffle boundary");
                     }
                     runtimeCompiledMethods.add((AnalysisMethod) method);
    @@ -1054,7 +1055,7 @@ private static void printStaticTruffleBoundaries(CallTreeInfo treeInfo) {
             int calleeCount = 0;
             for (RuntimeCompiledMethod runtimeCompiledMethod : treeInfo.runtimeCompilations()) {
                 for (ResolvedJavaMethod targetMethod : runtimeCompiledMethod.getInvokeTargets()) {
    -                TruffleBoundary truffleBoundary = targetMethod.getAnnotation(TruffleBoundary.class);
    +                TruffleBoundary truffleBoundary = AnnotationUtil.getAnnotation(targetMethod, TruffleBoundary.class);
                     if (truffleBoundary != null) {
                         ++callSiteCount;
                         if (foundBoundaries.contains(targetMethod)) {
    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
    new file mode 100644
    index 000000000000..a1c1ba0b40b2
    --- /dev/null
    +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationUtil.java
    @@ -0,0 +1,221 @@
    +/*
    + * Copyright (c) 2025, 2025, 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.util;
    +
    +import java.lang.annotation.Annotation;
    +import java.lang.reflect.AnnotatedElement;
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.function.Function;
    +
    +import org.graalvm.nativeimage.ImageInfo;
    +import org.graalvm.nativeimage.ImageSingletons;
    +import org.graalvm.nativeimage.impl.AnnotationExtractor;
    +
    +import jdk.graal.compiler.annotation.AnnotationValue;
    +import jdk.graal.compiler.annotation.AnnotationValueType;
    +import jdk.graal.compiler.annotation.EnumElement;
    +import jdk.graal.compiler.util.EconomicHashMap;
    +import jdk.vm.ci.meta.ResolvedJavaType;
    +import jdk.vm.ci.meta.UnresolvedJavaType;
    +import jdk.vm.ci.meta.annotation.Annotated;
    +
    +/**
    + * 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.
    + */
    +public final class AnnotationUtil {
    +
    +    /**
    +     * Annotation related functionality that is in terms of {@link Annotated} instead of
    +     * {@link java.lang.reflect.AnnotatedElement}. This interface must be implemented by the
    +     * registered {@link AnnotationExtractor} image singleton.
    +     */
    +    public interface Access {
    +        /**
    +         * Retrieves the annotation of type {@code annotationType} from the given {@code element}.
    +         *
    +         * @param element the annotated element to retrieve the annotation value from
    +         * @param annotationType the type of annotation to retrieve
    +         * @return the annotation value of the specified type, or null if no such annotation exists
    +         */
    +         T getAnnotation(Annotated element, Class annotationType);
    +
    +        /**
    +         * Gets the declared annotations of {@code annotated}.
    +         */
    +        Map getDeclaredAnnotationValues(Annotated element);
    +
    +        /**
    +         * Converts an {@link AnnotationValue} to an {@link Annotation} of type
    +         * {@code annotationType}.
    +         */
    +         T asAnnotation(AnnotationValue annotationValue, Class annotationType);
    +
    +        /**
    +         * Converts an {@link Annotation} to an {@link AnnotationValue}.
    +         */
    +        AnnotationValue asAnnotationValue(Annotation annotation);
    +    }
    +
    +    private static Access access() {
    +        return (Access) ImageSingletons.lookup(AnnotationExtractor.class);
    +    }
    +
    +    /**
    +     * Converts an {@link Annotation} to an {@link AnnotationValue}.
    +     */
    +    public static AnnotationValue asAnnotationValue(Annotation annotation) {
    +        return access().asAnnotationValue(annotation);
    +    }
    +
    +    /**
    +     * Gets the declared annotations of {@code annotated}.
    +     */
    +    public static Map getDeclaredAnnotationValues(Annotated annotated) {
    +        return access().getDeclaredAnnotationValues(annotated);
    +    }
    +
    +    /**
    +     * Gets the annotation of type {@code annotationType} from {@code element} if such an annotation
    +     * is present, else null.
    +     */
    +    public static  T getAnnotation(Annotated element, Class annotationType) {
    +        // Checkstyle: allow direct annotation access
    +        if (ImageInfo.inImageBuildtimeCode()) {
    +            return access().getAnnotation(element, annotationType);
    +        } else {
    +            return ((AnnotatedElement) element).getAnnotation(annotationType);
    +        }
    +        // Checkstyle: disallow direct annotation access
    +    }
    +
    +    /**
    +     * Retrieves the annotations of type {@code annotationClass} from the given {@code element},
    +     * including both direct annotations and those contained within a container annotation of type
    +     * {@code containerClass}.
    +     * 

    + * Unlike {@link AnnotatedElement#getAnnotationsByType}, this method does not initialize all + * annotation classes and their dependencies, making it suitable for use during image build + * time. + *

    + * The order of annotations returned by this method differs from that of + * {@link AnnotatedElement#getAnnotationsByType}: direct annotations are always returned first, + * followed by container annotations. + *

    + * To avoid complex reflective lookups, information about the container annotation must be + * provided through the {@code containerClass} and {@code valueFunction} parameters. + * + * @param element the annotated element to retrieve annotations from + * @param annotationClass the type of annotation to retrieve + * @param containerClass the type of container annotation that may contain the desired + * annotations + * @param valueFunction a function that extracts the desired annotations from a container + * annotation + * @return a list of annotations of type {@code annotationClass} found on the given element + */ + public static List getAnnotationsByType(Annotated element, + Class annotationClass, Class containerClass, Function valueFunction) { + + List result = new ArrayList<>(); + A direct = getAnnotation(element, annotationClass); + if (direct != null) { + result.add(direct); + } + C container = getAnnotation(element, containerClass); + if (container != null) { + result.addAll(List.of(valueFunction.apply(container))); + } + return result; + } + + /** + * Determines if an annotation of type {@code annotationType} is present on {@code element}. + */ + public static boolean isAnnotationPresent(Annotated element, Class annotationType) { + return getAnnotation(element, annotationType) != null; + } + + /** + * Creates an {@link Annotation} for the given annotation type and element values. + * + * @param elements a sequence of (name,value) pairs where each name must denote an existing + * element of the annotation type and the value must have the right type according to + * {@link AnnotationValueType#matchesElementType}. Note that {@link Enum} and + * {@link Class} values are automatically converted to {@link EnumElement} and + * {@link ResolvedJavaType} values respectively. + */ + public static T newAnnotation(Class annotationType, Object... elements) { + return access().asAnnotation(newAnnotationValue(annotationType, elements), annotationType); + } + + /** + * Creates an {@link AnnotationValue} for the given annotation type and element values. + * + * @param elements a sequence of (name,value) pairs where name must denote an existing element + * of the annotation type and value must have a type according to + * {@link AnnotationValueType#matchesElementType}. Note that {@link Enum} and + * {@link Class} values are automatically converted to {@link EnumElement} and + * {@link ResolvedJavaType} values respectively. + */ + public static AnnotationValue newAnnotationValue(Class annotationType, Object... elements) { + if ((elements.length % 2) != 0) { + throw new IllegalArgumentException("Elements must be a sequence of (name,value) pairs"); + } + ResolvedJavaType jvmciAnnotationType = GraalAccess.lookupType(annotationType); + AnnotationValueType annotationValueType = AnnotationValueType.getInstance(jvmciAnnotationType); + var elementTypes = annotationValueType.memberTypes(); + Map elementsMap = new EconomicHashMap<>(annotationValueType.memberDefaults()); + for (int i = 0; i < elements.length; i += 2) { + if (!(elements[i] instanceof String name)) { + throw new IllegalArgumentException(String.format("entry %d of elements is not a String: %s", i, elements[i])); + } + Object elementValue = elements[i + 1]; + if (elementValue == null) { + throw new IllegalArgumentException(String.format("entry %d of elements is null", i)); + } + ResolvedJavaType elementType = elementTypes.get(name); + if (elementType == null) { + throw new IllegalArgumentException(String.format("%s does not define an element named %s", annotationType.getName(), name)); + } + if (elementValue instanceof Class c) { + String internalName = "L" + c.getName().replace(".", "/") + ";"; + elementValue = UnresolvedJavaType.create(internalName).resolve(jvmciAnnotationType); + } else if (elementValue instanceof Enum e) { + String internalName = "L" + e.getClass().getName().replace(".", "/") + ";"; + ResolvedJavaType enumType = UnresolvedJavaType.create(internalName).resolve(jvmciAnnotationType); + elementValue = new EnumElement(enumType, e.name()); + } + if (!AnnotationValueType.matchesElementType(elementValue, elementType)) { + throw new IllegalArgumentException(String.format("element '%s' is not of type %s: %s", name, elementType.toJavaName(), elementValue)); + } + elementsMap.put(name, elementValue); + } + return new AnnotationValue(jvmciAnnotationType, elementsMap); + } +} diff --git a/web-image/mx.web-image/suite.py b/web-image/mx.web-image/suite.py index f8baadbc0029..b8671b08bc05 100644 --- a/web-image/mx.web-image/suite.py +++ b/web-image/mx.web-image/suite.py @@ -187,7 +187,13 @@ ], "requiresConcealed": { "java.base": ["sun.nio.ch", "sun.security.provider", "jdk.internal.reflect"], - "jdk.internal.vm.ci": ["jdk.vm.ci.code.site", "jdk.vm.ci.code", "jdk.vm.ci.common", "jdk.vm.ci.meta"], + "jdk.internal.vm.ci": [ + "jdk.vm.ci.code.site", + "jdk.vm.ci.code", + "jdk.vm.ci.common", + "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", + ], }, "javaCompliance": "21+", "spotbugs": "false", # depends on SVM which has compliance level 24 which SpotBugs does not support @@ -249,6 +255,7 @@ "requiresConcealed": { "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", ], }, "javaCompliance": "21+", diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java index e4a0646fe2cc..e62a38d8a8d4 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageFeature.java @@ -37,12 +37,11 @@ import java.util.function.Predicate; import java.util.function.Supplier; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.Platforms; +import org.graalvm.nativeimage.dynamicaccess.AccessCondition; import org.graalvm.nativeimage.hosted.Feature; import org.graalvm.nativeimage.hosted.RuntimeReflection; -import org.graalvm.nativeimage.dynamicaccess.AccessCondition; import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; import org.graalvm.nativeimage.impl.RuntimeJNIAccessSupport; import org.graalvm.nativeimage.impl.RuntimeSystemPropertiesSupport; @@ -93,6 +92,7 @@ import com.oracle.svm.hosted.webimage.options.WebImageOptions; import com.oracle.svm.hosted.webimage.snippets.WebImageNonSnippetLowerings; import com.oracle.svm.hosted.webimage.wasm.WasmLogHandler; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.webimage.WebImageSystemPropertiesSupport; import com.oracle.svm.webimage.api.Nothing; @@ -341,6 +341,6 @@ private boolean neverInlineTrivial(@SuppressWarnings("unused") AnalysisMethod ca /* * Methods annotated with @JS are never trivial. */ - return AnnotationAccess.isAnnotationPresent(callee, JS.class); + return AnnotationUtil.isAnnotationPresent(callee, JS.class); } } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java index 334bfe2f1f80..855bb7013187 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSBodyFeature.java @@ -26,7 +26,6 @@ import java.lang.reflect.Modifier; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.Platforms; import org.graalvm.webimage.api.JS; import org.graalvm.webimage.api.JSObject; @@ -44,6 +43,7 @@ import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.webimage.codegen.oop.ClassWithMirrorLowerer; import com.oracle.svm.hosted.webimage.js.JSObjectAccessMethodSupport; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.webimage.api.Nothing; import com.oracle.svm.webimage.platform.WebImageJSPlatform; @@ -77,7 +77,7 @@ public void registerGraphBuilderPlugins(Providers providers, GraphBuilderConfigu plugins.appendNodePlugin(new NodePlugin() { @Override public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { - if (AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), JS.Import.class)) { + if (AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), JS.Import.class)) { ((AnalysisType) method.getDeclaringClass()).registerAsInstantiated("JS.Import classes might be allocated in JavaScript. We need to tell the static analysis about that"); } return false; diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSCodeGenTool.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSCodeGenTool.java index 91dee22f0073..e34dfedb83fd 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSCodeGenTool.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/JSCodeGenTool.java @@ -34,7 +34,6 @@ import org.graalvm.collections.EconomicMap; import org.graalvm.collections.EconomicSet; import org.graalvm.collections.MapCursor; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.webimage.api.JSValue; import com.oracle.svm.core.option.HostedOptionValues; @@ -45,6 +44,7 @@ import com.oracle.svm.hosted.webimage.js.JSBody; import com.oracle.svm.hosted.webimage.js.JSKeyword; import com.oracle.svm.hosted.webimage.options.WebImageOptions; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.webimage.annotation.WebImage; import com.oracle.svm.webimage.hightiercodegen.CodeGenTool; import com.oracle.svm.webimage.hightiercodegen.Emitter; @@ -169,7 +169,7 @@ public void genMethodHeader(StructuredGraph graph, ResolvedJavaMethod m, List includedPaths = new HashSet<>(); codeBuffer.emitNewLine(); for (HostedType type : getProviders().typeControl().emittedTypes()) { - var includes = AnnotationUtil.getDeclaredAnnotationsByType(type, JS.Code.Include.class, JS.Code.Include.Group.class, JS.Code.Include.Group::value); + var includes = AnnotationUtil.getAnnotationsByType(type, JS.Code.Include.class, JS.Code.Include.Group.class, JS.Code.Include.Group::value); for (JS.Code.Include include : includes) { String path = include.value(); if (includedPaths.contains(path)) { @@ -283,7 +283,7 @@ protected void emitJSCodeFiles() { } lowerJavaScriptCode(codeBuffer, titleComment, is); } - var code = type.getDeclaredAnnotation(JS.Code.class); + var code = AnnotationUtil.getAnnotation(type, JS.Code.class); if (code != null) { String titleComment = "// Class file: " + type.getJavaClass().getName(); lowerJavaScriptCode(codeBuffer, titleComment, new ByteArrayInputStream(code.value().getBytes(StandardCharsets.UTF_8))); @@ -334,7 +334,7 @@ private void registerTypes() { private void requestJSObjectSubclasses(HostedType type) { // Only explicitly exported classes must be emitted. - if (type.getJavaClass().equals(JSObject.class) || type.getAnnotation(JS.Export.class) != null) { + if (type.getJavaClass().equals(JSObject.class) || AnnotationUtil.getAnnotation(type, JS.Export.class) != null) { typeControl.requestTypeName(type); } for (HostedType subtype : type.getSubTypes()) { diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassLowerer.java index f81c451e35f5..78e74df1de5f 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassLowerer.java @@ -54,9 +54,9 @@ import com.oracle.svm.hosted.webimage.metrickeys.ImageBreakdownMetricKeys; import com.oracle.svm.hosted.webimage.metrickeys.MethodMetricKeys; import com.oracle.svm.hosted.webimage.options.WebImageOptions; -import com.oracle.svm.hosted.webimage.util.AnnotationUtil; import com.oracle.svm.hosted.webimage.util.metrics.CodeSizeCollector; import com.oracle.svm.hosted.webimage.util.metrics.MethodMetricsCollector; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.webimage.hightiercodegen.CodeBuffer; import jdk.graal.compiler.core.common.cfg.BlockMap; @@ -301,14 +301,15 @@ public static void addResourceProvider(Function reso * Emits a static method on the given type for initializing JS resource, if any are present. */ private static void lowerJSResources(HostedType type, JSCodeGenTool loweringTool) { - var requiredJSResources = AnnotationUtil.getDeclaredAnnotationsByType(type, JSResource.class, JSResource.Group.class, JSResource.Group::value); + var requiredJSResources = AnnotationUtil.getAnnotationsByType(type, JSResource.class, JSResource.Group.class, JSResource.Group::value); /* * JavaScriptResource is annotated as @Repeatable(JavaScriptResource.Group.class). * getDeclaredAnnotationsByType() must detect @Repeatable and thus also look for * JavaScriptResource.Group. */ - assert requiredJSResources.size() != 0 || !type.isAnnotationPresent(JSResource.Group.class) : "Repeated annotation not detected by getDeclaredAnnotationsByType"; + assert !requiredJSResources.isEmpty() || + !AnnotationUtil.isAnnotationPresent(type, JSResource.Group.class) : "Repeated annotation not detected by getDeclaredAnnotationsByType"; List resourceNames = new ArrayList<>(requiredJSResources.size()); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassWithMirrorLowerer.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassWithMirrorLowerer.java index ba02f34e8093..7f151005c94f 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassWithMirrorLowerer.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/codegen/oop/ClassWithMirrorLowerer.java @@ -37,7 +37,6 @@ import org.graalvm.webimage.api.JS; import org.graalvm.webimage.api.JSObject; -import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; import com.oracle.svm.hosted.meta.HostedClass; import com.oracle.svm.hosted.meta.HostedField; @@ -52,6 +51,8 @@ import com.oracle.svm.hosted.webimage.snippets.JSSnippet; import com.oracle.svm.hosted.webimage.snippets.JSSnippets; import com.oracle.svm.hosted.webimage.util.metrics.MethodMetricsCollector; +import com.oracle.svm.util.AnnotationUtil; +import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.webimage.hightiercodegen.CodeBuffer; import jdk.graal.compiler.debug.DebugContext; @@ -186,9 +187,9 @@ public class ClassWithMirrorLowerer extends ClassLowerer { public ClassWithMirrorLowerer(OptionValues options, DebugContext debug, JSCodeGenTool jsLTools, Map methodGraphs, Labeler labeler, MethodMetricsCollector methodMetricsCollector, Consumer compiledMethodBytesCounter, HostedType type) { super(options, debug, jsLTools, methodGraphs, labeler, methodMetricsCollector, compiledMethodBytesCounter, type); - this.isImportedClass = type.isAnnotationPresent(JS.Import.class); - this.isSourceIncluded = type.isAnnotationPresent(JS.Code.Include.class) || type.isAnnotationPresent(JS.Code.class); - this.isDirectSubclassOfImport = type.getSuperclass().isAnnotationPresent(JS.Import.class); + this.isImportedClass = AnnotationUtil.isAnnotationPresent(type, JS.Import.class); + this.isSourceIncluded = AnnotationUtil.isAnnotationPresent(type, JS.Code.Include.class) || AnnotationUtil.isAnnotationPresent(type, JS.Code.class); + this.isDirectSubclassOfImport = AnnotationUtil.isAnnotationPresent(type.getSuperclass(), JS.Import.class); this.isSubclassOfImport = isSubclassOfImport(type); this.externClassDescriptor = null; } @@ -213,7 +214,7 @@ private boolean needExternDeclaration() { } private static boolean isSubclassOfImport(HostedType type) { - return type != null && (type.isAnnotationPresent(JS.Import.class) || isSubclassOfImport(type.getSuperclass())); + return type != null && (AnnotationUtil.isAnnotationPresent(type, JS.Import.class) || isSubclassOfImport(type.getSuperclass())); } public static boolean isJSObjectSubtype(Class cls) { @@ -286,7 +287,7 @@ protected void lowerPreamble(JSCodeGenTool tool) { buffer.emitNewLine(); buffer.emitNewLine(); - if (type.getAnnotation(JS.Export.class) != null) { + if (AnnotationUtil.getAnnotation(type, JS.Export.class) != null) { genJavaScriptExportMirrorClassDefinition(); } } @@ -451,7 +452,7 @@ private static void genDefaultValue(JSCodeGenTool tool, CodeBuffer buffer, Hoste } private static String importedName(HostedType type) { - String importedName = type.getAnnotation(JS.Import.class).value(); + String importedName = AnnotationUtil.getAnnotation(type, JS.Import.class).value(); return importedName.equals(UNSPECIFIED_IMPORTED_NAME_VALUE) ? computeImportedName(type) : importedName; } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSStubMethod.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSStubMethod.java index 659003367113..ab7cb551b735 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSStubMethod.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSStubMethod.java @@ -28,7 +28,6 @@ import java.util.List; import java.util.Objects; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.webimage.api.JS; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; @@ -39,6 +38,7 @@ import com.oracle.svm.hosted.phases.HostedGraphKit; import com.oracle.svm.hosted.webimage.options.WebImageOptions; import com.oracle.svm.hosted.webimage.phases.WebImageHostedGraphKit; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ReflectionUtil; import com.oracle.svm.webimage.annotation.JSRawCall; import com.oracle.svm.webimage.functionintrinsics.JSConversion; @@ -118,9 +118,9 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos coercion = jsObjectAccessMethod.isLoad(); jsCode = jsObjectAccessMethod.getJSCode(); } else { - rawCall = AnnotationAccess.isAnnotationPresent(method, JSRawCall.class); - coercion = AnnotationAccess.isAnnotationPresent(method, JS.Coerce.class); - JS js = Objects.requireNonNull(AnnotationAccess.getAnnotation(method, JS.class)); + rawCall = AnnotationUtil.isAnnotationPresent(method, JSRawCall.class); + coercion = AnnotationUtil.isAnnotationPresent(method, JS.Coerce.class); + JS js = Objects.requireNonNull(AnnotationUtil.getAnnotation(method, JS.class)); jsCode = new JSBody.JSCode(js, method); } return buildGraph(debug, method, providers, purpose, jsCode, coercion, rawCall); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSSubstitutionProcessor.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSSubstitutionProcessor.java index 5e55ea179df6..22a2e0a15e12 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSSubstitutionProcessor.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/js/JSSubstitutionProcessor.java @@ -28,12 +28,12 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.webimage.api.JS; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.svm.hosted.annotation.CustomSubstitutionMethod; +import com.oracle.svm.util.AnnotationUtil; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -59,6 +59,6 @@ public ResolvedJavaMethod lookup(ResolvedJavaMethod method) { private static boolean isJSStubMethod(ResolvedJavaMethod method) { // If AnalysisMethods appeared here, they would first need to be unwrapped assert !(method instanceof AnalysisMethod) : method; - return method instanceof JSObjectAccessMethod || AnnotationAccess.isAnnotationPresent(method, JS.class); + return method instanceof JSObjectAccessMethod || AnnotationUtil.isAnnotationPresent(method, JS.class); } } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/phases/WebImageHostedGraphKit.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/phases/WebImageHostedGraphKit.java index 86ed3a58dcb9..2bbe8c0ce470 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/phases/WebImageHostedGraphKit.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/phases/WebImageHostedGraphKit.java @@ -27,7 +27,6 @@ import java.util.EnumMap; import java.util.Locale; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.webimage.api.JSResource; import com.oracle.graal.pointsto.infrastructure.GraphProvider; @@ -35,6 +34,7 @@ import com.oracle.svm.hosted.phases.HostedGraphKit; import com.oracle.svm.hosted.webimage.js.JSBody; import com.oracle.svm.hosted.webimage.js.JSBodyWithExceptionNode; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.webimage.functionintrinsics.JSCallNode; import com.oracle.svm.webimage.functionintrinsics.JSSystemFunction; @@ -79,7 +79,7 @@ public ValueNode createConvertToJs(ValueNode value, JavaKind kind) { public JSBody createJSBody(JSBody.JSCode jsCode, ResolvedJavaMethod method, ValueNode[] argNodes, Stamp returnStamp, FrameStateBuilder state, int bci, ResolvedJavaMethod exceptionHandler) { ExceptionObjectNode exceptionObject = createExceptionObjectNode(state, bci); - boolean declaresResource = AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), JSResource.class); + boolean declaresResource = AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), JSResource.class); JSBodyWithExceptionNode jsBody = append(new JSBodyWithExceptionNode(jsCode, method, argNodes, returnStamp, exceptionObject, declaresResource)); startWithException(jsBody, exceptionObject, state, bci); exceptionPart(); diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util/AnnotationUtil.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util/AnnotationUtil.java deleted file mode 100644 index 5079b9b824a6..000000000000 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/util/AnnotationUtil.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2025, 2025, 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.webimage.util; - -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -public class AnnotationUtil { - - /** - * This method is similar to {@link AnnotatedElement#getDeclaredAnnotationsByType} but avoids - * the access of all annotations of the element, which is not allowed at image build time - * because it initializes all annotation classes and their dependencies. - * - * In contrast to {@link AnnotatedElement#getDeclaredAnnotationsByType}, the order of the - * annotations in the source code is not taken into account: this method always puts the direct - * annotation before container annotations. Also, information about the container annotation - * needs to be passed in as additional arguments to avoid complicated reflective lookups. - */ - public static List getDeclaredAnnotationsByType(AnnotatedElement element, - Class annotationClass, Class containerClass, Function valueFunction) { - - List result = new ArrayList<>(); - A direct = element.getDeclaredAnnotation(annotationClass); - if (direct != null) { - result.add(direct); - } - C container = element.getDeclaredAnnotation(containerClass); - if (container != null) { - result.addAll(List.of(valueFunction.apply(container))); - } - return result; - } -} diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmCodeGen.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmCodeGen.java index a94356b2b5f8..4d65d92f802f 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmCodeGen.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/codegen/WebImageWasmCodeGen.java @@ -79,6 +79,7 @@ import com.oracle.svm.hosted.webimage.wasm.debug.WasmDebug; import com.oracle.svm.hosted.webimage.wasmgc.WasmGCFunctionTemplateFeature; import com.oracle.svm.hosted.webimage.wasmgc.types.WasmRefType; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.webimage.NamingConvention; import com.oracle.svm.webimage.functionintrinsics.JSFunctionDefinition; import com.oracle.svm.webimage.functionintrinsics.JSGenericFunctionDefinition; @@ -287,12 +288,12 @@ protected void genWasmModule() { module.addFunctionExport(getProviders().idFactory.forMethod(mainEntryPoint), "main", "Main Entry Point"); for (HostedMethod entryPoint : hostedEntryPoints) { - if (entryPoint.isAnnotationPresent(WasmExport.class)) { - WasmExport annotation = entryPoint.getAnnotation(WasmExport.class); + if (AnnotationUtil.isAnnotationPresent(entryPoint, WasmExport.class)) { + WasmExport annotation = AnnotationUtil.getAnnotation(entryPoint, WasmExport.class); module.addFunctionExport(getProviders().idFactory().forMethod(entryPoint), annotation.value(), annotation.comment().isEmpty() ? null : annotation.comment()); } - if (entryPoint.isAnnotationPresent(WasmStartFunction.class)) { + if (AnnotationUtil.isAnnotationPresent(entryPoint, WasmStartFunction.class)) { module.setStartFunction(new StartFunction(getProviders().idFactory().forMethod(entryPoint), null)); } } diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/phases/StackPointerVerificationPhase.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/phases/StackPointerVerificationPhase.java index fb21b7aad77d..1dcf3b1f9afc 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/phases/StackPointerVerificationPhase.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/phases/StackPointerVerificationPhase.java @@ -25,11 +25,10 @@ package com.oracle.svm.hosted.webimage.wasm.phases; -import org.graalvm.nativeimage.AnnotationAccess; - import com.oracle.svm.core.snippets.KnownIntrinsics; import com.oracle.svm.hosted.webimage.wasm.debug.NoStackVerification; import com.oracle.svm.hosted.webimage.wasm.debug.WasmDebug; +import com.oracle.svm.util.AnnotationUtil; import jdk.graal.compiler.nodes.ControlSinkNode; import jdk.graal.compiler.nodes.FixedNode; @@ -54,7 +53,7 @@ public class StackPointerVerificationPhase extends BasePhase { @Override protected void run(StructuredGraph graph, CoreProviders context) { - if (AnnotationAccess.isAnnotationPresent(graph.method(), NoStackVerification.class)) { + if (AnnotationUtil.isAnnotationPresent(graph.method(), NoStackVerification.class)) { return; } diff --git a/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JSBodyStubMethod.java b/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JSBodyStubMethod.java index c19d79181557..dd140a7d3f77 100644 --- a/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JSBodyStubMethod.java +++ b/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JSBodyStubMethod.java @@ -40,6 +40,7 @@ import com.oracle.svm.hosted.webimage.codegen.JSCodeGenTool; import com.oracle.svm.hosted.webimage.js.JSBody; import com.oracle.svm.hosted.webimage.js.JSBodyWithExceptionNode; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.webimage.hightiercodegen.CodeGenTool; import jdk.graal.compiler.core.common.calc.FloatConvert; @@ -147,7 +148,7 @@ public StructuredGraph buildGraph(DebugContext debug, AnalysisMethod method, Hos private static ValueNode createJSBody(AnalysisMethod method, HostedGraphKit kit, ValueNode[] argNodes, Stamp returnStamp, JSBody.JSCode jsCode, Function codeSupplier) { - boolean declaresResource = AnnotationAccess.isAnnotationPresent(method.getDeclaringClass(), JavaScriptResource.class); + boolean declaresResource = AnnotationUtil.isAnnotationPresent(method.getDeclaringClass(), JavaScriptResource.class); return kit.appendWithUnwind(new JSBodyWithExceptionNode(jsCode, method, argNodes, returnStamp, null, declaresResource, codeSupplier)); } diff --git a/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JavaScriptBodyFeature.java b/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JavaScriptBodyFeature.java index 4543b3a07672..c5cb152f43f1 100644 --- a/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JavaScriptBodyFeature.java +++ b/web-image/src/com.oracle.svm.webimage.thirdparty/src/com/oracle/svm/webimage/thirdparty/JavaScriptBodyFeature.java @@ -27,7 +27,6 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor; @@ -37,7 +36,7 @@ import com.oracle.svm.hosted.webimage.codegen.LowerableResource; import com.oracle.svm.hosted.webimage.codegen.LowerableResources; import com.oracle.svm.hosted.webimage.codegen.oop.ClassLowerer; -import com.oracle.svm.hosted.webimage.util.AnnotationUtil; +import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.ModuleSupport; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -51,8 +50,10 @@ public class JavaScriptBodyFeature implements Feature { private static String[] getJSResources(ResolvedJavaType type) { - var requiredJavaScriptResources = AnnotationUtil.getDeclaredAnnotationsByType(type, JavaScriptResource.class, JavaScriptResource.Group.class, JavaScriptResource.Group::value); - assert requiredJavaScriptResources.size() != 0 || !type.isAnnotationPresent(JavaScriptResource.Group.class) : "Repeated annotation not detected by getDeclaredAnnotationsByType"; + var requiredJavaScriptResources = AnnotationUtil.getAnnotationsByType(type, JavaScriptResource.class, JavaScriptResource.Group.class, + JavaScriptResource.Group::value); + assert !requiredJavaScriptResources.isEmpty() || + !AnnotationUtil.isAnnotationPresent(type, JavaScriptResource.Group.class) : "Repeated annotation not detected by getDeclaredAnnotationsByType"; return requiredJavaScriptResources.stream().map(JavaScriptResource::value).toArray(String[]::new); } @@ -80,7 +81,7 @@ private boolean neverInlineTrivial(@SuppressWarnings("unused") AnalysisMethod ca /* * Methods annotated with @JavaScriptBody are never trivial */ - return AnnotationAccess.isAnnotationPresent(callee, JavaScriptBody.class); + return AnnotationUtil.isAnnotationPresent(callee, JavaScriptBody.class); } @Override @@ -103,10 +104,7 @@ public ResolvedJavaMethod lookup(ResolvedJavaMethod method) { } private static boolean isJavaScriptBodyStubMethod(ResolvedJavaMethod method) { - if (AnnotationAccess.isAnnotationPresent(method, JavaScriptBody.class)) { - return true; - } - return false; + return AnnotationUtil.isAnnotationPresent(method, JavaScriptBody.class); } } } From e96bf465d13ca93d9a6f23a8c375a13ae4c63206 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 27 Oct 2025 20:30:08 +0100 Subject: [PATCH 2/2] moved most SubstrateAnnotationExtractor logic in com.oracle.svm.util --- substratevm/mx.substratevm/suite.py | 7 +- .../StandaloneAnnotationExtractor.java | 4 +- .../infrastructure/WrappedJavaField.java | 10 +- .../infrastructure/WrappedJavaMethod.java | 10 +- .../infrastructure/WrappedJavaType.java | 10 +- .../graal/pointsto/meta/BaseLayerField.java | 4 +- .../graal/pointsto/meta/BaseLayerMethod.java | 3 +- .../graal/pointsto/meta/BaseLayerType.java | 3 +- .../oracle/svm/graal/meta/SubstrateField.java | 21 +- .../svm/graal/meta/SubstrateMethod.java | 21 +- .../oracle/svm/graal/meta/SubstrateType.java | 20 +- .../svm/hosted/foreign/DowncallStub.java | 2 +- .../hosted/annotation/AnnotationWrapper.java | 12 +- .../annotation/CustomSubstitutionMethod.java | 7 +- .../annotation/CustomSubstitutionType.java | 7 +- .../SubstrateAnnotationExtractor.java | 468 +-------------- .../hosted/cenum/CEnumCallWrapperMethod.java | 2 +- .../code/CEntryPointJavaCallStubMethod.java | 4 +- .../svm/hosted/code/NonBytecodeMethod.java | 9 +- .../hosted/reflect/ReflectionDataBuilder.java | 11 +- .../svm/hosted/substitute/AliasField.java | 9 +- .../svm/hosted/substitute/AnnotatedField.java | 7 +- .../hosted/substitute/AnnotatedMethod.java | 7 +- .../hosted/substitute/InjectedFieldsType.java | 9 +- .../PolymorphicSignatureWrapperMethod.java | 9 +- .../hosted/substitute/SubstitutionField.java | 10 +- .../hosted/substitute/SubstitutionMethod.java | 9 +- .../hosted/substitute/SubstitutionType.java | 9 +- .../svm/util/AnnotatedObjectAccess.java | 533 ++++++++++++++++++ .../svm/util/AnnotatedObjectAccessError.java} | 15 +- .../com/oracle/svm/util/AnnotatedWrapper.java | 49 ++ .../com/oracle/svm/util/AnnotationUtil.java | 67 +-- .../svm/util/AnnotationsContainer.java} | 20 +- 33 files changed, 805 insertions(+), 583 deletions(-) create mode 100644 substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccess.java rename substratevm/src/{com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExtractionError.java => com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccessError.java} (75%) create mode 100644 substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedWrapper.java rename substratevm/src/{com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerElement.java => com.oracle.svm.util/src/com/oracle/svm/util/AnnotationsContainer.java} (71%) diff --git a/substratevm/mx.substratevm/suite.py b/substratevm/mx.substratevm/suite.py index 96ceeb3e64bf..1b05f5ce2d67 100644 --- a/substratevm/mx.substratevm/suite.py +++ b/substratevm/mx.substratevm/suite.py @@ -228,7 +228,10 @@ "compiler:GRAAL", ], "requiresConcealed" : { - "java.base" : ["jdk.internal.module"], + "java.base" : [ + "jdk.internal.module", + "sun.reflect.annotation" + ], "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", "jdk.vm.ci.meta.annotation", @@ -1590,6 +1593,7 @@ "requiresConcealed": { "jdk.internal.vm.ci": [ "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", "jdk.vm.ci.code", "jdk.vm.ci.common", ] @@ -1639,6 +1643,7 @@ "requiresConcealed" : { "jdk.internal.vm.ci" : [ "jdk.vm.ci.meta", + "jdk.vm.ci.meta.annotation", "jdk.vm.ci.code", ], "java.base" : [ diff --git a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneAnnotationExtractor.java b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneAnnotationExtractor.java index affbd6a3d23b..b0f206236712 100644 --- a/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneAnnotationExtractor.java +++ b/substratevm/src/com.oracle.graal.pointsto.standalone/src/com/oracle/graal/pointsto/standalone/StandaloneAnnotationExtractor.java @@ -26,12 +26,12 @@ package com.oracle.graal.pointsto.standalone; -import org.graalvm.nativeimage.impl.AnnotationExtractor; - import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.util.Arrays; +import org.graalvm.nativeimage.impl.AnnotationExtractor; + public class StandaloneAnnotationExtractor implements AnnotationExtractor { // Checkstyle: allow direct annotation access @Override diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaField.java index 43288471dc78..0599cd9cdb4a 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaField.java @@ -24,10 +24,18 @@ */ package com.oracle.graal.pointsto.infrastructure; +import com.oracle.svm.util.AnnotatedWrapper; + import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.annotation.Annotated; -public interface WrappedJavaField extends ResolvedJavaField, WrappedElement { +public interface WrappedJavaField extends ResolvedJavaField, WrappedElement, AnnotatedWrapper { @Override ResolvedJavaField getWrapped(); + + @Override + default Annotated getWrappedAnnotated() { + return getWrapped(); + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaMethod.java index ec61abfae10f..e936eae1f4ed 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaMethod.java @@ -24,10 +24,18 @@ */ package com.oracle.graal.pointsto.infrastructure; +import com.oracle.svm.util.AnnotatedWrapper; + import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.annotation.Annotated; -public interface WrappedJavaMethod extends WrappedElement, ResolvedJavaMethod { +public interface WrappedJavaMethod extends WrappedElement, AnnotatedWrapper, ResolvedJavaMethod { @Override ResolvedJavaMethod getWrapped(); + + @Override + default Annotated getWrappedAnnotated() { + return getWrapped(); + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaType.java index 7bad26395435..fa0494df0cad 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedJavaType.java @@ -24,10 +24,18 @@ */ package com.oracle.graal.pointsto.infrastructure; +import com.oracle.svm.util.AnnotatedWrapper; + import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; -public interface WrappedJavaType extends WrappedElement, ResolvedJavaType { +public interface WrappedJavaType extends WrappedElement, AnnotatedWrapper, ResolvedJavaType { @Override ResolvedJavaType getWrapped(); + + @Override + default Annotated getWrappedAnnotated() { + return getWrapped(); + } } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerField.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerField.java index 3921b3a4dea6..11b35b51d049 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerField.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerField.java @@ -26,6 +26,8 @@ import java.lang.annotation.Annotation; +import com.oracle.svm.util.AnnotationsContainer; + import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; @@ -37,7 +39,7 @@ * If a field cannot be looked up by name, a {@link BaseLayerField} is created and put in an * {@link AnalysisField} to represent this missing field, using the information from the base layer. */ -public class BaseLayerField extends BaseLayerElement implements ResolvedJavaField { +public class BaseLayerField extends AnnotationsContainer implements ResolvedJavaField { private final int id; private final String name; private final ResolvedJavaType declaringClass; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java index 8305ddbbccfc..ccb07184e1f8 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerMethod.java @@ -28,6 +28,7 @@ import java.lang.reflect.Type; import com.oracle.graal.pointsto.infrastructure.ResolvedSignature; +import com.oracle.svm.util.AnnotationsContainer; import jdk.graal.compiler.debug.GraalError; import jdk.vm.ci.meta.Constant; @@ -50,7 +51,7 @@ * {@link BaseLayerMethod} is created and put in an {@link AnalysisMethod} to represent this missing * method, using the information from the base layer. */ -public class BaseLayerMethod extends BaseLayerElement implements ResolvedJavaMethod { +public class BaseLayerMethod extends AnnotationsContainer implements ResolvedJavaMethod { private static final String CLINIT = ""; private final int id; diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java index e5d5aadd2f33..7f811d61f726 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerType.java @@ -28,6 +28,7 @@ import java.util.List; import com.oracle.graal.pointsto.util.AnalysisError; +import com.oracle.svm.util.AnnotationsContainer; import com.oracle.svm.util.OriginalClassProvider; import jdk.vm.ci.meta.Assumptions; @@ -47,7 +48,7 @@ * this case, a {@link BaseLayerType} is created using information from the base layer and wrapped * in an {@link AnalysisType} to replace this missing type is the new layer. */ -public class BaseLayerType extends BaseLayerElement implements ResolvedJavaType, OriginalClassProvider { +public class BaseLayerType extends AnnotationsContainer implements ResolvedJavaType, OriginalClassProvider { /** * The type corresponding to this {@link BaseLayerType} can be created later while building the * new layer. To avoid both types having the same name, the name of the {@link BaseLayerType} is diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java index cee39345fcad..bdcbfb5790a1 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateField.java @@ -48,6 +48,7 @@ import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PrimitiveConstant; import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; public class SubstrateField implements SharedField { @@ -157,19 +158,33 @@ public SubstrateType getDeclaringClass() { return declaringClass; } + private RuntimeException annotationsUnimplemented() { + return VMError.unimplemented("Annotations are not available for JIT compilation at image run time: " + format("%H.%n")); + } + + @Override + public AnnotationsInfo getDeclaredAnnotationInfo() { + throw annotationsUnimplemented(); + } + + @Override + public AnnotationsInfo getTypeAnnotationInfo() { + throw annotationsUnimplemented(); + } + @Override public Annotation[] getAnnotations() { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override public Annotation[] getDeclaredAnnotations() { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override public T getAnnotation(Class annotationClass) { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java index 3c5e7a7200ec..7a872eae2c87 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateMethod.java @@ -70,6 +70,7 @@ import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; import jdk.vm.ci.meta.TriState; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; public class SubstrateMethod implements SharedRuntimeMethod { @@ -416,19 +417,33 @@ public ConstantPool getConstantPool() { throw intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport } + private RuntimeException annotationsUnimplemented() { + return VMError.unimplemented("Annotations are not available for JIT compilation at image run time: " + format("%H.%n(%p)")); + } + + @Override + public AnnotationsInfo getDeclaredAnnotationInfo() { + throw annotationsUnimplemented(); + } + + @Override + public AnnotationsInfo getTypeAnnotationInfo() { + throw annotationsUnimplemented(); + } + @Override public Annotation[] getAnnotations() { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override public Annotation[] getDeclaredAnnotations() { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override public T getAnnotation(Class annotationClass) { - throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); + throw annotationsUnimplemented(); } @Override diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java index 4f1ae18a6012..f8b8e26ba271 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateType.java @@ -53,6 +53,7 @@ import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.AnnotationsInfo; public class SubstrateType implements SharedType { private final JavaKind kind; @@ -380,18 +381,33 @@ public ResolvedJavaField[] getStaticFields() { throw VMError.intentionallyUnimplemented(); // ExcludeFromJacocoGeneratedReport } + private RuntimeException annotationsUnimplemented() { + return VMError.unimplemented("Annotations are not available for JIT compilation at image run time: " + toClassName()); + } + + @Override + public AnnotationsInfo getDeclaredAnnotationInfo() { + throw annotationsUnimplemented(); + } + + @Override + public AnnotationsInfo getTypeAnnotationInfo() { + throw annotationsUnimplemented(); + } + @Override public Annotation[] getAnnotations() { - return DynamicHub.toClass(getHub()).getAnnotations(); + throw annotationsUnimplemented(); } @Override public Annotation[] getDeclaredAnnotations() { - return DynamicHub.toClass(getHub()).getDeclaredAnnotations(); + throw annotationsUnimplemented(); } @Override public T getAnnotation(Class annotationClass) { + // Once GR-70556 is resolved: throw annotationsUnimplemented(); return DynamicHub.toClass(getHub()).getAnnotation(annotationClass); } diff --git a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java index 6c3a25473076..715389459a40 100644 --- a/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java +++ b/substratevm/src/com.oracle.svm.hosted.foreign/src/com/oracle/svm/hosted/foreign/DowncallStub.java @@ -121,7 +121,7 @@ public List getInjectedAnnotations() { if (nep.allowHeapAccess()) { return INJECTED_ANNOTATIONS_FOR_ALLOW_HEAP_ACCESS; } - return null; + return List.of(); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java index be7a64b56f9b..36ac474d1d4f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationWrapper.java @@ -26,21 +26,17 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import java.util.List; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.impl.AnnotationExtractor; import com.oracle.svm.core.util.VMError; -import jdk.graal.compiler.annotation.AnnotationValue; - +/** + * Default implementations for {@link AnnotatedElement} based on the {@link AnnotationExtractor} + * image singleton. + */ public interface AnnotationWrapper extends AnnotatedElement { - AnnotatedElement getAnnotationRoot(); - - default List getInjectedAnnotations() { - return null; - } @Override default boolean isAnnotationPresent(Class annotationClass) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java index 02a530518e2c..f1980dd9f5fa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionMethod.java @@ -27,10 +27,10 @@ import static com.oracle.svm.core.util.VMError.intentionallyUnimplemented; import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; import com.oracle.graal.pointsto.infrastructure.GraphProvider; +import com.oracle.svm.util.AnnotatedWrapper; import com.oracle.svm.util.OriginalMethodProvider; import jdk.vm.ci.meta.Constant; @@ -44,8 +44,9 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.annotation.Annotated; -public abstract class CustomSubstitutionMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper { +public abstract class CustomSubstitutionMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper, AnnotatedWrapper { protected final ResolvedJavaMethod original; @@ -218,7 +219,7 @@ public ConstantPool getConstantPool() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return original; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java index f4322daa06ce..cab5afb1dab1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/CustomSubstitutionType.java @@ -24,10 +24,10 @@ */ package com.oracle.svm.hosted.annotation; -import java.lang.reflect.AnnotatedElement; import java.util.List; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.util.AnnotatedWrapper; import com.oracle.svm.util.OriginalClassProvider; import jdk.vm.ci.meta.Assumptions.AssumptionResult; @@ -41,8 +41,9 @@ import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.UnresolvedJavaField; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; -public abstract class CustomSubstitutionType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper { +public abstract class CustomSubstitutionType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaType original; public CustomSubstitutionType(ResolvedJavaType original) { @@ -60,7 +61,7 @@ public String getName() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return null; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java index 1083a77ca7af..f1a3e2ec8ff1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/SubstrateAnnotationExtractor.java @@ -26,55 +26,29 @@ import java.lang.annotation.Annotation; import java.lang.annotation.AnnotationFormatError; -import java.lang.annotation.Inherited; import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Array; import java.lang.reflect.Executable; import java.lang.reflect.Field; -import java.lang.reflect.GenericSignatureFormatError; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.RecordComponent; -import java.nio.BufferUnderflowException; -import java.util.Collection; -import java.util.List; -import java.util.Map; import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.impl.AnnotationExtractor; -import com.oracle.graal.pointsto.infrastructure.WrappedElement; -import com.oracle.graal.pointsto.meta.BaseLayerElement; -import com.oracle.graal.pointsto.reports.ReportUtils; import com.oracle.svm.core.traits.BuiltinTraits.BuildtimeAccessOnly; import com.oracle.svm.core.traits.BuiltinTraits.NoLayeredCallbacks; import com.oracle.svm.core.traits.SingletonLayeredInstallationKind.Independent; import com.oracle.svm.core.traits.SingletonTraits; -import com.oracle.svm.core.util.VMError; -import com.oracle.svm.util.AnnotationUtil; +import com.oracle.svm.util.AnnotatedObjectAccess; +import com.oracle.svm.util.AnnotatedObjectAccessError; import com.oracle.svm.util.GraalAccess; import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.annotation.AnnotationValue; -import jdk.graal.compiler.annotation.AnnotationValueSupport; -import jdk.graal.compiler.annotation.ElementTypeMismatch; -import jdk.graal.compiler.annotation.EnumElement; -import jdk.graal.compiler.annotation.MissingType; -import jdk.graal.compiler.annotation.TypeAnnotationValue; -import jdk.graal.compiler.util.CollectionsUtil; -import jdk.graal.compiler.util.EconomicHashMap; -import jdk.vm.ci.meta.ResolvedJavaField; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaRecordComponent; -import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.annotation.Annotated; -import sun.reflect.annotation.AnnotationParser; -import sun.reflect.annotation.AnnotationSupport; -import sun.reflect.annotation.AnnotationType; -import sun.reflect.annotation.TypeNotPresentExceptionProxy; /** * This class wraps all annotation accesses during the Native Image build. It relies on @@ -87,227 +61,12 @@ * their dependencies. */ @SingletonTraits(access = BuildtimeAccessOnly.class, layeredCallbacks = NoLayeredCallbacks.class, layeredInstallationKind = Independent.class) -public class SubstrateAnnotationExtractor implements AnnotationExtractor, AnnotationUtil.Access { - private final Map> annotationCache = new ConcurrentHashMap<>(); - private final Map> declaredAnnotationCache = new ConcurrentHashMap<>(); - private final Map>> parameterAnnotationCache = new ConcurrentHashMap<>(); - private final Map> typeAnnotationCache = new ConcurrentHashMap<>(); - private final Map annotationDefaultCache = new ConcurrentHashMap<>(); - private final Map resolvedAnnotationsCache = new ConcurrentHashMap<>(); - - private static final Method packageGetPackageInfo = ReflectionUtil.lookupMethod(Package.class, "getPackageInfo"); - - @Override - public T getAnnotation(Annotated element, Class annotationType) { - Inherited inherited = annotationType.getAnnotation(Inherited.class); - Map annotationValues = getAnnotationValues(element, inherited == null); - AnnotationValue annotationValue = annotationValues.get(GraalAccess.lookupType(annotationType)); - if (annotationValue != null) { - return asAnnotation(annotationValue, annotationType); - } - return null; - } - - /** - * Gets the annotation of type {@code annotationType} from {@code annotated}. - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - public static AnnotationValue toAnnotationValue(Annotation annotation) { - ResolvedJavaType type = GraalAccess.lookupType(annotation.annotationType()); - Map values = AnnotationSupport.memberValues(annotation); - Map.Entry[] elements = new Map.Entry[values.size()]; - int i = 0; - for (Map.Entry e : values.entrySet()) { - String name = e.getKey(); - Object aElement = e.getValue(); - Object avElement = toAnnotationValueElement(aElement); - elements[i++] = Map.entry(name, avElement); - } - return new AnnotationValue(type, CollectionsUtil.mapOfEntries(elements)); - } - - private static final Class AnnotationTypeMismatchExceptionProxy = ReflectionUtil.lookupClass("sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy"); - - /** - * Converts an annotation element value from its core reflection representation to its JVMCI - * representation. That is, this method converts a value as found in the map returned by - * {@link AnnotationSupport#memberValues(Annotation)} to the corresponding value in the map - * returned by {@link AnnotationValue#getElements()}. - *

    - * This is the inverse of the conversion performed by - * {@link #toAnnotationElement(Class, Object)}. - * - * @param aElement core reflection representation of an annotation element value - * @return the JVMCI representation of the same value - */ - private static Object toAnnotationValueElement(Object aElement) { - return switch (aElement) { - case Enum ev -> new EnumElement(GraalAccess.lookupType(aElement.getClass()), ev.name()); - case Class cls -> GraalAccess.lookupType(cls); - case Annotation a -> toAnnotationValue(a); - case TypeNotPresentExceptionProxy proxy -> new MissingType(proxy.typeName(), proxy.getCause()); - default -> { - Class valueType = aElement.getClass(); - if (valueType.isArray()) { - int length = Array.getLength(aElement); - Object[] array = new Object[length]; - for (int i = 0; i < length; i++) { - array[i] = toAnnotationValueElement(Array.get(aElement, i)); - } - yield List.of(array); - } else if (AnnotationTypeMismatchExceptionProxy.isInstance(aElement)) { - String foundType = ReflectionUtil.readField(AnnotationTypeMismatchExceptionProxy, "foundType", aElement); - yield new ElementTypeMismatch(foundType); - } else { - yield aElement; - } - } - }; - } - - /** - * Converts an annotation element value from its JVMCI representation to its core reflection - * representation. That is, this method converts a value as found in the map returned by - * {@link AnnotationValue#getElements()} to the corresponding value in the map returned by - * {@link AnnotationSupport#memberValues(Annotation)}. - *

    - * This is the inverse of the conversion performed by {@link #toAnnotationValueElement(Object)}. - * - * @param returnType the return type of the method representing the annotation element whose - * value is being converted - * @param avElement the annotation element value to convert - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - private static Object toAnnotationElement(Class returnType, Object avElement) { - switch (avElement) { - case EnumElement ee -> { - Class enumType = (Class) OriginalClassProvider.getJavaClass(ee.enumType); - return Enum.valueOf(enumType, ee.name); - } - case ResolvedJavaType rjt -> { - return OriginalClassProvider.getJavaClass(rjt); - } - case AnnotationValue av -> { - Class type = (Class) OriginalClassProvider.getJavaClass(av.getAnnotationType()); - return toAnnotation(av, type); - } - case List adList -> { - int length = adList.size(); - if (returnType == byte[].class) { - byte[] result = new byte[length]; - for (int i = 0; i < length; i++) { - result[i] = (byte) adList.get(i); - } - return result; - } - if (returnType == char[].class) { - char[] result = new char[length]; - for (int i = 0; i < length; i++) { - result[i] = (char) adList.get(i); - } - return result; - } - if (returnType == short[].class) { - short[] result = new short[length]; - for (int i = 0; i < length; i++) { - result[i] = (short) adList.get(i); - } - return result; - } - if (returnType == int[].class) { - int[] result = new int[length]; - for (int i = 0; i < length; i++) { - result[i] = (int) adList.get(i); - } - return result; - } - if (returnType == float[].class) { - float[] result = new float[length]; - for (int i = 0; i < length; i++) { - result[i] = (float) adList.get(i); - } - return result; - } - if (returnType == long[].class) { - long[] result = new long[length]; - for (int i = 0; i < length; i++) { - result[i] = (long) adList.get(i); - } - return result; - } - if (returnType == double[].class) { - double[] result = new double[length]; - for (int i = 0; i < length; i++) { - result[i] = (double) adList.get(i); - } - return result; - } - if (returnType == boolean[].class) { - boolean[] result = new boolean[length]; - for (int i = 0; i < length; i++) { - result[i] = (boolean) adList.get(i); - } - return result; - } - Class componentType = returnType.getComponentType(); - assert componentType != null && !componentType.isArray() && !componentType.isPrimitive() : componentType; - Object[] result = (Object[]) Array.newInstance(componentType, length); - for (int i = 0; i < length; i++) { - result[i] = toAnnotationElement(componentType, adList.get(i)); - } - return result; - } - default -> { - return avElement; - } - } - } - - /** - * Converts {@code annotationValue} to an instance of {@code type}. - */ - private static T toAnnotation(AnnotationValue annotationValue, Class type) { - AnnotationType annotationType = AnnotationType.getInstance(type); - Map memberValues = new EconomicHashMap<>(); - for (var e : annotationType.members().entrySet()) { - String name = e.getKey(); - Object o = annotationValue.get(name, Object.class); - memberValues.put(name, toAnnotationElement(e.getValue().getReturnType(), o)); - } - return type.cast(AnnotationParser.annotationForMap(type, memberValues)); - } - - @SuppressWarnings("unchecked") - private T extractAnnotation(Annotated element, Class annotationType, boolean declaredOnly) { - Map annotationValues = getAnnotationValues(element, declaredOnly); - AnnotationValue annotation = annotationValues.get(GraalAccess.lookupType(annotationType)); - if (annotation != null) { - return (T) resolvedAnnotationsCache.computeIfAbsent(annotation, value -> toAnnotation(value, annotationType)); - } - return null; - } - - @Override - public T asAnnotation(AnnotationValue annotationValue, Class annotationType) { - T res = annotationType.cast(resolvedAnnotationsCache.computeIfAbsent(annotationValue, value -> toAnnotation(value, annotationType))); - Class resType = res.annotationType(); - if (!resType.equals(annotationType)) { - throw VMError.shouldNotReachHere("Conversion failed: expected %s (loader: %s), got %s (loader: %s)", - annotationType.getName(), ReportUtils.loaderName(annotationType.getClassLoader()), - resType.getName(), ReportUtils.loaderName(resType.getClassLoader())); - } - return res; - } - - @Override - public AnnotationValue asAnnotationValue(Annotation annotation) { - return toAnnotationValue(annotation); - } +public class SubstrateAnnotationExtractor extends AnnotatedObjectAccess implements AnnotationExtractor { @Override public T extractAnnotation(AnnotatedElement element, Class annotationType, boolean declaredOnly) { try { - return extractAnnotation(toAnnotated(element), annotationType, declaredOnly); + return getAnnotation(toAnnotated(element), annotationType, declaredOnly); } catch (LinkageError | AnnotationFormatError e) { /* * Returning null essentially means that the element doesn't declare the annotationType, @@ -334,7 +93,9 @@ public boolean hasAnnotation(AnnotatedElement element, Class { return null; @@ -362,26 +123,12 @@ private static Annotated toAnnotated(AnnotatedElement element) { if (targetException instanceof LinkageError) { throw (LinkageError) targetException; } - throw new AnnotationExtractionError(element, e); + throw new AnnotatedObjectAccessError(element, e); } catch (IllegalAccessException e) { - throw new AnnotationExtractionError(element, e); + throw new AnnotatedObjectAccessError(element, e); } } - default -> throw new AnnotationExtractionError(element, (Throwable) null); - } - } - - public boolean hasAnnotation(Annotated element, Class annotationType) { - try { - return getAnnotationValues(element, false).containsKey(GraalAccess.lookupType(annotationType)); - } catch (LinkageError e) { - /* - * Returning false essentially means that the element doesn't declare the - * annotationType, but we cannot know that since the annotation parsing failed. However, - * this allows us to defend against crashing the image builder if the user code - * references types missing from the classpath. - */ - return false; + default -> throw new AnnotatedObjectAccessError(element, (Throwable) null); } } @@ -394,199 +141,4 @@ public Class[] getAnnotationTypes(AnnotatedElement element .filter(Objects::nonNull) // .toArray(Class[]::new); } - - public Map getDeclaredAnnotationValues(AnnotatedElement element) { - return getAnnotationValues(toAnnotated(element), true); - } - - @Override - public Map getDeclaredAnnotationValues(Annotated element) { - return getAnnotationValues(element, true); - } - - private Map getAnnotationValues(Annotated element, boolean declaredOnly) { - Annotated cur = element; - while (cur instanceof WrappedElement wrapped) { - cur = toAnnotated(wrapped.getWrapped()); - } - Map result = Map.of(); - while (cur instanceof AnnotationWrapper wrapper) { - result = concat(result, wrapper.getInjectedAnnotations()); - cur = toAnnotated(wrapper.getAnnotationRoot()); - } - - Annotated root = cur; - if (root instanceof BaseLayerElement baseLayerElement) { - Annotation[] baseLayerAnnotations = baseLayerElement.getBaseLayerAnnotations(); - if (baseLayerAnnotations.length == 0) { - return Map.of(); - } - result = new EconomicHashMap<>(baseLayerAnnotations.length); - for (var a : baseLayerAnnotations) { - AnnotationValue annotationValue = toAnnotationValue(a); - result.put(annotationValue.getAnnotationType(), annotationValue); - } - } else if (root != null) { - result = concat(result, declaredOnly ? getDeclaredAnnotationValuesFromRoot(root).values() : getAnnotationValuesFromRoot(root).values()); - } - return result; - } - - private static Map concat(Map a1, Collection a2) { - if (a2 == null || a2.isEmpty()) { - return a1; - } else { - Map result = a1 == null || a1.isEmpty() ? new EconomicHashMap<>(a2.size()) : new EconomicHashMap<>(a1); - for (AnnotationValue a : a2) { - ResolvedJavaType annotationType = a.isError() ? ANNOTATION_FORMAT_ERROR_TYPE : a.getAnnotationType(); - result.put(annotationType, a); - } - return result; - } - } - - /** - * Gets the annotations on the super class hierarchy of {@code clazz} that are annotated by - * {@link Inherited}. - */ - private Map getInheritableAnnotations(ResolvedJavaType clazz) { - Map inheritedAnnotations = null; - ResolvedJavaType superClass = clazz.getSuperclass(); - if (superClass != null) { - for (var e : getAnnotationValuesFromRoot(superClass).entrySet()) { - ResolvedJavaType annotationType = e.getKey(); - if (hasAnnotation((Annotated) annotationType, Inherited.class)) { - if (inheritedAnnotations == null) { - inheritedAnnotations = new EconomicHashMap<>(); - } - inheritedAnnotations.put(annotationType, e.getValue()); - } - } - } - return inheritedAnnotations; - } - - private Map getAnnotationValuesFromRoot(Annotated rootElement) { - if (!(rootElement instanceof ResolvedJavaType clazz)) { - return getDeclaredAnnotationValuesFromRoot(rootElement); - } - - Map existing = annotationCache.get(clazz); - if (existing != null) { - return existing; - } - - /* - * Inheritable annotations must be computed first to avoid recursively updating - * annotationCache. - */ - Map inheritableAnnotations = getInheritableAnnotations(clazz); - return annotationCache.computeIfAbsent(clazz, element -> { - Map declaredAnnotations = getDeclaredAnnotationValuesFromRoot(element); - Map annotations = null; - if (inheritableAnnotations != null) { - for (var e : inheritableAnnotations.entrySet()) { - if (!declaredAnnotations.containsKey(e.getKey())) { - if (annotations == null) { - annotations = new EconomicHashMap<>(declaredAnnotations); - } - annotations.put(e.getKey(), e.getValue()); - } - } - } - return annotations != null ? annotations : declaredAnnotations; - }); - } - - private Map getDeclaredAnnotationValuesFromRoot(Annotated rootElement) { - return declaredAnnotationCache.computeIfAbsent(rootElement, SubstrateAnnotationExtractor::parseDeclaredAnnotationValues); - } - - /** - * Annotation type for a {@link AnnotationValue#isError() value representing a parse error}. - */ - public static final ResolvedJavaType ANNOTATION_FORMAT_ERROR_TYPE = GraalAccess.lookupType(Void.TYPE); - - private static Map parseDeclaredAnnotationValues(Annotated element) { - try { - return AnnotationValueSupport.getDeclaredAnnotationValues(element); - } catch (AnnotationFormatError e) { - return Map.of(ANNOTATION_FORMAT_ERROR_TYPE, new AnnotationValue(e)); - } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { - return Map.of(ANNOTATION_FORMAT_ERROR_TYPE, new AnnotationValue(new AnnotationFormatError(e))); - } - } - - public List> getParameterAnnotationValues(AnnotatedElement element) { - Annotated root = toAnnotated(unwrap(element)); - return root != null ? getParameterAnnotationValuesFromRoot((ResolvedJavaMethod) root) : List.of(); - } - - private List> getParameterAnnotationValuesFromRoot(ResolvedJavaMethod rootElement) { - return parameterAnnotationCache.computeIfAbsent(rootElement, element -> { - try { - List> parameterAnnotationValues = AnnotationValueSupport.getParameterAnnotationValues(element); - return parameterAnnotationValues == null ? List.of() : parameterAnnotationValues; - } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { - return List.of(List.of(new AnnotationValue(new AnnotationFormatError(e)))); - } catch (AnnotationFormatError e) { - return List.of(List.of(new AnnotationValue(e))); - } - }); - } - - public List getTypeAnnotationValues(AnnotatedElement element) { - Annotated root = toAnnotated(unwrap(element)); - return root != null ? getTypeAnnotationValuesFromRoot(root) : List.of(); - } - - private List getTypeAnnotationValuesFromRoot(Annotated rootElement) { - return typeAnnotationCache.computeIfAbsent(rootElement, SubstrateAnnotationExtractor::parseTypeAnnotationValues); - } - - private static List parseTypeAnnotationValues(Annotated element) { - try { - return switch (element) { - case ResolvedJavaType type -> AnnotationValueSupport.getTypeAnnotationValues(type); - case ResolvedJavaMethod method -> AnnotationValueSupport.getTypeAnnotationValues(method); - case ResolvedJavaField field -> AnnotationValueSupport.getTypeAnnotationValues(field); - case ResolvedJavaRecordComponent recordComponent -> - AnnotationValueSupport.getTypeAnnotationValues(recordComponent); - default -> - throw new AnnotationExtractionError(element, "Unexpected annotated element type: " + element.getClass()); - }; - } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { - return List.of(new TypeAnnotationValue(new AnnotationFormatError(e))); - } catch (AnnotationFormatError e) { - return List.of(new TypeAnnotationValue(e)); - } - } - - public Object getAnnotationDefaultValue(AnnotatedElement element) { - Annotated root = toAnnotated(unwrap(element)); - return root != null ? getAnnotationDefaultValueFromRoot((ResolvedJavaMethod) root) : null; - } - - private Object getAnnotationDefaultValueFromRoot(ResolvedJavaMethod accessorMethod) { - return annotationDefaultCache.computeIfAbsent(accessorMethod, method -> { - try { - return AnnotationValueSupport.getAnnotationDefaultValue(method); - } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { - return new AnnotationFormatError(e); - } catch (AnnotationFormatError e) { - return e; - } - }); - } - - private static AnnotatedElement unwrap(AnnotatedElement element) { - AnnotatedElement cur = element; - while (cur instanceof WrappedElement) { - cur = ((WrappedElement) cur).getWrapped(); - } - while (cur instanceof AnnotationWrapper) { - cur = ((AnnotationWrapper) cur).getAnnotationRoot(); - } - return cur; - } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java index 051bdad4442f..d53b8c793403 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperMethod.java @@ -82,7 +82,7 @@ public List getInjectedAnnotations() { if (AnnotationUtil.getAnnotation(original, CEnumValue.class) != null) { return INJECTED_ANNOTATIONS; } - return null; + return List.of(); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java index c804cd9d810c..1e804427f77c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointJavaCallStubMethod.java @@ -24,7 +24,6 @@ */ package com.oracle.svm.hosted.code; -import java.lang.reflect.AnnotatedElement; import java.util.List; import org.graalvm.nativeimage.c.function.CEntryPoint; @@ -45,6 +44,7 @@ import jdk.graal.compiler.nodes.java.LoadFieldNode; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; /** * Call stub for invoking {@link CEntryPoint} methods via a Java-to-native call to the method's @@ -103,7 +103,7 @@ protected ValueNode createTargetAddressNode(HostedGraphKit kit, List } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return null; } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NonBytecodeMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NonBytecodeMethod.java index 07a6e75054da..2ad95a53cba5 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NonBytecodeMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/NonBytecodeMethod.java @@ -25,14 +25,14 @@ package com.oracle.svm.hosted.code; import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.svm.util.OriginalMethodProvider; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalMethodProvider; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; @@ -44,12 +44,13 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.annotation.Annotated; /** * Abstract base class for methods with generated Graal IR, i.e., methods that do not originate from * bytecode. */ -public abstract class NonBytecodeMethod implements GraphProvider, ResolvedJavaMethod, AnnotationWrapper, OriginalMethodProvider { +public abstract class NonBytecodeMethod implements GraphProvider, ResolvedJavaMethod, AnnotationWrapper, AnnotatedWrapper, OriginalMethodProvider { /** * Line numbers are bogus because this is generated code, but we need to include them in our @@ -243,7 +244,7 @@ public SpeculationLog getSpeculationLog() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return null; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index d2624806bd5a..8e6cc1e7a547 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -80,7 +80,6 @@ import com.oracle.graal.pointsto.ObjectScanner.OtherReason; import com.oracle.graal.pointsto.ObjectScanner.ScanReason; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; -import com.oracle.svm.util.OriginalClassProvider; import com.oracle.graal.pointsto.meta.AnalysisElement; import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -117,6 +116,7 @@ import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; import com.oracle.svm.hosted.substitute.SubstitutionReflectivityFilter; import com.oracle.svm.util.LogUtils; +import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.annotation.AnnotationValue; @@ -128,6 +128,7 @@ import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; import sun.reflect.annotation.ExceptionProxy; import sun.reflect.annotation.TypeNotPresentExceptionProxy; @@ -1019,7 +1020,8 @@ private void registerTypesForAnnotations(AnnotatedElement annotatedElement) { if (annotatedElement != null) { if (!filteredAnnotations.containsKey(annotatedElement)) { List includedAnnotations = new ArrayList<>(); - for (AnnotationValue annotation : annotationExtractor.getDeclaredAnnotationValues(annotatedElement).values()) { + Annotated annotated = SubstrateAnnotationExtractor.toAnnotated(annotatedElement); + for (AnnotationValue annotation : annotationExtractor.getDeclaredAnnotationValues(annotated).values()) { if (includeAnnotation(annotation)) { includedAnnotations.add(annotation); registerTypesForAnnotation(annotation); @@ -1055,7 +1057,8 @@ private void registerTypesForTypeAnnotations(AnnotatedElement annotatedElement) if (annotatedElement != null) { if (!filteredTypeAnnotations.containsKey(annotatedElement)) { List includedTypeAnnotations = new ArrayList<>(); - for (TypeAnnotationValue typeAnnotation : annotationExtractor.getTypeAnnotationValues(annotatedElement)) { + Annotated annotated = SubstrateAnnotationExtractor.toAnnotated(annotatedElement); + for (TypeAnnotationValue typeAnnotation : annotationExtractor.getTypeAnnotationValues(annotated)) { if (includeAnnotation(typeAnnotation.getAnnotation())) { includedTypeAnnotations.add(typeAnnotation); registerTypesForAnnotation(typeAnnotation.getAnnotation()); @@ -1431,7 +1434,7 @@ public TypeAnnotationValue[] getTypeAnnotationData(AnnotatedElement element) { return filteredTypeAnnotations.getOrDefault(element, NO_TYPE_ANNOTATIONS); } - public Object getAnnotationDefaultData(AnnotatedElement element) { + public Object getAnnotationDefaultData(AnalysisMethod element) { return annotationExtractor.getAnnotationDefaultValue(element); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AliasField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AliasField.java index be669d509765..922ff53f19db 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AliasField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AliasField.java @@ -24,18 +24,19 @@ */ package com.oracle.svm.hosted.substitute; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; -import com.oracle.svm.util.OriginalFieldProvider; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalFieldProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; -public final class AliasField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper { +public final class AliasField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper, AnnotatedWrapper { final ResolvedJavaField original; final ResolvedJavaField annotated; @@ -90,7 +91,7 @@ public ResolvedJavaType getDeclaringClass() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return original; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java index 0ad0c3c0a279..b6b0818033b8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedField.java @@ -25,10 +25,10 @@ package com.oracle.svm.hosted.substitute; import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; import java.util.List; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.OriginalFieldProvider; @@ -37,8 +37,9 @@ import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; -public class AnnotatedField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper { +public class AnnotatedField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaField original; private final List injectedAnnotations; @@ -49,7 +50,7 @@ public AnnotatedField(ResolvedJavaField original, Annotation injectedAnnotation) } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return original; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java index 939d5b447714..7f8896db4d5f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotatedMethod.java @@ -25,7 +25,6 @@ package com.oracle.svm.hosted.substitute; import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; @@ -38,6 +37,7 @@ import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; import com.oracle.svm.util.AnnotationUtil; import com.oracle.svm.util.OriginalMethodProvider; @@ -54,8 +54,9 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.annotation.Annotated; -public class AnnotatedMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper { +public class AnnotatedMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaMethod original; private final ResolvedJavaMethod annotated; @@ -197,7 +198,7 @@ public List getInjectedAnnotations() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return original; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java index f6527d1a57f1..b2ab673a86de 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/InjectedFieldsType.java @@ -24,14 +24,14 @@ */ package com.oracle.svm.hosted.substitute; -import java.lang.reflect.AnnotatedElement; import java.util.Arrays; import java.util.List; -import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.core.annotate.Inject; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalClassProvider; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; @@ -43,6 +43,7 @@ import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; /** * Type which {@linkplain Inject injects} individual members into its original type (and can alias @@ -50,7 +51,7 @@ * * @see SubstitutionType */ -public class InjectedFieldsType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper { +public class InjectedFieldsType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaType original; @@ -235,7 +236,7 @@ public ResolvedJavaField[] getStaticFields() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return original; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java index b653256c2d78..d983b7bd5567 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/PolymorphicSignatureWrapperMethod.java @@ -29,13 +29,11 @@ import java.lang.annotation.Annotation; import java.lang.invoke.MethodHandle; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.svm.util.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.invoke.MethodHandleUtils; @@ -43,6 +41,8 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationWrapper; import com.oracle.svm.hosted.phases.HostedGraphKit; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalMethodProvider; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.CallTargetNode; @@ -62,13 +62,14 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.annotation.Annotated; /** * Creates a wrapper around a {@link java.lang.invoke.MethodHandle}.PolymorphicSignature method that * assembles the arguments into an array, performing necessary boxing operations. The wrapper then * transfers execution to the underlying varargs method. */ -public class PolymorphicSignatureWrapperMethod implements ResolvedJavaMethod, GraphProvider, AnnotationWrapper, OriginalMethodProvider { +public class PolymorphicSignatureWrapperMethod implements ResolvedJavaMethod, GraphProvider, AnnotationWrapper, AnnotatedWrapper, OriginalMethodProvider { private final SubstitutionMethod substitutionBaseMethod; private final ResolvedJavaMethod originalMethod; @@ -342,7 +343,7 @@ public SpeculationLog getSpeculationLog() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return substitutionBaseMethod; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java index c05e54f28a71..4544691813b2 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionField.java @@ -24,17 +24,17 @@ */ package com.oracle.svm.hosted.substitute; -import java.lang.reflect.AnnotatedElement; - -import com.oracle.svm.util.OriginalFieldProvider; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalFieldProvider; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaType; import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; -public class SubstitutionField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper { +public class SubstitutionField implements ResolvedJavaField, OriginalFieldProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaField original; private final ResolvedJavaField annotated; @@ -99,7 +99,7 @@ public ResolvedJavaType getDeclaringClass() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return annotated; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java index a1049eafda0f..5d3e24809097 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionMethod.java @@ -28,14 +28,14 @@ import static com.oracle.svm.core.util.VMError.shouldNotReachHereAtRuntime; import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Type; import com.oracle.graal.pointsto.infrastructure.GraphProvider; -import com.oracle.svm.util.OriginalMethodProvider; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalMethodProvider; import jdk.graal.compiler.debug.DebugContext; import jdk.graal.compiler.nodes.StructuredGraph; @@ -50,8 +50,9 @@ import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; +import jdk.vm.ci.meta.annotation.Annotated; -public class SubstitutionMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper { +public class SubstitutionMethod implements ResolvedJavaMethod, GraphProvider, OriginalMethodProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaMethod original; private final ResolvedJavaMethod annotated; @@ -218,7 +219,7 @@ public ConstantPool getConstantPool() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return annotated; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java index c639084c2ec8..176a1ccc7d80 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/SubstitutionType.java @@ -24,15 +24,15 @@ */ package com.oracle.svm.hosted.substitute; -import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; -import com.oracle.svm.util.OriginalClassProvider; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.annotation.AnnotationWrapper; +import com.oracle.svm.util.AnnotatedWrapper; +import com.oracle.svm.util.OriginalClassProvider; import jdk.vm.ci.common.JVMCIError; import jdk.vm.ci.meta.Assumptions.AssumptionResult; @@ -44,13 +44,14 @@ import jdk.vm.ci.meta.ResolvedJavaRecordComponent; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.UnresolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; /** * Type which fully substitutes its original type, i.e. @{@link Substitute} on the class level. * * @see InjectedFieldsType */ -public class SubstitutionType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper { +public class SubstitutionType implements ResolvedJavaType, OriginalClassProvider, AnnotationWrapper, AnnotatedWrapper { private final ResolvedJavaType original; private final ResolvedJavaType annotated; @@ -273,7 +274,7 @@ public ResolvedJavaField[] getStaticFields() { } @Override - public AnnotatedElement getAnnotationRoot() { + public Annotated getWrappedAnnotated() { return annotated; } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccess.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccess.java new file mode 100644 index 000000000000..f7b97dad6e2f --- /dev/null +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccess.java @@ -0,0 +1,533 @@ +/* + * Copyright (c) 2022, 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 com.oracle.svm.util; + +import java.lang.annotation.Annotation; +import java.lang.annotation.AnnotationFormatError; +import java.lang.annotation.Inherited; +import java.lang.reflect.Array; +import java.lang.reflect.GenericSignatureFormatError; +import java.nio.BufferUnderflowException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import jdk.graal.compiler.annotation.AnnotationValue; +import jdk.graal.compiler.annotation.AnnotationValueSupport; +import jdk.graal.compiler.annotation.ElementTypeMismatch; +import jdk.graal.compiler.annotation.EnumElement; +import jdk.graal.compiler.annotation.MissingType; +import jdk.graal.compiler.annotation.TypeAnnotationValue; +import jdk.graal.compiler.util.CollectionsUtil; +import jdk.graal.compiler.util.EconomicHashMap; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaRecordComponent; +import jdk.vm.ci.meta.ResolvedJavaType; +import jdk.vm.ci.meta.annotation.Annotated; +import sun.reflect.annotation.AnnotationParser; +import sun.reflect.annotation.AnnotationSupport; +import sun.reflect.annotation.AnnotationType; +import sun.reflect.annotation.TypeNotPresentExceptionProxy; + +/** + * Provides methods to query annotation information on {@link Annotated} objects. Caches are + * employed to speed up most queries. + */ +@Platforms(Platform.HOSTED_ONLY.class) +public class AnnotatedObjectAccess { + private final Map> annotationCache = new ConcurrentHashMap<>(); + private final Map> declaredAnnotationCache = new ConcurrentHashMap<>(); + private final Map>> parameterAnnotationCache = new ConcurrentHashMap<>(); + private final Map> typeAnnotationCache = new ConcurrentHashMap<>(); + private final Map annotationDefaultCache = new ConcurrentHashMap<>(); + private final Map resolvedAnnotationsCache = new ConcurrentHashMap<>(); + + /** + * Gets the annotation of type {@code annotationType} from {@code element}. + * + * @param element the annotated element to retrieve the annotation value from + * @param annotationType the type of annotation to retrieve + * @return the annotation value of the specified type, or null if no such annotation exists + */ + public T getAnnotation(Annotated element, Class annotationType) { + // Checkstyle: allow direct annotation access + Inherited inherited = annotationType.getAnnotation(Inherited.class); + // Checkstyle: disallow direct annotation access + Map annotationValues = getAnnotationValues(element, inherited == null); + AnnotationValue annotationValue = annotationValues.get(GraalAccess.lookupType(annotationType)); + if (annotationValue != null) { + return asAnnotation(annotationValue, annotationType); + } + return null; + } + + /** + * Gets the annotation of type {@code annotationType} from {@code annotated}. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private static AnnotationValue toAnnotationValue(Annotation annotation) { + ResolvedJavaType type = GraalAccess.lookupType(annotation.annotationType()); + Map values = AnnotationSupport.memberValues(annotation); + Map.Entry[] elements = new Map.Entry[values.size()]; + int i = 0; + for (Map.Entry e : values.entrySet()) { + String name = e.getKey(); + Object aElement = e.getValue(); + Object avElement = toAnnotationValueElement(aElement); + elements[i++] = Map.entry(name, avElement); + } + return new AnnotationValue(type, CollectionsUtil.mapOfEntries(elements)); + } + + private static final Class AnnotationTypeMismatchExceptionProxy = ReflectionUtil.lookupClass("sun.reflect.annotation.AnnotationTypeMismatchExceptionProxy"); + + /** + * Converts an annotation element value from its core reflection representation to its JVMCI + * representation. That is, this method converts a value as found in the map returned by + * {@link AnnotationSupport#memberValues(Annotation)} to the corresponding value in the map + * returned by {@link AnnotationValue#getElements()}. + *

    + * This is the inverse of the conversion performed by + * {@link #toAnnotationElement(Class, Object)}. + * + * @param aElement core reflection representation of an annotation element value + * @return the JVMCI representation of the same value + */ + private static Object toAnnotationValueElement(Object aElement) { + return switch (aElement) { + case Enum ev -> new EnumElement(GraalAccess.lookupType(aElement.getClass()), ev.name()); + case Class cls -> GraalAccess.lookupType(cls); + case Annotation a -> toAnnotationValue(a); + case TypeNotPresentExceptionProxy proxy -> new MissingType(proxy.typeName(), proxy.getCause()); + default -> { + Class valueType = aElement.getClass(); + if (valueType.isArray()) { + int length = Array.getLength(aElement); + Object[] array = new Object[length]; + for (int i = 0; i < length; i++) { + array[i] = toAnnotationValueElement(Array.get(aElement, i)); + } + yield List.of(array); + } else if (AnnotationTypeMismatchExceptionProxy.isInstance(aElement)) { + String foundType = ReflectionUtil.readField(AnnotationTypeMismatchExceptionProxy, "foundType", aElement); + yield new ElementTypeMismatch(foundType); + } else { + yield aElement; + } + } + }; + } + + /** + * Converts an annotation element value from its JVMCI representation to its core reflection + * representation. That is, this method converts a value as found in the map returned by + * {@link AnnotationValue#getElements()} to the corresponding value in the map returned by + * {@link AnnotationSupport#memberValues(Annotation)}. + *

    + * This is the inverse of the conversion performed by {@link #toAnnotationValueElement(Object)}. + * + * @param returnType the return type of the method representing the annotation element whose + * value is being converted + * @param avElement the annotation element value to convert + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private static Object toAnnotationElement(Class returnType, Object avElement) { + switch (avElement) { + case EnumElement ee -> { + Class enumType = (Class) OriginalClassProvider.getJavaClass(ee.enumType); + return Enum.valueOf(enumType, ee.name); + } + case ResolvedJavaType rjt -> { + return OriginalClassProvider.getJavaClass(rjt); + } + case AnnotationValue av -> { + Class type = (Class) OriginalClassProvider.getJavaClass(av.getAnnotationType()); + return toAnnotation(av, type); + } + case List adList -> { + int length = adList.size(); + if (returnType == byte[].class) { + byte[] result = new byte[length]; + for (int i = 0; i < length; i++) { + result[i] = (byte) adList.get(i); + } + return result; + } + if (returnType == char[].class) { + char[] result = new char[length]; + for (int i = 0; i < length; i++) { + result[i] = (char) adList.get(i); + } + return result; + } + if (returnType == short[].class) { + short[] result = new short[length]; + for (int i = 0; i < length; i++) { + result[i] = (short) adList.get(i); + } + return result; + } + if (returnType == int[].class) { + int[] result = new int[length]; + for (int i = 0; i < length; i++) { + result[i] = (int) adList.get(i); + } + return result; + } + if (returnType == float[].class) { + float[] result = new float[length]; + for (int i = 0; i < length; i++) { + result[i] = (float) adList.get(i); + } + return result; + } + if (returnType == long[].class) { + long[] result = new long[length]; + for (int i = 0; i < length; i++) { + result[i] = (long) adList.get(i); + } + return result; + } + if (returnType == double[].class) { + double[] result = new double[length]; + for (int i = 0; i < length; i++) { + result[i] = (double) adList.get(i); + } + return result; + } + if (returnType == boolean[].class) { + boolean[] result = new boolean[length]; + for (int i = 0; i < length; i++) { + result[i] = (boolean) adList.get(i); + } + return result; + } + Class componentType = returnType.getComponentType(); + assert componentType != null && !componentType.isArray() && !componentType.isPrimitive() : componentType; + Object[] result = (Object[]) Array.newInstance(componentType, length); + for (int i = 0; i < length; i++) { + result[i] = toAnnotationElement(componentType, adList.get(i)); + } + return result; + } + default -> { + return avElement; + } + } + } + + /** + * Converts {@code annotationValue} to an instance of {@code type}. + */ + private static T toAnnotation(AnnotationValue annotationValue, Class type) { + AnnotationType annotationType = AnnotationType.getInstance(type); + Map memberValues = new EconomicHashMap<>(); + for (var e : annotationType.members().entrySet()) { + String name = e.getKey(); + Object o = annotationValue.get(name, Object.class); + memberValues.put(name, toAnnotationElement(e.getValue().getReturnType(), o)); + } + return type.cast(AnnotationParser.annotationForMap(type, memberValues)); + } + + /** + * Retrieves the annotation of type {@code annotationType} from {@code element}, considering + * only declared annotations iff {@code declaredOnly} is true. + * + * @param element the annotated element to retrieve the annotation value from + * @param annotationType the type of annotation to retrieve + * @param declaredOnly whether to consider only declared annotations + * @return the annotation value of the specified type, or null if no such annotation exists + */ + @SuppressWarnings("unchecked") + protected T getAnnotation(Annotated element, Class annotationType, boolean declaredOnly) { + Map annotationValues = getAnnotationValues(element, declaredOnly); + AnnotationValue annotation = annotationValues.get(GraalAccess.lookupType(annotationType)); + if (annotation != null) { + return (T) resolvedAnnotationsCache.computeIfAbsent(annotation, value -> toAnnotation(value, annotationType)); + } + return null; + } + + private static String loaderName(ClassLoader loader) { + if (loader == null) { + return "null"; + } + var loaderName = loader.getName(); + if (loaderName == null || loaderName.isBlank()) { + return loader.getClass().getName(); + } else { + return loaderName; + } + } + + /** + * Converts an {@link AnnotationValue} to an {@link Annotation} of type {@code annotationType}. + */ + public T asAnnotation(AnnotationValue annotationValue, Class annotationType) { + T res = annotationType.cast(resolvedAnnotationsCache.computeIfAbsent(annotationValue, value -> toAnnotation(value, annotationType))); + Class resType = res.annotationType(); + if (!resType.equals(annotationType)) { + + throw new IllegalArgumentException("Conversion failed: expected %s (loader: %s), got %s (loader: %s)".formatted( + annotationType.getName(), loaderName(annotationType.getClassLoader()), + resType.getName(), loaderName(resType.getClassLoader()))); + } + return res; + } + + /** + * Converts an {@link Annotation} to an {@link AnnotationValue}. + */ + public AnnotationValue asAnnotationValue(Annotation annotation) { + return toAnnotationValue(annotation); + } + + protected boolean hasAnnotation(Annotated element, Class annotationType) { + try { + return getAnnotationValues(element, false).containsKey(GraalAccess.lookupType(annotationType)); + } catch (LinkageError e) { + /* + * Returning false essentially means that the element doesn't declare the + * annotationType, but we cannot know that since the annotation parsing failed. However, + * this allows us to defend against crashing the image builder if the user code + * references types missing from the classpath. + */ + return false; + } + } + + /** + * Gets the declared annotations of {@code element}. + */ + public Map getDeclaredAnnotationValues(Annotated element) { + return getAnnotationValues(element, true); + } + + protected Map getAnnotationValues(Annotated element, boolean declaredOnly) { + Map result = null; + List annotationValues = new ArrayList<>(); + Annotated root = unwrap(element, annotationValues); + if (root instanceof AnnotationsContainer ac) { + List annotations = ac.getContainedAnnotations(); + if (annotations.isEmpty()) { + return Map.of(); + } + result = new EconomicHashMap<>(annotations.size()); + for (var a : annotations) { + AnnotationValue annotationValue = toAnnotationValue(a); + result.put(annotationValue.getAnnotationType(), annotationValue); + } + } else { + if (root != null) { + if (declaredOnly) { + annotationValues.addAll(getDeclaredAnnotationValuesFromRoot(root).values()); + } else { + annotationValues.addAll(getAnnotationValuesFromRoot(root).values()); + } + } + if (!annotationValues.isEmpty()) { + result = new EconomicHashMap<>(annotationValues.size()); + for (AnnotationValue a : annotationValues) { + ResolvedJavaType annotationType = a.isError() ? ANNOTATION_FORMAT_ERROR_TYPE : a.getAnnotationType(); + result.put(annotationType, a); + } + } + } + return result == null ? Map.of() : result; + } + + /** + * Gets the annotations on the super class hierarchy of {@code clazz} that are annotated by + * {@link Inherited}. + */ + private Map getInheritableAnnotations(ResolvedJavaType clazz) { + Map inheritedAnnotations = null; + ResolvedJavaType superClass = clazz.getSuperclass(); + if (superClass != null) { + for (var e : getAnnotationValuesFromRoot(superClass).entrySet()) { + ResolvedJavaType annotationType = e.getKey(); + if (hasAnnotation(annotationType, Inherited.class)) { + if (inheritedAnnotations == null) { + inheritedAnnotations = new EconomicHashMap<>(); + } + inheritedAnnotations.put(annotationType, e.getValue()); + } + } + } + return inheritedAnnotations; + } + + private Map getAnnotationValuesFromRoot(Annotated rootElement) { + if (!(rootElement instanceof ResolvedJavaType clazz)) { + return getDeclaredAnnotationValuesFromRoot(rootElement); + } + + Map existing = annotationCache.get(clazz); + if (existing != null) { + return existing; + } + + /* + * Inheritable annotations must be computed first to avoid recursively updating + * annotationCache. + */ + Map inheritableAnnotations = getInheritableAnnotations(clazz); + return annotationCache.computeIfAbsent(clazz, element -> { + Map declaredAnnotations = getDeclaredAnnotationValuesFromRoot(element); + Map annotations = null; + if (inheritableAnnotations != null) { + for (var e : inheritableAnnotations.entrySet()) { + if (!declaredAnnotations.containsKey(e.getKey())) { + if (annotations == null) { + annotations = new EconomicHashMap<>(declaredAnnotations); + } + annotations.put(e.getKey(), e.getValue()); + } + } + } + return annotations != null ? annotations : declaredAnnotations; + }); + } + + private Map getDeclaredAnnotationValuesFromRoot(Annotated rootElement) { + return declaredAnnotationCache.computeIfAbsent(rootElement, AnnotatedObjectAccess::parseDeclaredAnnotationValues); + } + + /** + * Annotation type for a {@link AnnotationValue#isError() value representing a parse error}. + */ + public static final ResolvedJavaType ANNOTATION_FORMAT_ERROR_TYPE = GraalAccess.lookupType(Void.TYPE); + + private static Map parseDeclaredAnnotationValues(Annotated element) { + try { + return AnnotationValueSupport.getDeclaredAnnotationValues(element); + } catch (AnnotationFormatError e) { + return Map.of(ANNOTATION_FORMAT_ERROR_TYPE, new AnnotationValue(e)); + } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { + return Map.of(ANNOTATION_FORMAT_ERROR_TYPE, new AnnotationValue(new AnnotationFormatError(e))); + } + } + + /** + * Gets the annotation values associated with the parameters of {@code element}. + * + * @param element the annotated element to retrieve parameter annotation values from + * @return a list of lists, where each inner list contains the annotation values for a single + * parameter of the annotated element, or an empty list if the element has no parameters + * or no annotations + */ + public List> getParameterAnnotationValues(Annotated element) { + Annotated root = unwrap(element, null); + return root != null ? getParameterAnnotationValuesFromRoot((ResolvedJavaMethod) root) : List.of(); + } + + private List> getParameterAnnotationValuesFromRoot(ResolvedJavaMethod rootElement) { + return parameterAnnotationCache.computeIfAbsent(rootElement, element -> { + try { + List> parameterAnnotationValues = AnnotationValueSupport.getParameterAnnotationValues(element); + return parameterAnnotationValues == null ? List.of() : parameterAnnotationValues; + } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { + return List.of(List.of(new AnnotationValue(new AnnotationFormatError(e)))); + } catch (AnnotationFormatError e) { + return List.of(List.of(new AnnotationValue(e))); + } + }); + } + + /** + * Gets the type annotations associated with {@code element}. + * + * @param element the annotated element to retrieve type annotations from + * @return a list of type annotations, or an empty list if none exist + */ + public List getTypeAnnotationValues(Annotated element) { + Annotated root = unwrap(element, null); + return root != null ? getTypeAnnotationValuesFromRoot(root) : List.of(); + } + + private List getTypeAnnotationValuesFromRoot(Annotated rootElement) { + return typeAnnotationCache.computeIfAbsent(rootElement, AnnotatedObjectAccess::parseTypeAnnotationValues); + } + + private static List parseTypeAnnotationValues(Annotated element) { + try { + return switch (element) { + case ResolvedJavaType type -> AnnotationValueSupport.getTypeAnnotationValues(type); + case ResolvedJavaMethod method -> AnnotationValueSupport.getTypeAnnotationValues(method); + case ResolvedJavaField field -> AnnotationValueSupport.getTypeAnnotationValues(field); + case ResolvedJavaRecordComponent recordComponent -> + AnnotationValueSupport.getTypeAnnotationValues(recordComponent); + default -> + throw new AnnotatedObjectAccessError(element, "Unexpected annotated element type: " + element.getClass()); + }; + } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { + return List.of(new TypeAnnotationValue(new AnnotationFormatError(e))); + } catch (AnnotationFormatError e) { + return List.of(new TypeAnnotationValue(e)); + } + } + + /** + * Gets the default value for the annotation member represented by {@code method}. + * + * @see AnnotationValueSupport#getAnnotationDefaultValue + */ + public Object getAnnotationDefaultValue(Annotated method) { + Annotated root = unwrap(method, null); + return root != null ? getAnnotationDefaultValueFromRoot((ResolvedJavaMethod) root) : null; + } + + private Object getAnnotationDefaultValueFromRoot(ResolvedJavaMethod accessorMethod) { + return annotationDefaultCache.computeIfAbsent(accessorMethod, method -> { + try { + return AnnotationValueSupport.getAnnotationDefaultValue(method); + } catch (IllegalArgumentException | BufferUnderflowException | GenericSignatureFormatError e) { + return new AnnotationFormatError(e); + } catch (AnnotationFormatError e) { + return e; + } + }); + } + + private static Annotated unwrap(Annotated element, List injectedAnnotationsCollector) { + Annotated cur = element; + while (cur instanceof AnnotatedWrapper wrapper) { + if (injectedAnnotationsCollector != null) { + List injectedAnnotations = wrapper.getInjectedAnnotations(); + if (injectedAnnotations != null) { + injectedAnnotationsCollector.addAll(injectedAnnotations); + } + } + cur = wrapper.getWrappedAnnotated(); + } + return cur; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExtractionError.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccessError.java similarity index 75% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExtractionError.java rename to substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccessError.java index cbb9b515eda8..23917ee5a454 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/AnnotationExtractionError.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedObjectAccessError.java @@ -22,15 +22,22 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.svm.hosted.annotation; +package com.oracle.svm.util; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +/** + * Error thrown by {@link AnnotatedObjectAccess} or one of its subclasses. + */ @SuppressWarnings("serial") -public final class AnnotationExtractionError extends Error { - AnnotationExtractionError(Object targetElement, Throwable cause) { +@Platforms(Platform.HOSTED_ONLY.class) +public final class AnnotatedObjectAccessError extends Error { + public AnnotatedObjectAccessError(Object targetElement, Throwable cause) { super("Failed to process '%s': %s".formatted(targetElement, cause), cause); } - AnnotationExtractionError(Object targetElement, String message) { + public AnnotatedObjectAccessError(Object targetElement, String message) { super("Failed to process '%s': %s".formatted(targetElement, message)); } } diff --git a/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedWrapper.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedWrapper.java new file mode 100644 index 000000000000..b6d3bd728bb5 --- /dev/null +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotatedWrapper.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022, 2025, 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.util; + +import java.util.List; + +import jdk.graal.compiler.annotation.AnnotationValue; +import jdk.vm.ci.meta.annotation.Annotated; + +/** + * An annotated element may have its annotations provided by multiple, layered objects that + * implement this interface. A layer can optionally {@linkplain #getInjectedAnnotations() inject + * annotations}. + */ +public interface AnnotatedWrapper { + /** + * Gets the annotated element wrapped by this wrapper. + */ + Annotated getWrappedAnnotated(); + + /** + * Gets the annotations injected by this wrapper. + */ + default List getInjectedAnnotations() { + return List.of(); + } +} 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 a1c1ba0b40b2..3eda89c0ae8b 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,6 +33,8 @@ 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 jdk.graal.compiler.annotation.AnnotationValue; @@ -51,54 +53,38 @@ */ public final class AnnotationUtil { - /** - * Annotation related functionality that is in terms of {@link Annotated} instead of - * {@link java.lang.reflect.AnnotatedElement}. This interface must be implemented by the - * registered {@link AnnotationExtractor} image singleton. - */ - public interface Access { - /** - * Retrieves the annotation of type {@code annotationType} from the given {@code element}. - * - * @param element the annotated element to retrieve the annotation value from - * @param annotationType the type of annotation to retrieve - * @return the annotation value of the specified type, or null if no such annotation exists - */ - T getAnnotation(Annotated element, Class annotationType); - - /** - * Gets the declared annotations of {@code annotated}. - */ - Map getDeclaredAnnotationValues(Annotated element); - - /** - * Converts an {@link AnnotationValue} to an {@link Annotation} of type - * {@code annotationType}. - */ - T asAnnotation(AnnotationValue annotationValue, Class annotationType); - - /** - * Converts an {@link Annotation} to an {@link AnnotationValue}. - */ - AnnotationValue asAnnotationValue(Annotation annotation); + @Platforms(Platform.HOSTED_ONLY.class) + static class Lazy { + static final AnnotatedObjectAccess instance; + static { + if (ImageSingletons.contains(AnnotationExtractor.class)) { + instance = (AnnotatedObjectAccess) ImageSingletons.lookup(AnnotationExtractor.class); + } else { + ModuleSupport.accessPackagesToClass(ModuleSupport.Access.OPEN, AnnotatedObjectAccess.class, false, "java.base", "sun.reflect.annotation"); + instance = new AnnotatedObjectAccess(); + } + } } - private static Access access() { - return (Access) ImageSingletons.lookup(AnnotationExtractor.class); + @Platforms(Platform.HOSTED_ONLY.class) + private static AnnotatedObjectAccess instance() { + return Lazy.instance; } /** * Converts an {@link Annotation} to an {@link AnnotationValue}. */ + @Platforms(Platform.HOSTED_ONLY.class) public static AnnotationValue asAnnotationValue(Annotation annotation) { - return access().asAnnotationValue(annotation); + return instance().asAnnotationValue(annotation); } /** * Gets the declared annotations of {@code annotated}. */ + @Platforms(Platform.HOSTED_ONLY.class) public static Map getDeclaredAnnotationValues(Annotated annotated) { - return access().getDeclaredAnnotationValues(annotated); + return instance().getDeclaredAnnotationValues(annotated); } /** @@ -107,11 +93,13 @@ public static Map getDeclaredAnnotationValues */ public static T getAnnotation(Annotated element, Class annotationType) { // Checkstyle: allow direct annotation access - if (ImageInfo.inImageBuildtimeCode()) { - return access().getAnnotation(element, annotationType); - } else { - return ((AnnotatedElement) element).getAnnotation(annotationType); + if (ImageInfo.inImageRuntimeCode()) { + if (element instanceof AnnotatedElement ae) { + return ae.getAnnotation(annotationType); + } + throw new IllegalArgumentException("Cannot cast " + element.getClass() + " to " + AnnotatedElement.class.getName() + ": " + element); } + return instance().getAnnotation(element, annotationType); // Checkstyle: disallow direct annotation access } @@ -170,8 +158,9 @@ public static boolean isAnnotationPresent(Annotated element, Class T newAnnotation(Class annotationType, Object... elements) { - return access().asAnnotation(newAnnotationValue(annotationType, elements), annotationType); + return instance().asAnnotation(newAnnotationValue(annotationType, elements), annotationType); } /** diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerElement.java b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationsContainer.java similarity index 71% rename from substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerElement.java rename to substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationsContainer.java index 25257ed47860..887df8946494 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/BaseLayerElement.java +++ b/substratevm/src/com.oracle.svm.util/src/com/oracle/svm/util/AnnotationsContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, 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 @@ -22,21 +22,25 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -package com.oracle.graal.pointsto.meta; +package com.oracle.svm.util; import java.lang.annotation.Annotation; +import java.util.List; /** - * Base class for types representing persisted information from the base layer. + * A container for an array of annotations. */ -public class BaseLayerElement { - private final Annotation[] annotations; +public class AnnotationsContainer { + private final List annotations; - public BaseLayerElement(Annotation[] annotations) { - this.annotations = annotations; + public AnnotationsContainer(Annotation[] annotations) { + this.annotations = List.of(annotations); } - public Annotation[] getBaseLayerAnnotations() { + /** + * Gets an immutable view of the contained annotations. + */ + public List getContainedAnnotations() { return annotations; } }