diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java index 8ced71de44e9..211150983501 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java @@ -24,9 +24,6 @@ */ package org.graalvm.compiler.nodes; -import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; -import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; - import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -336,26 +333,12 @@ private StructuredGraph(String name, assert !isSubstitution || profileProvider == null; this.profileProvider = profileProvider; this.isSubstitution = isSubstitution; - assert checkIsSubstitutionInvariants(method, isSubstitution); this.cancellable = cancellable; this.inliningLog = GraalOptions.TraceInlining.getValue(options) || OptimizationLog.isOptimizationLogEnabled(options) ? new InliningLog(rootMethod) : null; this.callerContext = context; this.optimizationLog = OptimizationLog.getInstance(this); } - private static boolean checkIsSubstitutionInvariants(ResolvedJavaMethod method, boolean isSubstitution) { - if (!IS_IN_NATIVE_IMAGE && !IS_BUILDING_NATIVE_IMAGE) { - if (method != null) { - if (method.getAnnotation(Snippet.class) != null) { - assert isSubstitution : "Graph for method " + method.format("%H.%n(%p)") + - " annotated by " + Snippet.class.getName() + - " must have its `isSubstitution` field set to true"; - } - } - } - return true; - } - public void setLastSchedule(ScheduleResult result) { GraalError.guarantee(result == null || result.cfg.getStartBlock().isModifiable(), "Schedule must use blocks that can be modified"); lastSchedule = result; diff --git a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerRuntime.java b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerRuntime.java index 88f1b2d32242..b234aa125e0d 100644 --- a/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerRuntime.java +++ b/compiler/src/org.graalvm.compiler.truffle.common/src/org/graalvm/compiler/truffle/common/TruffleCompilerRuntime.java @@ -125,6 +125,19 @@ public static ConstantFieldInfo forDimensions(int dimensions) { private ConstantFieldInfo(int dimensions) { this.dimensions = dimensions; } + + @Override + public int hashCode() { + return dimensions; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ConstantFieldInfo other) { + return dimensions == other.dimensions; + } + return false; + } } /** diff --git a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java index c77da53676a4..6f78f6086903 100644 --- a/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java +++ b/compiler/src/org.graalvm.compiler.truffle.runtime/src/org/graalvm/compiler/truffle/runtime/GraalTruffleRuntime.java @@ -986,9 +986,6 @@ public final class KnownMethods { public final ResolvedJavaMethod callTargetMethod; public final ResolvedJavaMethod callInlinedCallMethod; public final ResolvedJavaMethod[] anyFrameMethod; - public final ResolvedJavaMethod inInterpreterMethod; - public final ResolvedJavaMethod inInterpreterFastPathMethod; - public final ResolvedJavaMethod[] transferToInterpreterMethods; public KnownMethods(MetaAccessProvider metaAccess) { this.callDirectMethod = metaAccess.lookupJavaMethod(GraalFrameInstance.CALL_DIRECT); @@ -997,26 +994,9 @@ public KnownMethods(MetaAccessProvider metaAccess) { this.callInlinedCallMethod = metaAccess.lookupJavaMethod(GraalFrameInstance.CALL_INLINED_CALL); this.callTargetMethod = metaAccess.lookupJavaMethod(GraalFrameInstance.CALL_TARGET_METHOD); this.anyFrameMethod = new ResolvedJavaMethod[]{callDirectMethod, callIndirectMethod, callInlinedMethod, callTargetMethod, callInlinedCallMethod}; - ResolvedJavaType compilerDirectives = metaAccess.lookupJavaType(CompilerDirectives.class); - this.transferToInterpreterMethods = new ResolvedJavaMethod[2]; - this.transferToInterpreterMethods[0] = searchMethod(compilerDirectives, "transferToInterpreter"); - this.transferToInterpreterMethods[1] = searchMethod(compilerDirectives, "transferToInterpreterAndInvalidate"); - this.inInterpreterMethod = searchMethod(compilerDirectives, "inInterpreter"); - - ResolvedJavaType hostCompilerDirectives = metaAccess.lookupJavaType(HostCompilerDirectives.class); - this.inInterpreterFastPathMethod = searchMethod(hostCompilerDirectives, "inInterpreterFastPath"); } } - protected static ResolvedJavaMethod searchMethod(ResolvedJavaType type, String name) { - for (ResolvedJavaMethod searchMethod : type.getDeclaredMethods()) { - if (searchMethod.getName().equals(name)) { - return searchMethod; - } - } - throw CompilerDirectives.shouldNotReachHere(type + "." + name + " method not found."); - } - @Override public boolean isValueType(ResolvedJavaType type) { return getAnnotation(CompilerDirectives.ValueType.class, type) != null; @@ -1130,16 +1110,16 @@ public boolean isInliningCutoff(ResolvedJavaMethod method) { * Determines if {@code method} is an inInterpeter method. */ @Override - public boolean isInInterpreter(ResolvedJavaMethod targetMethod) { - return getKnownMethods().inInterpreterMethod.equals(targetMethod); + public boolean isInInterpreter(ResolvedJavaMethod method) { + return method.getName().equals("inInterpreter") && method.getDeclaringClass().toClassName().equals(CompilerDirectives.class.getName()); } /** * Determines if {@code method} is an inInterpeter method. */ @Override - public boolean isInInterpreterFastPath(ResolvedJavaMethod targetMethod) { - return getKnownMethods().inInterpreterFastPathMethod.equals(targetMethod); + public boolean isInInterpreterFastPath(ResolvedJavaMethod method) { + return method.getName().equals("inInterpreterFastPath") && method.getDeclaringClass().toClassName().equals(HostCompilerDirectives.class.getName()); } /** @@ -1147,13 +1127,8 @@ public boolean isInInterpreterFastPath(ResolvedJavaMethod targetMethod) { */ @Override public boolean isTransferToInterpreterMethod(ResolvedJavaMethod method) { - ResolvedJavaMethod[] methods = getKnownMethods().transferToInterpreterMethods; - for (int i = 0; i < methods.length; i++) { - if (methods[i].equals(method)) { - return true; - } - } - return false; + return (method.getName().equals("transferToInterpreter") || method.getName().equals("transferToInterpreterAndInvalidate")) && + method.getDeclaringClass().toClassName().equals(CompilerDirectives.class.getName()); } @SuppressWarnings("deprecation") diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java index e8acc824eb4f..9a9189a571b1 100755 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64Backend.java @@ -116,7 +116,6 @@ import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.common.AddressLoweringByUsePhase; import org.graalvm.compiler.phases.util.Providers; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.FrameAccess; @@ -152,7 +151,6 @@ import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.nodes.SafepointCheckNode; -import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.util.VMError; @@ -791,8 +789,8 @@ public Variable emitReadReturnAddress() { @Override public ForeignCallLinkage lookupGraalStub(ValueNode valueNode, ForeignCallDescriptor foreignCallDescriptor) { - ResolvedJavaMethod method = valueNode.graph().method(); - if (method != null && AnnotationAccess.getAnnotation(method, SubstrateForeignCallTarget.class) != null) { + SharedMethod method = (SharedMethod) valueNode.graph().method(); + if (method != null && method.isForeignCallTarget()) { // Emit assembly for snippet stubs return null; } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java index 39a9ccdbb6bc..447f26d7bdd3 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64Backend.java @@ -126,7 +126,6 @@ import org.graalvm.compiler.phases.common.AddressLoweringByNodePhase; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.amd64.AMD64IntrinsicStubs; -import org.graalvm.nativeimage.AnnotationAccess; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.svm.core.CPUFeatureAccess; @@ -170,7 +169,6 @@ import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.nodes.SafepointCheckNode; -import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.thread.VMThreads.StatusSupport; import com.oracle.svm.core.util.VMError; @@ -927,8 +925,8 @@ public Variable emitReadReturnAddress() { @Override public ForeignCallLinkage lookupGraalStub(ValueNode valueNode, ForeignCallDescriptor foreignCallDescriptor) { - ResolvedJavaMethod method = valueNode.graph().method(); - if (method != null && AnnotationAccess.getAnnotation(method, SubstrateForeignCallTarget.class) != null) { + SharedMethod method = (SharedMethod) valueNode.graph().method(); + if (method != null && method.isForeignCallTarget()) { // Emit assembly for snippet stubs return null; } 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 a40d169a22f5..da181b982f05 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 @@ -34,6 +34,8 @@ import org.graalvm.compiler.api.replacements.Fold; import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CFunction; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; import org.graalvm.word.WordBase; @@ -202,10 +204,12 @@ public static Uninterruptible getAnnotation(AnnotatedElement method) { * Returns whether the method is {@link Uninterruptible}, either by explicit annotation of * the method or implicitly due to other annotations. */ + @Platforms(Platform.HOSTED_ONLY.class) public static boolean isUninterruptible(AnnotatedElement method) { return getAnnotation(method) != null; } + @Platforms(Platform.HOSTED_ONLY.class) public static boolean inliningAllowed(AnnotatedElement caller, AnnotatedElement callee) { boolean callerUninterruptible = isUninterruptible(caller); boolean calleeUninterruptible = isUninterruptible(callee); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/ExplicitCallingConvention.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/ExplicitCallingConvention.java index 48ef71a6c18f..8adf7767e460 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/ExplicitCallingConvention.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/ExplicitCallingConvention.java @@ -29,6 +29,12 @@ 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 jdk.vm.ci.meta.ResolvedJavaMethod; + /** * Annotation that overrides the default calling convention used for a method. */ @@ -36,4 +42,18 @@ @Target(value = {ElementType.METHOD}) public @interface ExplicitCallingConvention { SubstrateCallingConventionKind value(); + + class Util { + @Platforms(Platform.HOSTED_ONLY.class) + public static SubstrateCallingConventionKind getCallingConventionKind(ResolvedJavaMethod method, boolean isEntryPoint) { + ExplicitCallingConvention explicitCallingConvention = AnnotationAccess.getAnnotation(method, ExplicitCallingConvention.class); + if (explicitCallingConvention != null) { + return explicitCallingConvention.value(); + } else if (isEntryPoint) { + return SubstrateCallingConventionKind.Native; + } else { + return SubstrateCallingConventionKind.Java; + } + } + } } 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 89a8fc41e18b..fae450689a06 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 @@ -51,6 +51,7 @@ public @interface StubCallingConvention { class Utils { + @Platforms(Platform.HOSTED_ONLY.class) public static boolean hasStubCallingConvention(ResolvedJavaMethod method) { boolean result = false; if (CalleeSavedRegisters.supportedByPlatform()) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateMetaAccessExtensionProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateMetaAccessExtensionProvider.java index d9fbcb54ed69..6d35c08f41eb 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateMetaAccessExtensionProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateMetaAccessExtensionProvider.java @@ -27,7 +27,6 @@ import org.graalvm.compiler.core.common.spi.MetaAccessExtensionProvider; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SharedType; @@ -59,14 +58,14 @@ public boolean isGuaranteedSafepoint(ResolvedJavaMethod method, boolean isDirect // check if the method itself indicates it will not have a safepoint. SharedMethod sharedMethod = (SharedMethod) method; - if (Uninterruptible.Utils.isUninterruptible(sharedMethod)) { + if (sharedMethod.isUninterruptible()) { return false; } // for indirect calls, confirming all implementations also have safepoints. if (!isDirect) { for (SharedMethod implementation : sharedMethod.getImplementations()) { - if (Uninterruptible.Utils.isUninterruptible(implementation)) { + if (implementation.isUninterruptible()) { return false; } } 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 9b9c03878b9e..a4c2c9fe388b 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 @@ -87,6 +87,7 @@ import com.oracle.svm.core.SubstrateTargetDescription; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.VMError; @@ -407,4 +408,13 @@ public Stamp getInjectedStamp(Class type, boolean nonNull) { return StampFactory.forKind(kind); } } + + @Override + public boolean isSnippet(ResolvedJavaMethod method) { + if (method instanceof SharedMethod sharedMethod) { + return sharedMethod.isSnippet(); + } else { + return super.isSnippet(method); + } + } } 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 bac4b90d47ba..9f57a6ff8eaa 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 @@ -30,6 +30,8 @@ import org.graalvm.compiler.phases.common.LoopSafepointInsertionPhase; import org.graalvm.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; import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer; @@ -37,12 +39,15 @@ import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.meta.SharedMethod; +import jdk.vm.ci.meta.ResolvedJavaMethod; + /** * Adds safepoints to loops and at method ends. */ public class SubstrateSafepointInsertionPhase extends LoopSafepointInsertionPhase { - public static boolean needSafepointCheck(SharedMethod method) { + @Platforms(Platform.HOSTED_ONLY.class) + public static boolean needSafepointCheck(ResolvedJavaMethod method) { if (Uninterruptible.Utils.isUninterruptible(method)) { /* Uninterruptible methods must not have a safepoint inserted. */ return false; @@ -62,7 +67,7 @@ public static boolean needSafepointCheck(SharedMethod method) { @Override protected void run(StructuredGraph graph, MidTierContext context) { SharedMethod method = (SharedMethod) graph.method(); - if (!needSafepointCheck(method)) { + if (!method.needSafepointCheck()) { return; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java index 99621ba614d1..1ae6ba72cf88 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/NonSnippetLowerings.java @@ -82,7 +82,6 @@ import com.oracle.svm.core.FrameAccess; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.code.CodeInfoTable; import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.meta.KnownOffsets; @@ -304,7 +303,7 @@ public void lower(FixedNode node, LoweringTool tool) { InvokeKind invokeKind = callTarget.invokeKind(); SharedMethod[] implementations = method.getImplementations(); - if (verifyTypes && !callTarget.isStatic() && receiver.getStackKind() == JavaKind.Object && !Uninterruptible.Utils.isUninterruptible(graph.method())) { + if (verifyTypes && !callTarget.isStatic() && receiver.getStackKind() == JavaKind.Object && !((SharedMethod) graph.method()).isUninterruptible()) { /* * Verify that the receiver is an instance of the class that declares the call * target method. To avoid that the new type check floats above a deoptimization diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SafepointSnippets.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SafepointSnippets.java index 4e2f5f684a10..320dc4ff15a8 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SafepointSnippets.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/SafepointSnippets.java @@ -51,11 +51,11 @@ import org.graalvm.word.LocationIdentity; import com.oracle.svm.core.SubstrateOptions; -import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; +import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.nodes.SafepointCheckNode; import com.oracle.svm.core.thread.Safepoint; @@ -93,7 +93,7 @@ class SafepointLowering implements NodeLoweringProvider { public void lower(SafepointNode node, LoweringTool tool) { if (tool.getLoweringStage() == LoweringTool.StandardLoweringStage.LOW_TIER) { assert SubstrateOptions.MultiThreaded.getValue() : "safepoints are only inserted into the graph in MultiThreaded mode"; - if (Uninterruptible.Utils.isUninterruptible(node.graph().method())) { + if (((SharedMethod) node.graph().method()).isUninterruptible()) { /* Basic sanity check to catch errors during safepoint insertion. */ throw GraalError.shouldNotReachHere("Must not insert safepoints in Uninterruptible code: " + node.stateBefore().toString(Verbosity.Debugger)); // ExcludeFromJacocoGeneratedReport } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java index 4641b40f2cf3..0610261425b5 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckImpl.java @@ -330,7 +330,7 @@ private static StackOverflowError newStackOverflowError0() { } public static boolean needStackOverflowCheck(SharedMethod method) { - if (Uninterruptible.Utils.isUninterruptible(method)) { + if (method.isUninterruptible()) { /* * Uninterruptible methods are allowed to use the yellow and red zones of the stack. * Also, the thread register and stack boundary might not be set up. We cannot do a diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/AnnotationsEncoding.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/AnnotationsEncoding.java deleted file mode 100644 index ab6cd0594a8a..000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/AnnotationsEncoding.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.hub; - -import com.oracle.svm.core.util.VMError; - -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; -import java.util.Set; - -public final class AnnotationsEncoding { - - final Annotation[] allAnnotations; - final int startOfDeclaredAnnotations; - - private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; - private static final AnnotationsEncoding EMPTY_ANNOTATIONS_ENCODING = new AnnotationsEncoding(null, 0); - - private AnnotationsEncoding(Annotation[] allAnnotations, int startOfDeclaredAnnotations) { - this.allAnnotations = allAnnotations; - this.startOfDeclaredAnnotations = startOfDeclaredAnnotations; - } - - @Override - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (other == null || getClass() != other.getClass()) { - return false; - } - AnnotationsEncoding that = (AnnotationsEncoding) other; - return startOfDeclaredAnnotations == that.startOfDeclaredAnnotations && - Arrays.equals(allAnnotations, that.allAnnotations); - } - - @Override - public int hashCode() { - int result = Objects.hash(startOfDeclaredAnnotations); - result = 31 * result + Arrays.hashCode(allAnnotations); - return result; - } - - public Annotation[] getAnnotations() { - return allAnnotations == null ? EMPTY_ANNOTATION_ARRAY : allAnnotations.clone(); - } - - public T getAnnotation(Class annotationClass) { - return filterByType(getAnnotations(), annotationClass); - } - - public Annotation[] getDeclaredAnnotations() { - if (allAnnotations == null) { - return EMPTY_ANNOTATION_ARRAY; - - } - - int size = allAnnotations.length - startOfDeclaredAnnotations; - if (size == 0) { - return EMPTY_ANNOTATION_ARRAY; - } - - Annotation[] declAnns = new Annotation[size]; - System.arraycopy(allAnnotations, startOfDeclaredAnnotations, declAnns, 0, size); - return declAnns; - } - - public T getDeclaredAnnotation(Class annotationClass) { - return filterByType(getDeclaredAnnotations(), annotationClass); - } - - @SuppressWarnings("unchecked") - private static T filterByType(Annotation[] all, Class annotationClass) { - Objects.requireNonNull(annotationClass); - for (Annotation annotation : all) { - if (annotationClass.isInstance(annotation)) { - return (T) annotation; - } - } - return null; - } - - public static AnnotationsEncoding decodeAnnotations(Object annotationsEncoding) { - if (annotationsEncoding == null) { - return EMPTY_ANNOTATIONS_ENCODING; - } else if (annotationsEncoding instanceof ArrayStoreException) { - /* JDK-7183985 was hit at image build time when the annotations were encoded. */ - throw (ArrayStoreException) annotationsEncoding; - } else if (annotationsEncoding instanceof AnnotationsEncoding) { - return (AnnotationsEncoding) annotationsEncoding; - } else { - VMError.shouldNotReachHere("Unexpected encoding for annotations in class: " + annotationsEncoding.getClass().getName()); - return null; - } - } - - public static Object encodeAnnotations(Set allAnnotations, Set declaredAnnotations) { - if (allAnnotations == null || allAnnotations.isEmpty()) { - return null; - } - - if (declaredAnnotations == null || declaredAnnotations.isEmpty()) { - return new AnnotationsEncoding(allAnnotations.toArray(new Annotation[0]), allAnnotations.size()); - } - - assert allAnnotations.size() >= declaredAnnotations.size(); - List head = new ArrayList<>(); - List tail = new ArrayList<>(); - for (Annotation a : allAnnotations) { - if (!declaredAnnotations.contains(a)) { - head.add(a); - } else { - tail.add(a); - } - } - - int position = head.size(); - Annotation[] encoding = new Annotation[head.size() + tail.size()]; - System.arraycopy(head.toArray(new Annotation[0]), 0, encoding, 0, head.size()); - System.arraycopy(tail.toArray(new Annotation[0]), 0, encoding, position, tail.size()); - - return new AnnotationsEncoding(encoding, position); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java index bb92b699b0ed..f13abcd839f3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/meta/SharedMethod.java @@ -26,7 +26,6 @@ import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.deopt.Deoptimizer; -import com.oracle.svm.core.graal.code.ExplicitCallingConvention; import com.oracle.svm.core.graal.code.SubstrateCallingConventionKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -36,22 +35,21 @@ */ public interface SharedMethod extends ResolvedJavaMethod { + boolean isUninterruptible(); + + boolean needSafepointCheck(); + /** * Returns true if this method is a native entry point, i.e., called from C code. The method * must not be called from Java code then. */ boolean isEntryPoint(); - default SubstrateCallingConventionKind getCallingConventionKind() { - ExplicitCallingConvention explicitCallingConvention = getAnnotation(ExplicitCallingConvention.class); - if (explicitCallingConvention != null) { - return explicitCallingConvention.value(); - } else if (isEntryPoint()) { - return SubstrateCallingConventionKind.Native; - } else { - return SubstrateCallingConventionKind.Java; - } - } + boolean isSnippet(); + + boolean isForeignCallTarget(); + + SubstrateCallingConventionKind getCallingConventionKind(); boolean hasCalleeSavedRegisters(); diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java index 52a25bc0a4b9..fb84a893ff97 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSupport.java @@ -38,7 +38,6 @@ import java.util.function.Function; import org.graalvm.collections.EconomicMap; -import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.gen.NodeMatchRules; @@ -382,7 +381,7 @@ public static StructuredGraph decodeGraph(DebugContext debug, String name, Compi return null; } - boolean isSubstitution = method.getAnnotation(Snippet.class) != null; + boolean isSubstitution = method.isSnippet(); StructuredGraph graph = new StructuredGraph.Builder(debug.getOptions(), debug) .name(name) .method(method) diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index b0da261a6991..9ecac57ac322 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -25,7 +25,6 @@ package com.oracle.svm.graal.hosted; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -48,7 +47,6 @@ import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; @@ -63,11 +61,10 @@ import com.oracle.svm.graal.meta.SubstrateMethod; import com.oracle.svm.graal.meta.SubstrateSignature; import com.oracle.svm.graal.meta.SubstrateType; +import com.oracle.svm.graal.meta.SubstrateUniverseFactory; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.ameta.AnalysisConstantFieldProvider; import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; -import com.oracle.svm.hosted.ameta.ReadableJavaField; -import com.oracle.svm.hosted.analysis.AnnotationsProcessor; import com.oracle.svm.hosted.meta.HostedConstantFieldProvider; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; @@ -98,37 +95,33 @@ public class GraalGraphObjectReplacer implements Function { private final AnalysisUniverse aUniverse; - private final AnalysisMetaAccess aMetaAccess; private final HashMap methods = new HashMap<>(); private final HashMap fields = new HashMap<>(); private final HashMap fieldLocationIdentities = new HashMap<>(); private final HashMap types = new HashMap<>(); private final HashMap signatures = new HashMap<>(); private final SubstrateProviders sProviders; + private final SubstrateUniverseFactory universeFactory; private SubstrateGraalRuntime sGraalRuntime; private final HostedStringDeduplication stringTable; - private final Field substrateFieldAnnotationsEncodingField; private final Field substrateFieldTypeField; private final Field substrateFieldDeclaringClassField; private final Field dynamicHubMetaTypeField; private final Field substrateTypeRawAllInstanceFieldsField; private final Field substrateMethodImplementationsField; - private final Field substrateMethodAnnotationsEncodingField; - public GraalGraphObjectReplacer(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, SubstrateProviders sProviders) { + public GraalGraphObjectReplacer(AnalysisUniverse aUniverse, SubstrateProviders sProviders, SubstrateUniverseFactory universeFactory) { this.aUniverse = aUniverse; - this.aMetaAccess = aMetaAccess; this.sProviders = sProviders; + this.universeFactory = universeFactory; this.stringTable = HostedStringDeduplication.singleton(); - substrateFieldAnnotationsEncodingField = ReflectionUtil.lookupField(SubstrateField.class, "annotationsEncoding"); substrateFieldTypeField = ReflectionUtil.lookupField(SubstrateField.class, "type"); substrateFieldDeclaringClassField = ReflectionUtil.lookupField(SubstrateField.class, "declaringClass"); dynamicHubMetaTypeField = ReflectionUtil.lookupField(DynamicHub.class, "metaType"); substrateTypeRawAllInstanceFieldsField = ReflectionUtil.lookupField(SubstrateType.class, "rawAllInstanceFields"); substrateMethodImplementationsField = ReflectionUtil.lookupField(SubstrateMethod.class, "implementations"); - substrateMethodAnnotationsEncodingField = ReflectionUtil.lookupField(SubstrateMethod.class, "annotationsEncoding"); } public void setGraalRuntime(SubstrateGraalRuntime sGraalRuntime) { @@ -230,7 +223,7 @@ public synchronized SubstrateMethod createMethod(ResolvedJavaMethod original) { SubstrateMethod sMethod = methods.get(aMethod); if (sMethod == null) { assert !(original instanceof HostedMethod) : "too late to create new method"; - sMethod = new SubstrateMethod(aMethod, stringTable); + sMethod = universeFactory.createMethod(aMethod, stringTable); methods.put(aMethod, sMethod); /* @@ -238,12 +231,6 @@ public synchronized SubstrateMethod createMethod(ResolvedJavaMethod original) { * infinite recursion. */ sMethod.setLinks(createSignature(aMethod.getSignature()), createType(aMethod.getDeclaringClass())); - - /* - * Annotations are updated in every analysis iteration, but this is a starting point. It - * also ensures that all types used by annotations are created eagerly. - */ - setAnnotationsEncoding(aMethod, sMethod, null); } return sMethod; } @@ -263,23 +250,12 @@ public synchronized SubstrateField createField(ResolvedJavaField original) { if (sField == null) { assert !(original instanceof HostedField) : "too late to create new field"; - - int modifiers = aField.getModifiers(); - if (ReadableJavaField.injectFinalForRuntimeCompilation(aField.wrapped)) { - modifiers = modifiers | Modifier.FINAL; - } - sField = new SubstrateField(aField, modifiers, stringTable); + sField = universeFactory.createField(aField, stringTable); fields.put(aField, sField); sField.setLinks(createType(aField.getType()), createType(aField.getDeclaringClass())); aUniverse.getHeapScanner().rescanField(sField, substrateFieldTypeField); aUniverse.getHeapScanner().rescanField(sField, substrateFieldDeclaringClassField); - - /* - * Annotations are updated in every analysis iteration, but this is a starting point. It - * also ensures that all types used by annotations are created eagerly. - */ - setAnnotationsEncoding(aField, sField, null); } return sField; } @@ -408,42 +384,9 @@ public boolean updateDataDuringAnalysis() { } } - for (Map.Entry entry : methods.entrySet()) { - AnalysisMethod aMethod = entry.getKey(); - SubstrateMethod sMethod = entry.getValue(); - if (setAnnotationsEncoding(aMethod, sMethod, sMethod.getAnnotationsEncoding())) { - result = true; - } - } - for (Map.Entry entry : fields.entrySet()) { - AnalysisField aField = entry.getKey(); - SubstrateField sField = entry.getValue(); - if (setAnnotationsEncoding(aField, sField, sField.getAnnotationsEncoding())) { - result = true; - } - } - return result; } - private boolean setAnnotationsEncoding(AnalysisMethod aMethod, SubstrateMethod sMethod, Object oldEncoding) { - Object annotationsEncoding = AnnotationsProcessor.encodeAnnotations(aMetaAccess, aMethod.getAnnotations(), aMethod.getDeclaredAnnotations(), oldEncoding); - if (sMethod.setAnnotationsEncoding(annotationsEncoding)) { - aUniverse.getHeapScanner().rescanField(sMethod, substrateMethodAnnotationsEncodingField); - return true; - } - return false; - } - - private boolean setAnnotationsEncoding(AnalysisField aField, SubstrateField sField, Object oldEncoding) { - Object annotationsEncoding = AnnotationsProcessor.encodeAnnotations(aMetaAccess, aField.getAnnotations(), aField.getDeclaredAnnotations(), oldEncoding); - if (sField.setAnnotationsEncoding(annotationsEncoding)) { - aUniverse.getHeapScanner().rescanField(sField, substrateFieldAnnotationsEncodingField); - return true; - } - return false; - } - /** * Updates all relevant data from universe building. Object replacement is done during analysis. * Therefore all substrate VM related data has to be updated after building the substrate diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java index 8268098ef832..720e278519a0 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java @@ -93,6 +93,7 @@ import com.oracle.svm.graal.meta.SubstrateField; import com.oracle.svm.graal.meta.SubstrateMethod; import com.oracle.svm.graal.meta.SubstrateType; +import com.oracle.svm.graal.meta.SubstrateUniverseFactory; import com.oracle.svm.hosted.FeatureHandler; import com.oracle.svm.hosted.FeatureImpl.AfterHeapLayoutAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; @@ -337,6 +338,8 @@ private static List getCallTraceHelper(AbstractCallTreeNode node) { protected RuntimeCompilationCandidatePredicate runtimeCompilationCandidatePredicate; protected Predicate deoptimizeOnExceptionPredicate; + private SubstrateUniverseFactory universeFactory = new SubstrateUniverseFactory(); + public HostedProviders getHostedProviders() { return hostedProviders; } @@ -352,6 +355,10 @@ protected static List> getRequiredFeaturesHelper() { return List.of(RuntimeCompilationCanaryFeature.class, DeoptimizationFeature.class, FieldsOffsetsFeature.class); } + public void setUniverseFactory(SubstrateUniverseFactory universeFactory) { + this.universeFactory = universeFactory; + } + protected final void duringSetupHelper(DuringSetupAccess c) { if (SubstrateOptions.useLLVMBackend()) { throw UserError.abort("Runtime compilation is currently unimplemented on the LLVM backend (GR-43073)."); @@ -364,7 +371,7 @@ protected final void duringSetupHelper(DuringSetupAccess c) { DuringSetupAccessImpl config = (DuringSetupAccessImpl) c; AnalysisMetaAccess aMetaAccess = config.getMetaAccess(); SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(aMetaAccess); - objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), aMetaAccess, substrateProviders); + objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, universeFactory); config.registerObjectReplacer(objectReplacer); config.registerClassReachabilityListener(GraalSupport::registerPhaseStatistics); 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 5ee134ebd7f3..7d6b8ba7e47c 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 @@ -27,22 +27,23 @@ import static com.oracle.svm.core.util.VMError.unimplemented; import java.lang.annotation.Annotation; +import java.lang.reflect.Modifier; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; +import com.oracle.graal.pointsto.meta.AnalysisField; import com.oracle.svm.core.heap.UnknownObjectField; import com.oracle.svm.core.heap.UnknownPrimitiveField; -import com.oracle.svm.core.hub.AnnotationsEncoding; import com.oracle.svm.core.meta.DirectSubstrateObjectConstant; import com.oracle.svm.core.meta.SharedField; import com.oracle.svm.core.util.HostedStringDeduplication; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.ameta.ReadableJavaField; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.PrimitiveConstant; -import jdk.vm.ci.meta.ResolvedJavaField; public class SubstrateField implements SharedField { @@ -53,7 +54,6 @@ public class SubstrateField implements SharedField { private final String name; private final int modifiers; private int hashCode; - private Object annotationsEncoding; @UnknownPrimitiveField int location; @UnknownPrimitiveField private boolean isAccessed; @@ -61,24 +61,15 @@ public class SubstrateField implements SharedField { @UnknownObjectField(types = {DirectSubstrateObjectConstant.class, PrimitiveConstant.class}, fullyQualifiedTypes = "jdk.vm.ci.meta.NullConstant")// JavaConstant constantValue; - public SubstrateField(ResolvedJavaField original, int modifiers, HostedStringDeduplication stringTable) { - VMError.guarantee(!original.isInternal(), "Internal fields are not supported for JIT compilation"); - - this.modifiers = modifiers; - this.name = stringTable.deduplicate(original.getName(), true); - this.hashCode = original.hashCode(); - } - @Platforms(Platform.HOSTED_ONLY.class) - public boolean setAnnotationsEncoding(Object annotationsEncoding) { - boolean result = this.annotationsEncoding != annotationsEncoding; - this.annotationsEncoding = annotationsEncoding; - return result; - } + public SubstrateField(AnalysisField aField, HostedStringDeduplication stringTable) { + VMError.guarantee(!aField.isInternal(), "Internal fields are not supported for JIT compilation"); - @Platforms(Platform.HOSTED_ONLY.class) - public Object getAnnotationsEncoding() { - return annotationsEncoding; + this.modifiers = aField.getModifiers() | + (ReadableJavaField.injectFinalForRuntimeCompilation(aField.wrapped) ? Modifier.FINAL : 0); + + this.name = stringTable.deduplicate(aField.getName(), true); + this.hashCode = aField.hashCode(); } public void setLinks(SubstrateType type, SubstrateType declaringClass) { @@ -155,17 +146,17 @@ public SubstrateType getDeclaringClass() { @Override public Annotation[] getAnnotations() { - return AnnotationsEncoding.decodeAnnotations(annotationsEncoding).getAnnotations(); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @Override public Annotation[] getDeclaredAnnotations() { - return getAnnotations(); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @Override public T getAnnotation(Class annotationClass) { - return AnnotationsEncoding.decodeAnnotations(annotationsEncoding).getAnnotation(annotationClass); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @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 60618ca793af..0cec9a23db19 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 @@ -32,19 +32,25 @@ import java.lang.reflect.Type; import java.util.Arrays; -import com.oracle.svm.core.Uninterruptible; +import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.core.common.util.TypeConversion; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.c.function.CEntryPoint; -import com.oracle.svm.core.heap.UnknownObjectField; -import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.deopt.Deoptimizer; +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.graal.meta.SharedRuntimeMethod; -import com.oracle.svm.core.hub.AnnotationsEncoding; +import com.oracle.svm.core.graal.phases.SubstrateSafepointInsertionPhase; +import com.oracle.svm.core.heap.UnknownObjectField; +import com.oracle.svm.core.heap.UnknownPrimitiveField; +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.HostedStringDeduplication; +import com.oracle.svm.core.util.VMError; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.ConstantPool; @@ -53,7 +59,6 @@ import jdk.vm.ci.meta.LineNumberTable; import jdk.vm.ci.meta.LocalVariableTable; import jdk.vm.ci.meta.ProfilingInfo; -import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; import jdk.vm.ci.meta.SpeculationLog; @@ -61,15 +66,25 @@ public class SubstrateMethod implements SharedRuntimeMethod { + private static final int FLAG_BIT_BRIDGE = 0; + private static final int FLAG_BIT_NEVER_INLINE = 1; + private static final int FLAG_BIT_UNINTERRUPTIBLE = 2; + private static final int FLAG_BIT_NEEDS_SAFEPOINT_CHECK = 3; + private static final int FLAG_BIT_ENTRY_POINT = 4; + private static final int FLAG_BIT_SNIPPET = 5; + private static final int FLAG_BIT_FOREIGN_CALL_TARGET = 6; + private static final int FLAG_BIT_CALLING_CONVENTION_KIND = 7; + private static final int NUM_BITS_CALLING_CONVENTION_KIND = 2; + private static final int FLAG_BIT_CALLEE_SAVED_REGISTERS = 9; + + private final int flags; private final byte[] encodedLineNumberTable; private final int modifiers; private final String name; private final int hashCode; - private final boolean hasStubCallingConvention; private SubstrateType declaringClass; private int encodedGraphStartOffset; @UnknownPrimitiveField private int vTableIndex; - private Object annotationsEncoding; /** * A pointer to the compiled code of the corresponding method in the native image. Used as @@ -87,20 +102,16 @@ public class SubstrateMethod implements SharedRuntimeMethod { @UnknownObjectField(types = {SubstrateMethod[].class, SubstrateMethod.class}, canBeNull = true)// protected Object implementations; - private final boolean neverInline; - private final boolean bridge; - private SubstrateSignature signature; @Platforms(Platform.HOSTED_ONLY.class) - public SubstrateMethod(ResolvedJavaMethod original, HostedStringDeduplication stringTable) { + public SubstrateMethod(AnalysisMethod original, HostedStringDeduplication stringTable) { encodedLineNumberTable = EncodedLineNumberTable.encode(original.getLineNumberTable()); assert original.getAnnotation(CEntryPoint.class) == null : "Can't compile entry point method"; modifiers = original.getModifiers(); name = stringTable.deduplicate(original.getName(), true); - neverInline = original.hasNeverInlineDirective(); /* * AnalysisMethods of snippets are stored in a hash map of SubstrateReplacements. The @@ -112,20 +123,34 @@ public SubstrateMethod(ResolvedJavaMethod original, HostedStringDeduplication st hashCode = original.hashCode(); implementations = new SubstrateMethod[0]; encodedGraphStartOffset = -1; - bridge = original.isBridge(); - hasStubCallingConvention = StubCallingConvention.Utils.hasStubCallingConvention(original); + + SubstrateCallingConventionKind callingConventionKind = ExplicitCallingConvention.Util.getCallingConventionKind(original, original.isEntryPoint()); + flags = makeFlag(original.isBridge(), FLAG_BIT_BRIDGE) | + makeFlag(original.hasNeverInlineDirective(), FLAG_BIT_NEVER_INLINE) | + makeFlag(Uninterruptible.Utils.isUninterruptible(original), FLAG_BIT_UNINTERRUPTIBLE) | + makeFlag(SubstrateSafepointInsertionPhase.needSafepointCheck(original), FLAG_BIT_NEEDS_SAFEPOINT_CHECK) | + makeFlag(original.isEntryPoint(), FLAG_BIT_ENTRY_POINT) | + makeFlag(original.isAnnotationPresent(Snippet.class), FLAG_BIT_SNIPPET) | + makeFlag(original.isAnnotationPresent(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); } - @Platforms(Platform.HOSTED_ONLY.class) - public boolean setAnnotationsEncoding(Object annotationsEncoding) { - boolean result = this.annotationsEncoding != annotationsEncoding; - this.annotationsEncoding = annotationsEncoding; - return result; + private static int makeFlag(boolean value, int flagBit) { + return value ? 1 << flagBit : 0; } - @Platforms(Platform.HOSTED_ONLY.class) - public Object getAnnotationsEncoding() { - return annotationsEncoding; + private static int makeFlag(int value, int flagBit, int numBits) { + VMError.guarantee(value >= 0 && value < (1 << numBits), "flag value out of range"); + return value << flagBit; + } + + private boolean getFlag(int flagBit) { + return (flags & (1 << flagBit)) != 0; + } + + private int getFlag(int flagBit, int numBits) { + return (flags >> flagBit) & ((1 << numBits) - 1); } public byte[] getEncodedLineNumberTable() { @@ -200,13 +225,13 @@ public void setEncodedGraphStartOffset(long encodedGraphStartOffset) { } @Override - public boolean isEntryPoint() { - return false; + public SubstrateCallingConventionKind getCallingConventionKind() { + return SubstrateCallingConventionKind.values()[getFlag(FLAG_BIT_CALLING_CONVENTION_KIND, NUM_BITS_CALLING_CONVENTION_KIND)]; } @Override public boolean hasCalleeSavedRegisters() { - return hasStubCallingConvention; + return getFlag(FLAG_BIT_CALLEE_SAVED_REGISTERS); } @Override @@ -230,6 +255,31 @@ public boolean canDeoptimize() { return true; } + @Override + public boolean isUninterruptible() { + return getFlag(FLAG_BIT_UNINTERRUPTIBLE); + } + + @Override + public boolean needSafepointCheck() { + return getFlag(FLAG_BIT_NEEDS_SAFEPOINT_CHECK); + } + + @Override + public boolean isEntryPoint() { + return getFlag(FLAG_BIT_ENTRY_POINT); + } + + @Override + public boolean isSnippet() { + return getFlag(FLAG_BIT_SNIPPET); + } + + @Override + public boolean isForeignCallTarget() { + return getFlag(FLAG_BIT_FOREIGN_CALL_TARGET); + } + @Override public int getVTableIndex() { if (vTableIndex < 0) { @@ -334,17 +384,17 @@ public ConstantPool getConstantPool() { @Override public Annotation[] getAnnotations() { - return AnnotationsEncoding.decodeAnnotations(annotationsEncoding).getAnnotations(); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @Override public Annotation[] getDeclaredAnnotations() { - return getAnnotations(); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @Override public T getAnnotation(Class annotationClass) { - return AnnotationsEncoding.decodeAnnotations(annotationsEncoding).getAnnotation(annotationClass); + throw VMError.unimplemented("Annotations are not available for JIT compilation at image run time"); } @Override @@ -366,7 +416,7 @@ public boolean canBeInlined() { public boolean hasNeverInlineDirective() { // If there is no graph in the image, then the method must never be considered // for inlining (because any attempt to inline it would fail). - return neverInline || encodedGraphStartOffset < 0; + return getFlag(FLAG_BIT_NEVER_INLINE) || encodedGraphStartOffset < 0; } @Override @@ -406,7 +456,7 @@ public boolean isVarArgs() { @Override public boolean isBridge() { - return bridge; + return getFlag(FLAG_BIT_BRIDGE); } @Override diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateUniverseFactory.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateUniverseFactory.java new file mode 100644 index 000000000000..421eb1cdce30 --- /dev/null +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/meta/SubstrateUniverseFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023, 2023, 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.graal.meta; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.util.HostedStringDeduplication; + +/** + * Factory for creating method and field objects that are used for JIT compilation at image run + * time. This allows Truffle to use subclasses with more data fields. + * + * All methods and fields are created at image build time. The factory does not cover types, because + * {@link SubstrateType} instances can also be created at image run time. + */ +@Platforms(Platform.HOSTED_ONLY.class) +public class SubstrateUniverseFactory { + + public SubstrateMethod createMethod(AnalysisMethod aMethod, HostedStringDeduplication stringTable) { + return new SubstrateMethod(aMethod, stringTable); + } + + public SubstrateField createField(AnalysisField aField, HostedStringDeduplication stringTable) { + return new SubstrateField(aField, stringTable); + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java deleted file mode 100644 index 5d6265b5a49a..000000000000 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/analysis/AnnotationsProcessor.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2021, 2021, 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.analysis; - -import java.lang.annotation.Annotation; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisType; -import com.oracle.graal.pointsto.util.AnalysisError; -import com.oracle.svm.core.hub.AnnotationsEncoding; -import com.oracle.svm.hosted.substitute.SubstitutionReflectivityFilter; - -public class AnnotationsProcessor { - - public static Object encodeAnnotations(AnalysisMetaAccess metaAccess, Annotation[] allAnnotations, Annotation[] declaredAnnotations, Object oldEncoding) { - Object newEncoding; - if (allAnnotations.length == 0 && declaredAnnotations.length == 0) { - newEncoding = null; - } else { - Set all = new HashSet<>(); - Collections.addAll(all, allAnnotations); - Collections.addAll(all, declaredAnnotations); - final Set usedAnnotations = all.stream() - .filter(a -> !SubstitutionReflectivityFilter.shouldExclude(a.annotationType(), metaAccess, metaAccess.getUniverse())) - .filter(a -> { - try { - AnalysisType annotationClass = metaAccess.lookupJavaType(a.getClass()); - return isAnnotationUsed(annotationClass); - } catch (AnalysisError.TypeNotFoundError e) { - /* - * Silently ignore the annotation if its type was not discovered - * by the static analysis. - */ - return false; - } - }).collect(Collectors.toSet()); - Set usedDeclared = filterUsedAnnotation(usedAnnotations, declaredAnnotations); - newEncoding = usedAnnotations.size() == 0 - ? null - : AnnotationsEncoding.encodeAnnotations(usedAnnotations, usedDeclared); - } - - /* - * Return newEncoding only if the value is different from oldEncoding. Without this guard, - * for tests that do runtime compilation, the field appears as being continuously updated - * during BigBang.checkObjectGraph. - */ - if (oldEncoding != null && oldEncoding.equals(newEncoding)) { - return oldEncoding; - } else { - return newEncoding; - } - } - - /** - * We only want annotations in the native image heap that are "used" at run time. In our case, - * "used" means that the annotation interface is used at least in a type check. This leaves one - * case where Substrate VM behaves differently than a normal Java VM: When you just query the - * number of annotations on a class, then we might return a lower number. - */ - private static boolean isAnnotationUsed(AnalysisType annotationType) { - if (annotationType.isReachable()) { - return true; - } - assert annotationType.getInterfaces().length == 1 : annotationType; - - AnalysisType annotationInterfaceType = annotationType.getInterfaces()[0]; - return annotationInterfaceType.isReachable(); - } - - private static Set filterUsedAnnotation(Set used, Annotation[] rest) { - if (rest == null) { - return null; - } - - Set restUsed = new HashSet<>(); - for (Annotation a : rest) { - if (used.contains(a)) { - restUsed.add(a); - } - } - return restUsed; - } - -} 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 c7992477c38a..9c06542232bf 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 @@ -39,6 +39,7 @@ import java.util.function.Function; import org.graalvm.collections.Pair; +import org.graalvm.compiler.api.replacements.Snippet; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.JavaMethodContext; import org.graalvm.compiler.nodes.StructuredGraph; @@ -56,13 +57,18 @@ import com.oracle.svm.common.meta.MultiMethod; import com.oracle.svm.core.AlwaysInline; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.Uninterruptible; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; +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.graal.phases.SubstrateSafepointInsertionPhase; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; +import com.oracle.svm.core.snippets.SubstrateForeignCallTarget; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.code.CompilationInfo; import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; @@ -291,6 +297,26 @@ public boolean canDeoptimize() { return compilationInfo.canDeoptForTesting() || multiMethodKey == SubstrateCompilationDirectives.RUNTIME_COMPILED_METHOD; } + @Override + public boolean isUninterruptible() { + return Uninterruptible.Utils.isUninterruptible(wrapped); + } + + @Override + public boolean needSafepointCheck() { + return SubstrateSafepointInsertionPhase.needSafepointCheck(wrapped); + } + + @Override + public boolean isForeignCallTarget() { + return isAnnotationPresent(SubstrateForeignCallTarget.class); + } + + @Override + public boolean isSnippet() { + return isAnnotationPresent(Snippet.class); + } + public boolean hasVTableIndex() { return vtableIndex != -1; } @@ -319,6 +345,11 @@ public boolean isEntryPoint() { return wrapped.isEntryPoint(); } + @Override + public SubstrateCallingConventionKind getCallingConventionKind() { + return ExplicitCallingConvention.Util.getCallingConventionKind(wrapped, isEntryPoint()); + } + @Override public boolean hasCalleeSavedRegisters() { return StubCallingConvention.Utils.hasStubCallingConvention(this); 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 25e3d117688b..1e09fb56af4f 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 @@ -109,6 +109,7 @@ import com.oracle.svm.graal.hosted.GraalGraphObjectReplacer; import com.oracle.svm.graal.hosted.SubstrateGraalCompilerSetup; import com.oracle.svm.graal.hosted.SubstrateProviders; +import com.oracle.svm.graal.meta.SubstrateUniverseFactory; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; @@ -423,9 +424,6 @@ public void duringSetup(DuringSetupAccess access) { DuringSetupAccessImpl config = (DuringSetupAccessImpl) access; metaAccess = config.getMetaAccess(); - SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class) - .getSubstrateProviders(metaAccess); - graalGraphObjectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), metaAccess, substrateProviders); layoutInfoMapField = config.findField("com.oracle.truffle.object.DefaultLayout$LayoutInfo", "LAYOUT_INFO_MAP"); layoutMapField = config.findField("com.oracle.truffle.object.DefaultLayout", "LAYOUT_MAP"); @@ -435,9 +433,20 @@ public void duringSetup(DuringSetupAccess access) { } } + void setGraalGraphObjectReplacer(GraalGraphObjectReplacer graalGraphObjectReplacer) { + assert this.graalGraphObjectReplacer == null; + this.graalGraphObjectReplacer = graalGraphObjectReplacer; + } + @SuppressWarnings("deprecation") @Override public void beforeAnalysis(BeforeAnalysisAccess access) { + if (graalGraphObjectReplacer == null) { + BeforeAnalysisAccessImpl config = (BeforeAnalysisAccessImpl) access; + SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(metaAccess); + graalGraphObjectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), substrateProviders, new SubstrateUniverseFactory()); + } + StaticObjectSupport.beforeAnalysis(access); markAsUnsafeAccessed = access::registerAsUnsafeAccessed; 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 0cae79e8d896..1d04b7237b61 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 @@ -161,6 +161,7 @@ import com.oracle.svm.truffle.api.SubstrateThreadLocalHandshakeSnippets; import com.oracle.svm.truffle.api.SubstrateTruffleCompiler; import com.oracle.svm.truffle.api.SubstrateTruffleRuntime; +import com.oracle.svm.truffle.api.SubstrateTruffleUniverseFactory; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -273,9 +274,10 @@ public static boolean isInConfiguration() { @Override public void afterRegistration(AfterRegistrationAccess access) { - UserError.guarantee(Truffle.getRuntime() instanceof SubstrateTruffleRuntime, - "TruffleFeature requires SubstrateTruffleRuntime"); - ((SubstrateTruffleRuntime) Truffle.getRuntime()).resetHosted(); + UserError.guarantee(Truffle.getRuntime() instanceof SubstrateTruffleRuntime, "TruffleFeature requires SubstrateTruffleRuntime"); + SubstrateTruffleRuntime truffleRuntime = (SubstrateTruffleRuntime) Truffle.getRuntime(); + truffleRuntime.resetHosted(); + RuntimeCompilationFeature.singleton().setUniverseFactory(new SubstrateTruffleUniverseFactory(truffleRuntime)); } @Override @@ -293,6 +295,8 @@ public void duringSetup(DuringSetupAccess a) { if (!ImageSingletons.contains(TruffleSupport.class)) { ImageSingletons.add(TruffleSupport.class, new TruffleSupport()); } + + ImageSingletons.lookup(TruffleBaseFeature.class).setGraalGraphObjectReplacer(RuntimeCompilationFeature.singleton().getObjectReplacer()); } private void registerNeverPartOfCompilation(InvocationPlugins plugins) { diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleField.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleField.java new file mode 100644 index 000000000000..e7ffeb822979 --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleField.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime.ConstantFieldInfo; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.svm.core.util.HostedStringDeduplication; +import com.oracle.svm.graal.meta.SubstrateField; + +public class SubstrateTruffleField extends SubstrateField implements TruffleField { + + private final ConstantFieldInfo constantFieldInfo; + + @Platforms(Platform.HOSTED_ONLY.class) + public SubstrateTruffleField(AnalysisField aField, HostedStringDeduplication stringTable, ConstantFieldInfo constantFieldInfo) { + super(aField, stringTable); + this.constantFieldInfo = constantFieldInfo; + } + + @Override + public ConstantFieldInfo getConstantFieldInfo() { + return constantFieldInfo; + } +} diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleMethod.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleMethod.java new file mode 100644 index 000000000000..74d9e52c867e --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleMethod.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.util.HostedStringDeduplication; +import com.oracle.svm.graal.meta.SubstrateMethod; + +public class SubstrateTruffleMethod extends SubstrateMethod implements TruffleMethod { + + /** + * In practice, there are very few distinct flag combinations, i.e., only a few + * {@link TruffleMethodInfo} instances in the image heap, so a single object reference is more + * compact than storing individual flags directly in each method object. + */ + private final TruffleMethodInfo truffleMethodInfo; + + @Platforms(Platform.HOSTED_ONLY.class) + public SubstrateTruffleMethod(AnalysisMethod aMethod, HostedStringDeduplication stringTable, TruffleMethodInfo truffleMethodInfo) { + super(aMethod, stringTable); + this.truffleMethodInfo = truffleMethodInfo; + } + + @Override + public TruffleMethodInfo getTruffleMethodInfo() { + return truffleMethodInfo; + } +} diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java index 92d56178107f..9fd81173eea0 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleRuntime.java @@ -81,6 +81,7 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.MetaAccessProvider; +import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.SpeculationLog; @@ -378,18 +379,6 @@ public void log(String loggerId, CompilableTruffleAST compilable, String message } } - @Override - public boolean isInlineable(ResolvedJavaMethod method) { - if (Uninterruptible.Utils.isUninterruptible(method)) { - Uninterruptible uninterruptibleAnnotation = Uninterruptible.Utils.getAnnotation(method); - if (uninterruptibleAnnotation == null || !uninterruptibleAnnotation.mayBeInlined()) { - /* The semantics of Uninterruptible would get lost during partial evaluation. */ - return false; - } - } - return super.isInlineable(method); - } - @Override public boolean isSuppressedFailure(CompilableTruffleAST compilable, Supplier serializedException) { TriState res = TruffleSupport.singleton().tryIsSuppressedFailure(compilable, serializedException); @@ -496,4 +485,127 @@ public boolean hasNextTier() { } } + + /* + * Annotations for methods and fields are not available at image run time. So all information is + * pre-computed at image build time. Therefore, all the methods below delegate to the + * super-class at image build time when invoked for pre-computation, and access the pre-computed + * information at image run time. + */ + + @Override + public LoopExplosionKind getLoopExplosionKind(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.getLoopExplosionKind(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().explosionKind(); + } + } + + @Override + public InlineKind getInlineKind(ResolvedJavaMethod method, boolean duringPartialEvaluation) { + if (SubstrateUtil.HOSTED) { + return super.getInlineKind(method, duringPartialEvaluation); + } else { + TruffleMethodInfo truffleMethodInfo = ((TruffleMethod) method).getTruffleMethodInfo(); + return duringPartialEvaluation ? truffleMethodInfo.inlineKindPE() : truffleMethodInfo.inlineKindNonPE(); + } + } + + @Override + public boolean isInlineable(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + if (Uninterruptible.Utils.isUninterruptible(method)) { + Uninterruptible uninterruptibleAnnotation = Uninterruptible.Utils.getAnnotation(method); + if (uninterruptibleAnnotation == null || !uninterruptibleAnnotation.mayBeInlined()) { + /* The semantics of Uninterruptible would get lost during partial evaluation. */ + return false; + } + } + return super.isInlineable(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isInlineable(); + } + } + + @Override + public boolean isTruffleBoundary(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isTruffleBoundary(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isTruffleBoundary(); + } + } + + @Override + public boolean isSpecializationMethod(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isSpecializationMethod(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isSpecializationMethod(); + } + } + + @Override + public boolean isBytecodeInterpreterSwitch(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isBytecodeInterpreterSwitch(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isBytecodeInterpreterSwitch(); + } + } + + @Override + public boolean isInliningCutoff(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isInliningCutoff(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isInliningCutoff(); + } + } + + @Override + public boolean isBytecodeInterpreterSwitchBoundary(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isBytecodeInterpreterSwitchBoundary(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isBytecodeInterpreterSwitchBoundary(); + } + } + + @Override + public boolean isInInterpreter(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isInInterpreter(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isInInterpreter(); + } + } + + @Override + public boolean isInInterpreterFastPath(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isInInterpreterFastPath(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isInInterpreterFastPath(); + } + } + + @Override + public boolean isTransferToInterpreterMethod(ResolvedJavaMethod method) { + if (SubstrateUtil.HOSTED) { + return super.isTransferToInterpreterMethod(method); + } else { + return ((TruffleMethod) method).getTruffleMethodInfo().isTransferToInterpreterMethod(); + } + } + + @Override + public ConstantFieldInfo getConstantFieldInfo(ResolvedJavaField field) { + if (SubstrateUtil.HOSTED) { + return super.getConstantFieldInfo(field); + } else { + return ((TruffleField) field).getConstantFieldInfo(); + } + } } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleUniverseFactory.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleUniverseFactory.java new file mode 100644 index 000000000000..7fb8f1a65a7c --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateTruffleUniverseFactory.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime.ConstantFieldInfo; + +import com.oracle.graal.pointsto.meta.AnalysisField; +import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.svm.core.util.HostedStringDeduplication; +import com.oracle.svm.graal.meta.SubstrateField; +import com.oracle.svm.graal.meta.SubstrateMethod; +import com.oracle.svm.graal.meta.SubstrateUniverseFactory; + +public class SubstrateTruffleUniverseFactory extends SubstrateUniverseFactory { + + private final SubstrateTruffleRuntime truffleRuntime; + private final ConcurrentMap canonicalMethodInfos = new ConcurrentHashMap<>(); + private final ConcurrentMap canonicalFieldInfos = new ConcurrentHashMap<>(); + + public SubstrateTruffleUniverseFactory(SubstrateTruffleRuntime truffleRuntime) { + this.truffleRuntime = truffleRuntime; + } + + @Override + public SubstrateMethod createMethod(AnalysisMethod aMethod, HostedStringDeduplication stringTable) { + TruffleMethodInfo truffleMethodInfo = canonicalMethodInfos.computeIfAbsent(TruffleMethodInfo.create(truffleRuntime, aMethod), k -> k); + return new SubstrateTruffleMethod(aMethod, stringTable, truffleMethodInfo); + } + + @Override + public SubstrateField createField(AnalysisField aField, HostedStringDeduplication stringTable) { + ConstantFieldInfo key = truffleRuntime.getConstantFieldInfo(aField); + ConstantFieldInfo constantFieldInfo = key == null ? null : canonicalFieldInfos.computeIfAbsent(key, k -> k); + return new SubstrateTruffleField(aField, stringTable, constantFieldInfo); + } +} diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleBoundaryPhase.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleBoundaryPhase.java index 4564f2d88633..6f33344f3af8 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleBoundaryPhase.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleBoundaryPhase.java @@ -64,11 +64,8 @@ protected void run(StructuredGraph graph) { FixedNode originalNext = exceptionObject.next(); if (!(originalNext instanceof DeoptimizeNode) && invoke.callTarget().targetMethod() != null) { ResolvedJavaMethod targetMethod = invoke.callTarget().targetMethod(); - TruffleBoundary truffleBoundary = targetMethod.getAnnotation(TruffleBoundary.class); - if (truffleBoundary != null) { - if (truffleBoundary.transferToInterpreterOnException()) { - addDeoptimizeNode(graph, originalNext, targetMethod); - } + if (((TruffleMethod) targetMethod).getTruffleMethodInfo().isTruffleBoundaryTransferToInterpreterOnException()) { + addDeoptimizeNode(graph, originalNext, targetMethod); } } } diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleField.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleField.java new file mode 100644 index 000000000000..2c9ba3fe7391 --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleField.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime.ConstantFieldInfo; + +public interface TruffleField { + + ConstantFieldInfo getConstantFieldInfo(); +} diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethod.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethod.java new file mode 100644 index 000000000000..800e5ce52b8b --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethod.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +public interface TruffleMethod { + + TruffleMethodInfo getTruffleMethodInfo(); +} diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethodInfo.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethodInfo.java new file mode 100644 index 000000000000..bbad9774c3c6 --- /dev/null +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/TruffleMethodInfo.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2023, 2023, 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.truffle.api; + +import org.graalvm.compiler.truffle.common.TruffleCompilerRuntime; +import org.graalvm.nativeimage.AnnotationAccess; +import org.graalvm.nativeimage.Platform; +import org.graalvm.nativeimage.Platforms; + +import com.oracle.truffle.api.CompilerDirectives; + +import jdk.vm.ci.meta.ResolvedJavaMethod; + +/** + * A collection of all the flags that Truffle needs for partial evaluation. Most of this information + * comes from annotations on methods. But since we do not want to store annotations in the image + * heap, we pre-compute all information at image build time. This is also faster than accessing + * annotations at image run time. + */ +public record TruffleMethodInfo( + TruffleCompilerRuntime.LoopExplosionKind explosionKind, + TruffleCompilerRuntime.InlineKind inlineKindPE, + TruffleCompilerRuntime.InlineKind inlineKindNonPE, + boolean isInlineable, + boolean isTruffleBoundary, + boolean isTruffleBoundaryTransferToInterpreterOnException, + boolean isSpecializationMethod, + boolean isBytecodeInterpreterSwitch, + boolean isBytecodeInterpreterSwitchBoundary, + boolean isInInterpreter, + boolean isInInterpreterFastPath, + boolean isTransferToInterpreterMethod, + boolean isInliningCutoff) { + + @Platforms(Platform.HOSTED_ONLY.class) + static TruffleMethodInfo create(TruffleCompilerRuntime runtime, ResolvedJavaMethod method) { + return new TruffleMethodInfo( + runtime.getLoopExplosionKind(method), + runtime.getInlineKind(method, true), + runtime.getInlineKind(method, false), + runtime.isInlineable(method), + runtime.isTruffleBoundary(method), + computeTruffleBoundaryTransferToInterpreterOnException(method), + runtime.isSpecializationMethod(method), + runtime.isBytecodeInterpreterSwitch(method), + runtime.isBytecodeInterpreterSwitchBoundary(method), + runtime.isInInterpreter(method), + runtime.isInInterpreterFastPath(method), + runtime.isTransferToInterpreterMethod(method), + runtime.isInliningCutoff(method)); + } + + private static boolean computeTruffleBoundaryTransferToInterpreterOnException(ResolvedJavaMethod method) { + CompilerDirectives.TruffleBoundary truffleBoundary = AnnotationAccess.getAnnotation(method, CompilerDirectives.TruffleBoundary.class); + if (truffleBoundary != null) { + return truffleBoundary.transferToInterpreterOnException(); + } else { + return false; + } + } +}