From 43f9abad82395f437a8c27a1bf13bde5070e8331 Mon Sep 17 00:00:00 2001 From: Tom Shull Date: Tue, 23 Aug 2022 12:06:05 +0200 Subject: [PATCH] Rename support for SVM runtime compilation. --- .../hotspot/libgraal/LibGraalFeature.java | 4 +- .../oracle/svm/graal/GraalSubstitutions.java | 42 +- ...cer.java => GraalGraphObjectReplacer.java} | 18 +- ...re.java => RuntimeCompilationFeature.java} | 49 +- .../svm/graal/hosted/RuntimeGraalSetup.java | 54 -- ....java => SubstrateGraalCompilerSetup.java} | 18 +- ...lacements.java => SubstrateProviders.java} | 8 +- ...ements.java => IsolateAwareProviders.java} | 6 +- .../AnalysisToHostedGraphTransplanter.java | 326 +++++++++++ .../svm/hosted/code/CompilationInfo.java | 7 +- .../oracle/svm/hosted/code/CompileQueue.java | 548 +----------------- .../svm/hosted/code/DeoptimizationUtils.java | 328 +++++++++++ .../svm/hosted/code/HostedReplacements.java | 4 +- ...va => SubstrateCompilationDirectives.java} | 6 +- .../hosted/image/NativeImageCodeCache.java | 8 +- .../oracle/svm/hosted/meta/HostedMethod.java | 2 +- .../svm/hosted/meta/HostedUniverse.java | 14 +- .../svm/truffle/TruffleBaseFeature.java | 29 +- .../oracle/svm/truffle/TruffleFeature.java | 70 +-- .../oracle/svm/truffle/TruffleSupport.java | 8 +- 20 files changed, 818 insertions(+), 731 deletions(-) rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{GraalObjectReplacer.java => GraalGraphObjectReplacer.java} (97%) rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{GraalFeature.java => RuntimeCompilationFeature.java} (95%) delete mode 100644 substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeGraalSetup.java rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{SubstrateRuntimeGraalSetup.java => SubstrateGraalCompilerSetup.java} (86%) rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/{GraalProviderObjectReplacements.java => SubstrateProviders.java} (90%) rename substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/{IsolateAwareProviderObjectReplacements.java => IsolateAwareProviders.java} (86%) create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java create mode 100644 substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java rename substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/{CompilationInfoSupport.java => SubstrateCompilationDirectives.java} (97%) diff --git a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java index c24cf1b3dfe0..ea5face30bbc 100644 --- a/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal.hotspot.libgraal/src/com/oracle/svm/graal/hotspot/libgraal/LibGraalFeature.java @@ -133,7 +133,7 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.UserError.UserException; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.hosted.GraalFeature; +import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.DuringSetupAccessImpl; import com.oracle.svm.hosted.ImageClassLoader; @@ -195,7 +195,7 @@ public boolean isInConfiguration(IsInConfigurationAccess access) { @Override public List> getRequiredFeatures() { - return Arrays.asList(JNIFeature.class, GraalFeature.class, ReflectionFeature.class); + return Arrays.asList(JNIFeature.class, RuntimeCompilationFeature.class, ReflectionFeature.class); } public static final class IsEnabled implements BooleanSupplier { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java index 7bda19ba2d06..bf1f88a68588 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/GraalSubstitutions.java @@ -77,14 +77,14 @@ import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.VMError; import com.oracle.svm.graal.hosted.FieldsOffsetsFeature; -import com.oracle.svm.graal.hosted.GraalFeature; +import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; import com.oracle.svm.graal.meta.SubstrateMethod; import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.code.TargetDescription; import jdk.vm.ci.meta.ResolvedJavaMethod; -@TargetClass(value = org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) final class Target_org_graalvm_compiler_nodes_graphbuilderconf_InvocationPlugins { @Alias// @@ -98,7 +98,7 @@ private void flushDeferrables() { } } -@TargetClass(value = org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) @SuppressWarnings({"unused"}) final class Target_org_graalvm_compiler_phases_common_inlining_info_elem_InlineableGraph { @@ -112,7 +112,7 @@ private static StructuredGraph parseBytecodes(ResolvedJavaMethod method, HighTie } } -@TargetClass(value = org.graalvm.compiler.phases.common.inlining.walker.ComputeInliningRelevance.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.phases.common.inlining.walker.ComputeInliningRelevance.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) @SuppressWarnings({"static-method", "unused"}) final class Target_org_graalvm_compiler_phases_common_inlining_walker_ComputeInliningRelevance { @@ -130,11 +130,11 @@ public double getRelevance(Invoke invoke) { } } -@TargetClass(value = DebugContext.class, innerClass = "Invariants", onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = DebugContext.class, innerClass = "Invariants", onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_DebugContext_Invariants { } -@TargetClass(value = DebugContext.class, innerClass = "Immutable", onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = DebugContext.class, innerClass = "Immutable", onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_DebugContext_Immutable { static class ClearImmutableCache implements FieldValueTransformer { @Override @@ -163,7 +163,7 @@ public Object transform(Object receiver, Object originalValue) { private static Target_org_graalvm_compiler_debug_DebugContext_Immutable[] CACHE; } -@TargetClass(value = DebugHandlersFactory.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = DebugHandlersFactory.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_DebugHandlersFactory { static class CachedFactories implements FieldValueTransformer { @Override @@ -180,7 +180,7 @@ public Object transform(Object receiver, Object originalValue) { private static Iterable LOADER; } -@TargetClass(value = TimeSource.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = TimeSource.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_TimeSource { // Checkstyle: stop @Alias @RecomputeFieldValue(kind = FromAlias)// @@ -188,14 +188,14 @@ final class Target_org_graalvm_compiler_debug_TimeSource { // Checkstyle: resume } -@TargetClass(value = org.graalvm.compiler.debug.TTY.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.debug.TTY.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) final class Target_org_graalvm_compiler_debug_TTY { @Alias @RecomputeFieldValue(kind = FromAlias)// private static PrintStream out = Log.logStream(); } -@TargetClass(className = "org.graalvm.compiler.serviceprovider.IsolateUtil", onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(className = "org.graalvm.compiler.serviceprovider.IsolateUtil", onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_serviceprovider_IsolateUtil { @Substitute @@ -213,7 +213,7 @@ public static long getIsolateID() { * The following substitutions replace methods where reflection is used in the Graal code. */ -@TargetClass(value = org.graalvm.compiler.debug.KeyRegistry.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.debug.KeyRegistry.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_debug_KeyRegistry { @Alias @RecomputeFieldValue(kind = FromAlias)// @@ -223,7 +223,7 @@ final class Target_org_graalvm_compiler_debug_KeyRegistry { private static List keys = new ArrayList<>(); } -@TargetClass(value = org.graalvm.compiler.core.match.MatchRuleRegistry.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.core.match.MatchRuleRegistry.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_core_match_MatchRuleRegistry { @Substitute @@ -237,7 +237,7 @@ public static EconomicMap, List> lookup(Cl } } -@TargetClass(value = org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.replacements.nodes.BinaryMathIntrinsicNode.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) @SuppressWarnings({"unused", "static-method"}) final class Target_org_graalvm_compiler_replacements_nodes_BinaryMathIntrinsicNode { @@ -253,7 +253,7 @@ void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) { } } -@TargetClass(value = org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.class, onlyWith = GraalFeature.IsEnabledAndNotLibgraal.class) +@TargetClass(value = org.graalvm.compiler.replacements.nodes.UnaryMathIntrinsicNode.class, onlyWith = RuntimeCompilationFeature.IsEnabledAndNotLibgraal.class) @SuppressWarnings({"unused", "static-method"}) final class Target_org_graalvm_compiler_replacements_nodes_UnaryMathIntrinsicNode { @@ -263,7 +263,7 @@ void generate(NodeLIRBuilderTool nodeValueMap, ArithmeticLIRGeneratorTool gen) { } } -@TargetClass(value = org.graalvm.compiler.phases.BasePhase.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.phases.BasePhase.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_phases_BasePhase { @Substitute @@ -276,7 +276,7 @@ static BasePhase.BasePhaseStatistics getBasePhaseStatistics(Class clazz) { } } -@TargetClass(value = org.graalvm.compiler.lir.phases.LIRPhase.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.lir.phases.LIRPhase.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_lir_phases_LIRPhase { @Substitute @@ -289,7 +289,7 @@ static LIRPhase.LIRPhaseStatistics getLIRPhaseStatistics(Class clazz) { } } -@TargetClass(value = org.graalvm.compiler.graph.NodeClass.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.graph.NodeClass.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_graph_NodeClass { @Alias @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.Custom, declClass = FieldsOffsetsFeature.InputsIterationMaskRecomputation.class)// @@ -319,7 +319,7 @@ public String shortName() { } } -@TargetClass(value = org.graalvm.compiler.lir.LIRInstructionClass.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.lir.LIRInstructionClass.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_lir_LIRInstructionClass { @Substitute @@ -334,7 +334,7 @@ public static LIRInstructionClass get(Class clazz) } } -@TargetClass(value = org.graalvm.compiler.lir.CompositeValueClass.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.lir.CompositeValueClass.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_lir_CompositeValueClass { @Substitute @@ -356,7 +356,7 @@ final class Target_org_graalvm_compiler_printer_NoDeadCodeVerifyHandler { private static Map discovered; } -@TargetClass(value = org.graalvm.compiler.nodes.NamedLocationIdentity.class, innerClass = "DB", onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = org.graalvm.compiler.nodes.NamedLocationIdentity.class, innerClass = "DB", onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_org_graalvm_compiler_nodes_NamedLocationIdentity_DB { @Alias// @RecomputeFieldValue(kind = FromAlias, declClass = EconomicMap.class)// @@ -369,7 +369,7 @@ final class Target_org_graalvm_compiler_nodes_NamedLocationIdentity_DB { * created just once during the image build and accessed via {@link ConfigurationValues} and * {@link ImageSingletons} from many locations. */ -@TargetClass(value = TargetDescription.class, onlyWith = GraalFeature.IsEnabled.class) +@TargetClass(value = TargetDescription.class, onlyWith = RuntimeCompilationFeature.IsEnabled.class) final class Target_jdk_vm_ci_code_TargetDescription { @Alias @InjectAccessors(value = InlineObjectsAccessor.class) // boolean inlineObjects; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java similarity index 97% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java index 14f7f9fd02a4..f3454101a07a 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalObjectReplacer.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalGraphObjectReplacer.java @@ -94,7 +94,7 @@ * * It is mainly used to replace the Hosted* meta data with the Substrate* meta data. */ -public class GraalObjectReplacer implements Function { +public class GraalGraphObjectReplacer implements Function { private final AnalysisUniverse aUniverse; private final AnalysisMetaAccess aMetaAccess; @@ -103,7 +103,7 @@ public class GraalObjectReplacer implements Function { private final HashMap fieldLocationIdentities = new HashMap<>(); private final HashMap types = new HashMap<>(); private final HashMap signatures = new HashMap<>(); - private final GraalProviderObjectReplacements providerReplacements; + private final SubstrateProviders sProviders; private SubstrateGraalRuntime sGraalRuntime; private final HostedStringDeduplication stringTable; @@ -116,10 +116,10 @@ public class GraalObjectReplacer implements Function { private final Field substrateMethodImplementationsField; private final Field substrateMethodAnnotationsEncodingField; - public GraalObjectReplacer(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, GraalProviderObjectReplacements providerReplacements) { + public GraalGraphObjectReplacer(AnalysisUniverse aUniverse, AnalysisMetaAccess aMetaAccess, SubstrateProviders sProviders) { this.aUniverse = aUniverse; this.aMetaAccess = aMetaAccess; - this.providerReplacements = providerReplacements; + this.sProviders = sProviders; this.stringTable = HostedStringDeduplication.singleton(); substrateFieldAnnotationsEncodingField = ReflectionUtil.lookupField(SubstrateField.class, "annotationsEncoding"); substrateFieldTypeField = ReflectionUtil.lookupField(SubstrateField.class, "type"); @@ -152,7 +152,7 @@ public Object apply(Object source) { return source; } if (source instanceof MetaAccessProvider) { - dest = providerReplacements.getMetaAccessProvider(); + dest = sProviders.getMetaAccessProvider(); } else if (source instanceof HotSpotJVMCIRuntime) { throw new UnsupportedFeatureException("HotSpotJVMCIRuntime should not appear in the image: " + source); } else if (source instanceof GraalHotSpotVMConfig) { @@ -166,13 +166,13 @@ public Object apply(Object source) { } else if (source instanceof GraalRuntime) { dest = sGraalRuntime; } else if (source instanceof AnalysisConstantReflectionProvider) { - dest = providerReplacements.getConstantReflectionProvider(); + dest = sProviders.getConstantReflectionProvider(); } else if (source instanceof AnalysisConstantFieldProvider) { - dest = providerReplacements.getConstantFieldProvider(); + dest = sProviders.getConstantFieldProvider(); } else if (source instanceof ForeignCallsProvider) { - dest = providerReplacements.getForeignCallsProvider(); + dest = sProviders.getForeignCallsProvider(); } else if (source instanceof SnippetReflectionProvider) { - dest = providerReplacements.getSnippetReflectionProvider(); + dest = sProviders.getSnippetReflectionProvider(); } else if (source instanceof MetricKey) { /* Ensure lazily initialized name fields are computed. */ diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java similarity index 95% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java index 17cab5d9d6bc..0f48bfddbe6b 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeCompilationFeature.java @@ -124,8 +124,8 @@ import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.hosted.code.CompilationInfoSupport; import com.oracle.svm.hosted.code.SharedRuntimeConfigurationBuilder; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; @@ -145,13 +145,14 @@ import jdk.vm.ci.services.Services; /** - * The main handler for running Graal in the Substrate VM at run time. This feature (and features it - * depends on like {@link FieldsOffsetsFeature}) encodes Graal graphs for runtime compilation, - * ensures that all required {@link SubstrateType}, {@link SubstrateMethod}, {@link SubstrateField} - * objects are created by {@link GraalObjectReplacer} and added to the image. Data that is prepared - * during image generation and used at run time is stored in {@link GraalSupport}. + * The main handler for running the Graal compiler in the Substrate VM at run time. This feature + * (and features it depends on like {@link FieldsOffsetsFeature}) encodes Graal graphs for runtime + * compilation, ensures that all required {@link SubstrateType}, {@link SubstrateMethod}, + * {@link SubstrateField} objects are created by {@link GraalGraphObjectReplacer} and added to the + * image. Data that is prepared during image generation and used at run time is stored in + * {@link GraalSupport}. */ -public final class GraalFeature implements Feature { +public final class RuntimeCompilationFeature implements Feature { public static class Options { @Option(help = "Print call tree of methods available for runtime compilation")// @@ -167,7 +168,7 @@ public static class Options { public static final class IsEnabled implements BooleanSupplier { @Override public boolean getAsBoolean() { - return ImageSingletons.contains(GraalFeature.class); + return ImageSingletons.contains(RuntimeCompilationFeature.class); } } @@ -179,7 +180,7 @@ public boolean getAsBoolean() { public static final class IsEnabledAndNotLibgraal implements BooleanSupplier { @Override public boolean getAsBoolean() { - return ImageSingletons.contains(GraalFeature.class) && !SubstrateUtil.isBuildingLibgraal(); + return ImageSingletons.contains(RuntimeCompilationFeature.class) && !SubstrateUtil.isBuildingLibgraal(); } } @@ -270,7 +271,7 @@ public static class RuntimeBytecodeParser extends SubstrateGraphBuilderPhase.Sub protected boolean tryInvocationPlugin(InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { boolean result = super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType); if (result) { - CompilationInfoSupport.singleton().registerAsDeoptInlininingExclude(targetMethod); + SubstrateCompilationDirectives.singleton().registerAsDeoptInlininingExclude(targetMethod); } return result; } @@ -280,7 +281,7 @@ public CallTreeNode getCallTreeNode() { } } - private GraalObjectReplacer objectReplacer; + private GraalGraphObjectReplacer objectReplacer; private HostedProviders hostedProviders; private GraphEncoder graphEncoder; private SharedRuntimeConfigurationBuilder runtimeConfigBuilder; @@ -304,7 +305,7 @@ public HostedProviders getHostedProviders() { return hostedProviders; } - public GraalObjectReplacer getObjectReplacer() { + public GraalGraphObjectReplacer getObjectReplacer() { return objectReplacer; } @@ -319,14 +320,14 @@ public List> getRequiredFeatures() { @Override public void duringSetup(DuringSetupAccess c) { ImageSingletons.add(GraalSupport.class, new GraalSupport()); - if (!ImageSingletons.contains(RuntimeGraalSetup.class)) { - ImageSingletons.add(RuntimeGraalSetup.class, new SubstrateRuntimeGraalSetup()); + if (!ImageSingletons.contains(SubstrateGraalCompilerSetup.class)) { + ImageSingletons.add(SubstrateGraalCompilerSetup.class, new SubstrateGraalCompilerSetup()); } DuringSetupAccessImpl config = (DuringSetupAccessImpl) c; AnalysisMetaAccess aMetaAccess = config.getMetaAccess(); - GraalProviderObjectReplacements providerReplacements = ImageSingletons.lookup(RuntimeGraalSetup.class).getProviderObjectReplacements(aMetaAccess); - objectReplacer = new GraalObjectReplacer(config.getUniverse(), aMetaAccess, providerReplacements); + SubstrateProviders substrateProviders = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).getSubstrateProviders(aMetaAccess); + objectReplacer = new GraalGraphObjectReplacer(config.getUniverse(), aMetaAccess, substrateProviders); config.registerObjectReplacer(objectReplacer); config.registerClassReachabilityListener(GraalSupport::registerPhaseStatistics); @@ -364,7 +365,7 @@ public void beforeAnalysis(BeforeAnalysisAccess c) { Function backendProvider = GraalSupport.getRuntimeBackendProvider(); ClassInitializationSupport classInitializationSupport = config.getHostVM().getClassInitializationSupport(); Providers originalProviders = GraalAccess.getOriginalProviders(); - runtimeConfigBuilder = ImageSingletons.lookup(RuntimeGraalSetup.class).createRuntimeConfigurationBuilder(RuntimeOptionValues.singleton(), config.getHostVM(), config.getUniverse(), + runtimeConfigBuilder = ImageSingletons.lookup(SubstrateGraalCompilerSetup.class).createRuntimeConfigurationBuilder(RuntimeOptionValues.singleton(), config.getHostVM(), config.getUniverse(), config.getMetaAccess(), originalProviders.getConstantReflection(), backendProvider, config.getNativeLibraries(), classInitializationSupport, originalProviders.getLoopsDataProvider()).build(); RuntimeConfiguration runtimeConfig = runtimeConfigBuilder.getRuntimeConfig(); @@ -401,7 +402,7 @@ public void beforeAnalysis(BeforeAnalysisAccess c) { /* Initialize configuration with reasonable default values. */ graphBuilderConfig = GraphBuilderConfiguration.getDefault(hostedProviders.getGraphBuilderPlugins()).withBytecodeExceptionMode(BytecodeExceptionMode.ExplicitOnly); - includeCalleePredicate = GraalFeature::defaultIncludeCallee; + includeCalleePredicate = RuntimeCompilationFeature::defaultIncludeCallee; optimisticOpts = OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseLoopLimitChecks); methods = new LinkedHashMap<>(); graphEncoder = new GraphEncoder(ConfigurationValues.getTarget().arch); @@ -448,7 +449,7 @@ public SubstrateMethod requireFrameInformationForMethod(ResolvedJavaMethod metho AnalysisMethod aMethod = (AnalysisMethod) method; SubstrateMethod sMethod = objectReplacer.createMethod(aMethod); - CompilationInfoSupport.singleton().registerFrameInformationRequired(aMethod); + SubstrateCompilationDirectives.singleton().registerFrameInformationRequired(aMethod); return sMethod; } @@ -630,7 +631,7 @@ private void processMethod(CallTreeNode node, Deque worklist, BigB * call target does not reach the compile queue by default, e.g. if it is * inlined at image generation but not at runtime compilation. */ - CompilationInfoSupport.singleton().registerForcedCompilation(implementationMethod); + SubstrateCompilationDirectives.singleton().registerForcedCompilation(implementationMethod); } } } @@ -779,7 +780,7 @@ private static void registerDeoptEntries(CallTreeNode node) { */ for (FrameState inlineState = frameState; inlineState != null; inlineState = inlineState.outerFrameState()) { if (inlineState.bci >= 0) { - CompilationInfoSupport.singleton().registerDeoptEntry(inlineState); + SubstrateCompilationDirectives.singleton().registerDeoptEntry(inlineState); } } } @@ -804,7 +805,7 @@ private static void registerDeoptEntries(CallTreeNode node) { */ FrameState stateDuring = invoke.stateAfter().duplicateModifiedDuringCall(invoke.bci(), invoke.asNode().getStackKind()); assert stateDuring.duringCall() && !stateDuring.rethrowException(); - CompilationInfoSupport.singleton().registerDeoptEntry(stateDuring); + SubstrateCompilationDirectives.singleton().registerDeoptEntry(stateDuring); } } } @@ -891,9 +892,9 @@ public void afterHeapLayout(AfterHeapLayoutAccess a) { class RuntimeStrengthenStampsPhase extends StrengthenStampsPhase { private final HostedUniverse hUniverse; - private final GraalObjectReplacer objectReplacer; + private final GraalGraphObjectReplacer objectReplacer; - RuntimeStrengthenStampsPhase(HostedUniverse hUniverse, GraalObjectReplacer objectReplacer) { + RuntimeStrengthenStampsPhase(HostedUniverse hUniverse, GraalGraphObjectReplacer objectReplacer) { this.hUniverse = hUniverse; this.objectReplacer = objectReplacer; } diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeGraalSetup.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeGraalSetup.java deleted file mode 100644 index a8d7978f222e..000000000000 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/RuntimeGraalSetup.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2019, 2019, 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.hosted; - -import java.util.function.Function; - -import org.graalvm.compiler.nodes.spi.LoopsDataProvider; -import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.util.Providers; - -import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.graal.pointsto.meta.AnalysisUniverse; -import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.hosted.SVMHost; -import com.oracle.svm.hosted.c.NativeLibraries; -import com.oracle.svm.hosted.classinitialization.ClassInitializationSupport; -import com.oracle.svm.hosted.code.SharedRuntimeConfigurationBuilder; - -import jdk.vm.ci.meta.ConstantReflectionProvider; -import jdk.vm.ci.meta.MetaAccessProvider; - -/** - * Provides functionality during the image build for setting up Graal for compilation at runtime. - */ -public interface RuntimeGraalSetup { - - SharedRuntimeConfigurationBuilder createRuntimeConfigurationBuilder(OptionValues options, SVMHost hostVM, AnalysisUniverse aUniverse, - MetaAccessProvider metaAccess, ConstantReflectionProvider originalReflectionProvider, Function backendProvider, - NativeLibraries nativeLibraries, ClassInitializationSupport classInitializationSupport, LoopsDataProvider loopsDataProvider); - - GraalProviderObjectReplacements getProviderObjectReplacements(AnalysisMetaAccess aMetaAccess); -} diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateRuntimeGraalSetup.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java similarity index 86% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateRuntimeGraalSetup.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java index a7308687233b..25db2c1e4ba9 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateRuntimeGraalSetup.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateGraalCompilerSetup.java @@ -26,8 +26,6 @@ import java.util.function.Function; -import com.oracle.svm.graal.isolated.IsolateAwareMetaAccess; -import com.oracle.svm.graal.meta.SubstrateMetaAccess; import org.graalvm.compiler.nodes.spi.LoopsDataProvider; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; @@ -36,7 +34,9 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.graal.code.SubstrateBackend; -import com.oracle.svm.graal.isolated.IsolateAwareProviderObjectReplacements; +import com.oracle.svm.graal.isolated.IsolateAwareMetaAccess; +import com.oracle.svm.graal.isolated.IsolateAwareProviders; +import com.oracle.svm.graal.meta.SubstrateMetaAccess; import com.oracle.svm.graal.meta.SubstrateRuntimeConfigurationBuilder; import com.oracle.svm.hosted.SVMHost; import com.oracle.svm.hosted.c.NativeLibraries; @@ -46,11 +46,11 @@ import jdk.vm.ci.meta.ConstantReflectionProvider; import jdk.vm.ci.meta.MetaAccessProvider; -public class SubstrateRuntimeGraalSetup implements RuntimeGraalSetup { +public class SubstrateGraalCompilerSetup { protected final SubstrateMetaAccess sMetaAccess; - public SubstrateRuntimeGraalSetup() { + public SubstrateGraalCompilerSetup() { if (SubstrateOptions.supportCompileInIsolates()) { sMetaAccess = new IsolateAwareMetaAccess(); } else { @@ -58,17 +58,15 @@ public SubstrateRuntimeGraalSetup() { } } - @Override - public GraalProviderObjectReplacements getProviderObjectReplacements(AnalysisMetaAccess aMetaAccess) { + public SubstrateProviders getSubstrateProviders(AnalysisMetaAccess aMetaAccess) { if (SubstrateOptions.supportCompileInIsolates()) { assert sMetaAccess instanceof IsolateAwareMetaAccess; - return new IsolateAwareProviderObjectReplacements(aMetaAccess, (IsolateAwareMetaAccess) sMetaAccess); + return new IsolateAwareProviders(aMetaAccess, (IsolateAwareMetaAccess) sMetaAccess); } else { - return new GraalProviderObjectReplacements(aMetaAccess, sMetaAccess); + return new SubstrateProviders(aMetaAccess, sMetaAccess); } } - @Override public SharedRuntimeConfigurationBuilder createRuntimeConfigurationBuilder(OptionValues options, SVMHost hostVM, AnalysisUniverse aUniverse, MetaAccessProvider metaAccess, ConstantReflectionProvider originalReflectionProvider, Function backendProvider, NativeLibraries nativeLibraries, ClassInitializationSupport classInitializationSupport, LoopsDataProvider loopsDataProvider) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalProviderObjectReplacements.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java similarity index 90% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalProviderObjectReplacements.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java index 2521bb885b60..4cd65b52da28 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/GraalProviderObjectReplacements.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/SubstrateProviders.java @@ -38,20 +38,20 @@ import jdk.vm.ci.meta.MetaAccessProvider; /** - * The set of provider objects that are installed via {@link GraalObjectReplacer}. + * The set of provider objects that are installed via {@link GraalGraphObjectReplacer}. */ -public class GraalProviderObjectReplacements { +public class SubstrateProviders { private final SubstrateMetaAccess metaAccess; private final ConstantFieldProvider constantFieldProvider; private final ConstantReflectionProvider constantReflection; - GraalProviderObjectReplacements(AnalysisMetaAccess aMetaAccess, SubstrateMetaAccess metaAccess) { + SubstrateProviders(AnalysisMetaAccess aMetaAccess, SubstrateMetaAccess metaAccess) { this.metaAccess = metaAccess; this.constantFieldProvider = new SubstrateConstantFieldProvider(aMetaAccess); this.constantReflection = new SubstrateConstantReflectionProvider(this.metaAccess); } - protected GraalProviderObjectReplacements(SubstrateMetaAccess metaAccess, ConstantFieldProvider constantFieldProvider, ConstantReflectionProvider constantReflection) { + protected SubstrateProviders(SubstrateMetaAccess metaAccess, ConstantFieldProvider constantFieldProvider, ConstantReflectionProvider constantReflection) { this.metaAccess = metaAccess; this.constantFieldProvider = constantFieldProvider; this.constantReflection = constantReflection; diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviderObjectReplacements.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java similarity index 86% rename from substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviderObjectReplacements.java rename to substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java index 7094d8480b53..8999288a9b0c 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviderObjectReplacements.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/isolated/IsolateAwareProviders.java @@ -27,13 +27,13 @@ import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; -import com.oracle.svm.graal.hosted.GraalProviderObjectReplacements; +import com.oracle.svm.graal.hosted.SubstrateProviders; import com.oracle.svm.graal.meta.SubstrateConstantFieldProvider; -public final class IsolateAwareProviderObjectReplacements extends GraalProviderObjectReplacements { +public final class IsolateAwareProviders extends SubstrateProviders { private final SnippetReflectionProvider snippetReflection; - public IsolateAwareProviderObjectReplacements(AnalysisMetaAccess aMetaAccess, IsolateAwareMetaAccess sMetaAccess) { + public IsolateAwareProviders(AnalysisMetaAccess aMetaAccess, IsolateAwareMetaAccess sMetaAccess) { super(sMetaAccess, new SubstrateConstantFieldProvider(aMetaAccess), new IsolateAwareConstantReflectionProvider(sMetaAccess)); this.snippetReflection = new IsolateAwareSnippetReflectionProvider(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java new file mode 100644 index 000000000000..1b5451407b79 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/AnalysisToHostedGraphTransplanter.java @@ -0,0 +1,326 @@ +/* + * 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.hosted.code; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.List; + +import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; +import org.graalvm.compiler.core.common.Fields; +import org.graalvm.compiler.core.common.GraalOptions; +import org.graalvm.compiler.core.common.type.AbstractObjectStamp; +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampPair; +import org.graalvm.compiler.debug.DebugContext; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.graph.NodeClass; +import org.graalvm.compiler.graph.NodeSourcePosition; +import org.graalvm.compiler.nodes.FieldLocationIdentity; +import org.graalvm.compiler.nodes.PiNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; +import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; +import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; +import org.graalvm.compiler.nodes.virtual.VirtualObjectState; +import org.graalvm.compiler.options.OptionValues; + +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.core.graal.nodes.ComputedIndirectCallTargetNode; +import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; +import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; +import com.oracle.svm.core.meta.MethodPointer; +import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; +import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.meta.HostedField; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedType; +import com.oracle.svm.hosted.meta.HostedUniverse; + +import jdk.vm.ci.code.BytecodePosition; +import jdk.vm.ci.meta.ResolvedJavaField; +import jdk.vm.ci.meta.ResolvedJavaMethod; +import jdk.vm.ci.meta.ResolvedJavaType; + +public class AnalysisToHostedGraphTransplanter { + protected final HostedUniverse universe; + protected final CompileQueue compileQueue; + + public AnalysisToHostedGraphTransplanter(HostedUniverse universe, CompileQueue compileQueue) { + this.universe = universe; + this.compileQueue = compileQueue; + } + + public StructuredGraph transplantGraph(DebugContext debug, HostedMethod hMethod, CompileQueue.CompileReason reason) { + AnalysisMethod aMethod = hMethod.getWrapped(); + StructuredGraph aGraph = aMethod.decodeAnalyzedGraph(debug, null); + if (aGraph == null) { + throw VMError.shouldNotReachHere("Method not parsed during static analysis: " + aMethod.format("%r %H.%n(%p)") + ". Reachable from: " + reason); + } + + /* + * The graph in the analysis universe is no longer necessary once it is transplanted into + * the hosted universe. + */ + aMethod.setAnalyzedGraph(null); + + /* + * The static analysis always needs NodeSourcePosition. But for AOT compilation, we only + * need to preserve them when explicitly enabled, to reduce memory pressure. + */ + OptionValues compileOptions = compileQueue.getCustomizedOptions(hMethod, debug); + boolean trackNodeSourcePosition = GraalOptions.TrackNodeSourcePosition.getValue(compileOptions); + assert aMethod.equals(aGraph.method()); + StructuredGraph graph = aGraph.copy(getHostedMethod(universe, aMethod), compileOptions, debug, trackNodeSourcePosition); + + transplantEscapeAnalysisState(graph); + + IdentityHashMap replacements = new IdentityHashMap<>(); + for (Node node : graph.getNodes()) { + NodeClass nodeClass = node.getNodeClass(); + + for (int i = 0; i < nodeClass.getData().getCount(); i++) { + Object oldValue = nodeClass.getData().get(node, i); + Object newValue = replaceAnalysisObjects(oldValue, node, replacements, universe); + if (oldValue != newValue) { + nodeClass.getData().putObjectChecked(node, i, newValue); + } + } + /* + * The NodeSourcePosition is not part of the regular "data" fields, so we need to + * process it manually. + */ + if (trackNodeSourcePosition) { + node.setNodeSourcePosition((NodeSourcePosition) replaceAnalysisObjects(node.getNodeSourcePosition(), node, replacements, universe)); + } else { + node.clearNodeSourcePosition(); + } + } + + return graph; + } + + /** + * The nodes produced by escape analysis need some manual patching: escape analysis requires + * that {@link ResolvedJavaType#getInstanceFields} is stable and uses the index of a field in + * that array also to index its own data structures. But {@link AnalysisType} and + * {@link HostedType} cannot return fields in the same order: Fields that are not seen as + * reachable by the static analysis are removed from the hosted type; and the layout of objects, + * i.e., the field order, is only decided after static analysis. Therefore, we need to fix up + * all the nodes that implicitly use the field index. + */ + protected void transplantEscapeAnalysisState(StructuredGraph graph) { + for (CommitAllocationNode node : graph.getNodes().filter(CommitAllocationNode.class)) { + List values = node.getValues(); + List aValues = new ArrayList<>(values); + values.clear(); + + int aObjectStartIndex = 0; + for (VirtualObjectNode virtualObject : node.getVirtualObjects()) { + transplantVirtualObjectState(virtualObject, aValues, values, aObjectStartIndex); + aObjectStartIndex += virtualObject.entryCount(); + } + assert aValues.size() == aObjectStartIndex; + } + + for (VirtualObjectState node : graph.getNodes().filter(VirtualObjectState.class)) { + List values = node.values(); + List aValues = new ArrayList<>(values); + values.clear(); + + transplantVirtualObjectState(node.object(), aValues, values, 0); + } + + for (VirtualInstanceNode node : graph.getNodes(VirtualInstanceNode.TYPE)) { + AnalysisType aType = (AnalysisType) node.type(); + ResolvedJavaField[] aFields = node.getFields(); + assert Arrays.equals(aFields, aType.getInstanceFields(true)); + HostedField[] hFields = universe.lookup(aType).getInstanceFields(true); + /* + * We cannot directly write the final field `VirtualInstanceNode.fields`. So we rely on + * the NodeClass mechanism, which is also used to transplant all other fields. + */ + Fields nodeClassDataFields = node.getNodeClass().getData(); + for (int i = 0; i < nodeClassDataFields.getCount(); i++) { + if (nodeClassDataFields.get(node, i) == aFields) { + nodeClassDataFields.putObjectChecked(node, i, hFields); + } + } + } + } + + private void transplantVirtualObjectState(VirtualObjectNode virtualObject, List aValues, List hValues, int aObjectStartIndex) { + AnalysisType aType = (AnalysisType) virtualObject.type(); + if (aType.isArray()) { + /* For arrays, there is no change between analysis and hosted elements. */ + for (int i = 0; i < virtualObject.entryCount(); i++) { + hValues.add(aValues.get(aObjectStartIndex + i)); + } + } else { + /* + * For instance fields, we need to add fields in the order of the hosted fields. + * `AnalysisField.getPosition` gives us the index of the field in the analysis-level + * list of field values. + */ + assert virtualObject.entryCount() == aType.getInstanceFields(true).length; + HostedField[] hFields = universe.lookup(aType).getInstanceFields(true); + for (HostedField hField : hFields) { + int aPosition = hField.wrapped.getPosition(); + assert hField.wrapped.equals(aType.getInstanceFields(true)[aPosition]); + hValues.add(aValues.get(aObjectStartIndex + aPosition)); + } + } + } + + private static HostedMethod getHostedMethod(HostedUniverse universe, ResolvedJavaMethod method) { + return universe.lookup(method); + } + + static Object replaceAnalysisObjects(Object obj, Node node, IdentityHashMap replacements, HostedUniverse hUniverse) { + if (obj == null) { + return obj; + } + Object existingReplacement = replacements.get(obj); + if (existingReplacement != null) { + return existingReplacement; + } + + Object newReplacement; + + if (obj instanceof Node) { + throw VMError.shouldNotReachHere("Must not replace a Graal graph nodes, only data objects referenced from a node"); + + } else if (obj instanceof AnalysisType) { + newReplacement = hUniverse.lookup((AnalysisType) obj); + } else if (obj instanceof AnalysisMethod) { + newReplacement = getHostedMethod(hUniverse, (AnalysisMethod) obj); + } else if (obj instanceof AnalysisField) { + newReplacement = hUniverse.lookup((AnalysisField) obj); + } else if (obj instanceof FieldLocationIdentity) { + ResolvedJavaField inner = ((FieldLocationIdentity) obj).getField(); + assert inner instanceof AnalysisField; + newReplacement = new SubstrateFieldLocationIdentity((ResolvedJavaField) replaceAnalysisObjects(inner, node, replacements, hUniverse)); + } else if (obj.getClass() == ObjectStamp.class) { + ObjectStamp stamp = (ObjectStamp) obj; + if (stamp.type() == null) { + /* No actual type referenced, so we can keep the original object. */ + newReplacement = obj; + } else { + /* + * ObjectStamp references a type indirectly, so we need to provide a new stamp with + * a modified type. + */ + newReplacement = new ObjectStamp((ResolvedJavaType) replaceAnalysisObjects(stamp.type(), node, replacements, hUniverse), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), + stamp.isAlwaysArray()); + } + } else if (obj.getClass() == SubstrateNarrowOopStamp.class) { + SubstrateNarrowOopStamp stamp = (SubstrateNarrowOopStamp) obj; + if (stamp.type() == null) { + newReplacement = obj; + } else { + newReplacement = new SubstrateNarrowOopStamp((ResolvedJavaType) replaceAnalysisObjects(stamp.type(), node, replacements, hUniverse), stamp.isExactType(), stamp.nonNull(), + stamp.alwaysNull(), + stamp.isAlwaysArray(), stamp.getEncoding()); + } + } else if (obj.getClass() == PiNode.PlaceholderStamp.class) { + assert ((PiNode.PlaceholderStamp) obj).type() == null : "PlaceholderStamp never references a type"; + newReplacement = obj; + } else if (obj instanceof AbstractObjectStamp) { + throw VMError.shouldNotReachHere("missing replacement of a subclass of AbstractObjectStamp: " + obj.getClass().getTypeName()); + + } else if (obj.getClass() == StampPair.class) { + StampPair pair = (StampPair) obj; + Stamp trustedStamp = (Stamp) replaceAnalysisObjects(pair.getTrustedStamp(), node, replacements, hUniverse); + Stamp uncheckedStamp = (Stamp) replaceAnalysisObjects(pair.getUncheckedStamp(), node, replacements, hUniverse); + if (trustedStamp != pair.getTrustedStamp() || uncheckedStamp != pair.getUncheckedStamp()) { + newReplacement = StampPair.create(trustedStamp, uncheckedStamp); + } else { + newReplacement = pair; + } + + } else if (obj.getClass() == ResolvedJavaMethodBytecode.class) { + ResolvedJavaMethodBytecode bc = (ResolvedJavaMethodBytecode) obj; + newReplacement = new ResolvedJavaMethodBytecode(getHostedMethod(hUniverse, bc.getMethod()), bc.getOrigin()); + + } else if (obj instanceof Object[]) { + Object[] originalArray = (Object[]) obj; + Object[] copyArray = null; + for (int i = 0; i < originalArray.length; i++) { + Object original = originalArray[i]; + Object replaced = replaceAnalysisObjects(original, node, replacements, hUniverse); + if (replaced != original) { + if (copyArray == null) { + copyArray = Arrays.copyOf(originalArray, originalArray.length); + } + copyArray[i] = replaced; + } + } + newReplacement = copyArray != null ? copyArray : originalArray; + + } else if (obj.getClass() == NodeSourcePosition.class) { + NodeSourcePosition nsp = (NodeSourcePosition) obj; + + NodeSourcePosition replacedCaller = (NodeSourcePosition) replaceAnalysisObjects(nsp.getCaller(), node, replacements, hUniverse); + ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(nsp.getMethod(), node, replacements, hUniverse); + newReplacement = new NodeSourcePosition(nsp.getSourceLanguage(), replacedCaller, replacedMethod, nsp.getBCI(), nsp.getMarker()); + + } else if (obj.getClass() == BytecodePosition.class) { + BytecodePosition nsp = (BytecodePosition) obj; + + BytecodePosition replacedCaller = (BytecodePosition) replaceAnalysisObjects(nsp.getCaller(), node, replacements, hUniverse); + ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(nsp.getMethod(), node, replacements, hUniverse); + newReplacement = new BytecodePosition(replacedCaller, replacedMethod, nsp.getBCI()); + + } else if (obj.getClass() == SubstrateMethodPointerConstant.class) { + SubstrateMethodPointerConstant methodPointerConstant = (SubstrateMethodPointerConstant) obj; + + MethodPointer methodPointer = methodPointerConstant.pointer(); + ResolvedJavaMethod method = methodPointer.getMethod(); + ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(method, node, replacements, hUniverse); + newReplacement = new SubstrateMethodPointerConstant(new MethodPointer(replacedMethod)); + + } else if (obj.getClass() == ComputedIndirectCallTargetNode.FieldLoad.class) { + ComputedIndirectCallTargetNode.FieldLoad fieldLoad = (ComputedIndirectCallTargetNode.FieldLoad) obj; + newReplacement = new ComputedIndirectCallTargetNode.FieldLoad(hUniverse.lookup(fieldLoad.getField())); + } else if (obj.getClass() == ComputedIndirectCallTargetNode.FieldLoadIfZero.class) { + ComputedIndirectCallTargetNode.FieldLoadIfZero fieldLoadIfZero = (ComputedIndirectCallTargetNode.FieldLoadIfZero) obj; + newReplacement = new ComputedIndirectCallTargetNode.FieldLoadIfZero(fieldLoadIfZero.getObject(), hUniverse.lookup(fieldLoadIfZero.getField())); + + } else { + /* Check that we do not have a class or package name that relates to the analysis. */ + assert !obj.getClass().getName().toLowerCase().contains("analysis") : "Object " + obj + " of " + obj.getClass() + " in node " + node; + assert !obj.getClass().getName().toLowerCase().contains("pointsto") : "Object " + obj + " of " + obj.getClass() + " in node " + node; + newReplacement = obj; + } + + replacements.put(obj, newReplacement); + return newReplacement; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java index d0bfc136850a..f9edbaeb5e3a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java @@ -110,15 +110,16 @@ public boolean isDeoptTarget() { } public boolean isDeoptEntry(int bci, boolean duringCall, boolean rethrowException) { - return isDeoptTarget() && (deoptOrigin.compilationInfo.canDeoptForTesting || CompilationInfoSupport.singleton().isDeoptEntry(method, bci, duringCall, rethrowException)); + return isDeoptTarget() && (deoptOrigin.compilationInfo.canDeoptForTesting || SubstrateCompilationDirectives.singleton().isDeoptEntry(method, bci, duringCall, rethrowException)); } /** * Returns whether this bci was registered as a potential deoptimization entrypoint via - * {@link CompilationInfoSupport#registerDeoptEntry}. + * {@link SubstrateCompilationDirectives#registerDeoptEntry}. */ public boolean isRegisteredDeoptEntry(int bci, boolean duringCall, boolean rethrowException) { - return isDeoptTarget() && CompilationInfoSupport.singleton().isDeoptTarget(method) && CompilationInfoSupport.singleton().isDeoptEntry(method, bci, duringCall, rethrowException); + return isDeoptTarget() && SubstrateCompilationDirectives.singleton().isDeoptTarget(method) && + SubstrateCompilationDirectives.singleton().isDeoptEntry(method, bci, duringCall, rethrowException); } public boolean canDeoptForTesting() { 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 9363bbc0f21b..fd8ce187b08e 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 @@ -25,15 +25,11 @@ package com.oracle.svm.hosted.code; import java.lang.annotation.Annotation; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; -import java.util.HashMap; -import java.util.IdentityHashMap; import java.util.List; -import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -54,13 +50,7 @@ import org.graalvm.compiler.core.GraalCompiler; import org.graalvm.compiler.core.common.CompilationIdentifier; import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity; -import org.graalvm.compiler.core.common.Fields; -import org.graalvm.compiler.core.common.GraalOptions; import org.graalvm.compiler.core.common.spi.CodeGenProviders; -import org.graalvm.compiler.core.common.type.AbstractObjectStamp; -import org.graalvm.compiler.core.common.type.ObjectStamp; -import org.graalvm.compiler.core.common.type.Stamp; -import org.graalvm.compiler.core.common.type.StampPair; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.DebugContext.Description; import org.graalvm.compiler.debug.DebugHandlersFactory; @@ -69,36 +59,22 @@ import org.graalvm.compiler.debug.Indent; import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.graph.Node.NodeIntrinsic; -import org.graalvm.compiler.graph.NodeClass; -import org.graalvm.compiler.graph.NodeSourcePosition; -import org.graalvm.compiler.lir.RedundantMoveElimination; -import org.graalvm.compiler.lir.alloc.RegisterAllocationPhase; import org.graalvm.compiler.lir.asm.CompilationResultBuilder; import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; import org.graalvm.compiler.lir.asm.DataBuilder; import org.graalvm.compiler.lir.asm.FrameContext; import org.graalvm.compiler.lir.framemap.FrameMap; -import org.graalvm.compiler.lir.phases.LIRPhase; import org.graalvm.compiler.lir.phases.LIRSuites; -import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase.PostAllocationOptimizationContext; import org.graalvm.compiler.nodes.CallTargetNode; import org.graalvm.compiler.nodes.ConstantNode; import org.graalvm.compiler.nodes.EncodedGraph; -import org.graalvm.compiler.nodes.FieldLocationIdentity; -import org.graalvm.compiler.nodes.FixedNode; -import org.graalvm.compiler.nodes.FixedWithNextNode; import org.graalvm.compiler.nodes.FrameState; import org.graalvm.compiler.nodes.GraphState.GuardsStage; import org.graalvm.compiler.nodes.IndirectCallTargetNode; import org.graalvm.compiler.nodes.Invoke; -import org.graalvm.compiler.nodes.InvokeNode; import org.graalvm.compiler.nodes.ParameterNode; -import org.graalvm.compiler.nodes.PiNode; -import org.graalvm.compiler.nodes.StartNode; -import org.graalvm.compiler.nodes.StateSplit; import org.graalvm.compiler.nodes.StructuredGraph; import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.extended.ForeignCallNode; import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedFoldInvocationPlugin; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.BytecodeExceptionMode; @@ -106,64 +82,38 @@ import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; import org.graalvm.compiler.nodes.java.MethodCallTargetNode; -import org.graalvm.compiler.nodes.util.GraphUtil; -import org.graalvm.compiler.nodes.virtual.CommitAllocationNode; -import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode; -import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; -import org.graalvm.compiler.nodes.virtual.VirtualObjectState; import org.graalvm.compiler.options.OptionValues; -import org.graalvm.compiler.phases.BasePhase; import org.graalvm.compiler.phases.OptimisticOptimizations; import org.graalvm.compiler.phases.PhaseSuite; -import org.graalvm.compiler.phases.common.BoxNodeOptimizationPhase; import org.graalvm.compiler.phases.common.CanonicalizerPhase; -import org.graalvm.compiler.phases.common.FixReadsPhase; -import org.graalvm.compiler.phases.common.FloatingReadPhase; import org.graalvm.compiler.phases.tiers.HighTierContext; -import org.graalvm.compiler.phases.tiers.LowTierContext; -import org.graalvm.compiler.phases.tiers.MidTierContext; import org.graalvm.compiler.phases.tiers.Suites; import org.graalvm.compiler.phases.util.GraphOrder; import org.graalvm.compiler.phases.util.Providers; import org.graalvm.compiler.replacements.PEGraphDecoder; import org.graalvm.compiler.replacements.nodes.MacroInvokable; -import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; -import org.graalvm.compiler.virtual.phases.ea.ReadEliminationPhase; import org.graalvm.nativeimage.ImageSingletons; import com.oracle.graal.pointsto.api.PointstoOptions; import com.oracle.graal.pointsto.flow.AnalysisParsedGraph; import com.oracle.graal.pointsto.infrastructure.GraphProvider.Purpose; -import com.oracle.graal.pointsto.meta.AnalysisField; -import com.oracle.graal.pointsto.meta.AnalysisMethod; -import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; import com.oracle.graal.pointsto.util.CompletionExecutor; import com.oracle.graal.pointsto.util.CompletionExecutor.DebugContextRunnable; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateOptions.OptimizationLevel; -import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.Uninterruptible; -import com.oracle.svm.core.code.FrameInfoEncoder; -import com.oracle.svm.core.deopt.DeoptEntryInfopoint; import com.oracle.svm.core.deopt.DeoptTest; import com.oracle.svm.core.deopt.Specialize; -import com.oracle.svm.core.graal.GraalConfiguration; -import com.oracle.svm.core.graal.code.StubCallingConvention; import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.graal.meta.RuntimeConfiguration; import com.oracle.svm.core.graal.meta.SubstrateForeignCallLinkage; import com.oracle.svm.core.graal.meta.SubstrateForeignCallsProvider; -import com.oracle.svm.core.graal.nodes.ComputedIndirectCallTargetNode; import com.oracle.svm.core.graal.nodes.DeoptEntryNode; -import com.oracle.svm.core.graal.nodes.DeoptTestNode; -import com.oracle.svm.core.graal.nodes.SubstrateFieldLocationIdentity; -import com.oracle.svm.core.graal.nodes.SubstrateNarrowOopStamp; import com.oracle.svm.core.graal.phases.DeadStoreRemovalPhase; import com.oracle.svm.core.graal.phases.OptimizeExceptionPathsPhase; -import com.oracle.svm.core.graal.snippets.DeoptTester; -import com.oracle.svm.core.graal.stackvalue.StackValueNode; +import com.oracle.svm.core.heap.RestrictHeapAccess; import com.oracle.svm.core.heap.RestrictHeapAccessCallees; import com.oracle.svm.core.meta.MethodPointer; import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; @@ -174,9 +124,7 @@ import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.ProgressReporter; import com.oracle.svm.hosted.diagnostic.HostedHeapDumpFeature; -import com.oracle.svm.hosted.meta.HostedField; import com.oracle.svm.hosted.meta.HostedMethod; -import com.oracle.svm.hosted.meta.HostedType; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.phases.DevirtualizeCallsPhase; import com.oracle.svm.hosted.phases.HostedGraphBuilderPhase; @@ -186,21 +134,15 @@ import com.oracle.svm.hosted.substitute.DeletedMethod; import com.oracle.svm.util.ImageBuildStatistics; -import jdk.vm.ci.code.BytecodeFrame; -import jdk.vm.ci.code.BytecodePosition; -import jdk.vm.ci.code.DebugInfo; import jdk.vm.ci.code.Register; import jdk.vm.ci.code.site.Call; import jdk.vm.ci.code.site.ConstantReference; import jdk.vm.ci.code.site.DataPatch; import jdk.vm.ci.code.site.Infopoint; -import jdk.vm.ci.code.site.InfopointReason; import jdk.vm.ci.code.site.Reference; import jdk.vm.ci.meta.Constant; import jdk.vm.ci.meta.MetaAccessProvider; -import jdk.vm.ci.meta.ResolvedJavaField; import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.VMConstant; public class CompileQueue { @@ -228,6 +170,7 @@ public interface CompileFunction { private SnippetReflectionProvider snippetReflection; private final FeatureHandler featureHandler; protected final GlobalMetrics metricValues = new GlobalMetrics(); + private final AnalysisToHostedGraphTransplanter graphTransplanter; private volatile boolean inliningProgress; @@ -402,10 +345,15 @@ public CompileQueue(DebugContext debug, FeatureHandler featureHandler, HostedUni this.executor = new CompletionExecutor(universe.getBigBang(), executorService, universe.getBigBang().getHeartbeatCallback()); this.featureHandler = featureHandler; this.snippetReflection = snippetReflection; + this.graphTransplanter = createGraphTransplanter(); callForReplacements(debug, runtimeConfig); } + protected AnalysisToHostedGraphTransplanter createGraphTransplanter() { + return new AnalysisToHostedGraphTransplanter(universe, this); + } + public static OptimisticOptimizations getOptimisticOpts() { return OptimisticOptimizations.ALL.remove(OptimisticOptimizations.Optimization.UseLoopLimitChecks); } @@ -475,10 +423,10 @@ private void createSuites() { regularSuites = NativeImageGenerator.createSuites(featureHandler, runtimeConfig, snippetReflection, true); modifyRegularSuites(regularSuites); deoptTargetSuites = NativeImageGenerator.createSuites(featureHandler, runtimeConfig, snippetReflection, true); - removeDeoptTargetOptimizations(deoptTargetSuites); + DeoptimizationUtils.removeDeoptTargetOptimizations(deoptTargetSuites); regularLIRSuites = NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), true); deoptTargetLIRSuites = NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), true); - removeDeoptTargetOptimizations(deoptTargetLIRSuites); + DeoptimizationUtils.removeDeoptTargetOptimizations(deoptTargetLIRSuites); } protected void modifyRegularSuites(@SuppressWarnings("unused") Suites suites) { @@ -600,7 +548,7 @@ protected void parseAll() throws InterruptedException { private void parseAheadOfTimeCompiledMethods() { for (HostedMethod method : universe.getMethods()) { - if (method.isEntryPoint() || CompilationInfoSupport.singleton().isForcedCompilation(method) || + if (method.isEntryPoint() || SubstrateCompilationDirectives.singleton().isForcedCompilation(method) || method.wrapped.isDirectRootMethod() && method.wrapped.isImplementationInvoked()) { ensureParsed(method, null, new EntryPointReason()); } @@ -633,7 +581,7 @@ private void parseDeoptimizationTargetMethods() { * targets. */ universe.getMethods().stream() - .filter(method -> CompilationInfoSupport.singleton().isDeoptTarget(method)) + .filter(method -> SubstrateCompilationDirectives.singleton().isDeoptTarget(method)) .forEach(method -> ensureParsed(universe.createDeoptTarget(method), null, new EntryPointReason())); /* @@ -642,7 +590,7 @@ private void parseDeoptimizationTargetMethods() { * possible deoptimization entry points are emitted. */ universe.getMethods().stream() - .filter(method -> method.getWrapped().isImplementationInvoked() && canDeoptForTesting(method)) + .filter(method -> method.getWrapped().isImplementationInvoked() && DeoptimizationUtils.canDeoptForTesting(universe, method, deoptimizeAll)) .forEach(this::ensureParsedForDeoptTesting); } @@ -812,7 +760,7 @@ protected void compileAll() throws InterruptedException { public void scheduleEntryPoints() { for (HostedMethod method : universe.getMethods()) { - if (!ignoreEntryPoint(method) && (method.isEntryPoint() || CompilationInfoSupport.singleton().isForcedCompilation(method)) || + if (!ignoreEntryPoint(method) && (method.isEntryPoint() || SubstrateCompilationDirectives.singleton().isForcedCompilation(method)) || method.wrapped.isDirectRootMethod() && method.wrapped.isImplementationInvoked()) { ensureCompiled(method, new EntryPointReason()); } @@ -854,247 +802,6 @@ protected void doParse(DebugContext debug, ParseTask task) { fun.parse(debug, task.method, task.reason, runtimeConfig); } - private StructuredGraph transplantGraph(DebugContext debug, HostedMethod hMethod, CompileReason reason) { - AnalysisMethod aMethod = hMethod.getWrapped(); - StructuredGraph aGraph = aMethod.decodeAnalyzedGraph(debug, null); - if (aGraph == null) { - throw VMError.shouldNotReachHere("Method not parsed during static analysis: " + aMethod.format("%r %H.%n(%p)") + ". Reachable from: " + reason); - } - - /* - * The graph in the analysis universe is no longer necessary once it is transplanted into - * the hosted universe. - */ - aMethod.setAnalyzedGraph(null); - - /* - * The static analysis always needs NodeSourcePosition. But for AOT compilation, we only - * need to preserve them when explicitly enabled, to reduce memory pressure. - */ - OptionValues compileOptions = getCustomizedOptions(hMethod, debug); - boolean trackNodeSourcePosition = GraalOptions.TrackNodeSourcePosition.getValue(compileOptions); - StructuredGraph graph = aGraph.copy(universe.lookup(aGraph.method()), compileOptions, debug, trackNodeSourcePosition); - - transplantEscapeAnalysisState(graph); - - IdentityHashMap replacements = new IdentityHashMap<>(); - for (Node node : graph.getNodes()) { - NodeClass nodeClass = node.getNodeClass(); - - for (int i = 0; i < nodeClass.getData().getCount(); i++) { - Object oldValue = nodeClass.getData().get(node, i); - Object newValue = replaceAnalysisObjects(oldValue, node, replacements, universe); - if (oldValue != newValue) { - nodeClass.getData().putObjectChecked(node, i, newValue); - } - } - /* - * The NodeSourcePosition is not part of the regular "data" fields, so we need to - * process it manually. - */ - if (trackNodeSourcePosition) { - node.setNodeSourcePosition((NodeSourcePosition) replaceAnalysisObjects(node.getNodeSourcePosition(), node, replacements, universe)); - } else { - node.clearNodeSourcePosition(); - } - } - - return graph; - } - - public static Object replaceAnalysisObjects(Object obj, Node node, IdentityHashMap replacements, HostedUniverse hUniverse) { - if (obj == null) { - return obj; - } - Object existingReplacement = replacements.get(obj); - if (existingReplacement != null) { - return existingReplacement; - } - - Object newReplacement; - - if (obj instanceof Node) { - throw VMError.shouldNotReachHere("Must not replace a Graal graph nodes, only data objects referenced from a node"); - - } else if (obj instanceof AnalysisType) { - newReplacement = hUniverse.lookup((AnalysisType) obj); - } else if (obj instanceof AnalysisMethod) { - newReplacement = hUniverse.lookup((AnalysisMethod) obj); - } else if (obj instanceof AnalysisField) { - newReplacement = hUniverse.lookup((AnalysisField) obj); - } else if (obj instanceof FieldLocationIdentity) { - ResolvedJavaField inner = ((FieldLocationIdentity) obj).getField(); - assert inner instanceof AnalysisField; - newReplacement = new SubstrateFieldLocationIdentity((ResolvedJavaField) replaceAnalysisObjects(inner, node, replacements, hUniverse)); - } else if (obj.getClass() == ObjectStamp.class) { - ObjectStamp stamp = (ObjectStamp) obj; - if (stamp.type() == null) { - /* No actual type referenced, so we can keep the original object. */ - newReplacement = obj; - } else { - /* - * ObjectStamp references a type indirectly, so we need to provide a new stamp with - * a modified type. - */ - newReplacement = new ObjectStamp((ResolvedJavaType) replaceAnalysisObjects(stamp.type(), node, replacements, hUniverse), stamp.isExactType(), stamp.nonNull(), stamp.alwaysNull(), - stamp.isAlwaysArray()); - } - } else if (obj.getClass() == SubstrateNarrowOopStamp.class) { - SubstrateNarrowOopStamp stamp = (SubstrateNarrowOopStamp) obj; - if (stamp.type() == null) { - newReplacement = obj; - } else { - newReplacement = new SubstrateNarrowOopStamp((ResolvedJavaType) replaceAnalysisObjects(stamp.type(), node, replacements, hUniverse), stamp.isExactType(), stamp.nonNull(), - stamp.alwaysNull(), - stamp.isAlwaysArray(), stamp.getEncoding()); - } - } else if (obj.getClass() == PiNode.PlaceholderStamp.class) { - assert ((PiNode.PlaceholderStamp) obj).type() == null : "PlaceholderStamp never references a type"; - newReplacement = obj; - } else if (obj instanceof AbstractObjectStamp) { - throw VMError.shouldNotReachHere("missing replacement of a subclass of AbstractObjectStamp: " + obj.getClass().getTypeName()); - - } else if (obj.getClass() == StampPair.class) { - StampPair pair = (StampPair) obj; - Stamp trustedStamp = (Stamp) replaceAnalysisObjects(pair.getTrustedStamp(), node, replacements, hUniverse); - Stamp uncheckedStamp = (Stamp) replaceAnalysisObjects(pair.getUncheckedStamp(), node, replacements, hUniverse); - if (trustedStamp != pair.getTrustedStamp() || uncheckedStamp != pair.getUncheckedStamp()) { - newReplacement = StampPair.create(trustedStamp, uncheckedStamp); - } else { - newReplacement = pair; - } - - } else if (obj.getClass() == ResolvedJavaMethodBytecode.class) { - ResolvedJavaMethodBytecode bc = (ResolvedJavaMethodBytecode) obj; - newReplacement = new ResolvedJavaMethodBytecode(hUniverse.lookup(bc.getMethod()), bc.getOrigin()); - - } else if (obj instanceof Object[]) { - Object[] originalArray = (Object[]) obj; - Object[] copyArray = null; - for (int i = 0; i < originalArray.length; i++) { - Object original = originalArray[i]; - Object replaced = replaceAnalysisObjects(original, node, replacements, hUniverse); - if (replaced != original) { - if (copyArray == null) { - copyArray = Arrays.copyOf(originalArray, originalArray.length); - } - copyArray[i] = replaced; - } - } - newReplacement = copyArray != null ? copyArray : originalArray; - - } else if (obj.getClass() == NodeSourcePosition.class) { - NodeSourcePosition nsp = (NodeSourcePosition) obj; - - NodeSourcePosition replacedCaller = (NodeSourcePosition) replaceAnalysisObjects(nsp.getCaller(), node, replacements, hUniverse); - ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(nsp.getMethod(), node, replacements, hUniverse); - newReplacement = new NodeSourcePosition(nsp.getSourceLanguage(), replacedCaller, replacedMethod, nsp.getBCI(), nsp.getMarker()); - - } else if (obj.getClass() == BytecodePosition.class) { - BytecodePosition nsp = (BytecodePosition) obj; - - BytecodePosition replacedCaller = (BytecodePosition) replaceAnalysisObjects(nsp.getCaller(), node, replacements, hUniverse); - ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(nsp.getMethod(), node, replacements, hUniverse); - newReplacement = new BytecodePosition(replacedCaller, replacedMethod, nsp.getBCI()); - - } else if (obj.getClass() == SubstrateMethodPointerConstant.class) { - SubstrateMethodPointerConstant methodPointerConstant = (SubstrateMethodPointerConstant) obj; - - MethodPointer methodPointer = methodPointerConstant.pointer(); - ResolvedJavaMethod method = methodPointer.getMethod(); - ResolvedJavaMethod replacedMethod = (ResolvedJavaMethod) replaceAnalysisObjects(method, node, replacements, hUniverse); - newReplacement = new SubstrateMethodPointerConstant(new MethodPointer(replacedMethod)); - - } else if (obj.getClass() == ComputedIndirectCallTargetNode.FieldLoad.class) { - ComputedIndirectCallTargetNode.FieldLoad fieldLoad = (ComputedIndirectCallTargetNode.FieldLoad) obj; - newReplacement = new ComputedIndirectCallTargetNode.FieldLoad(hUniverse.lookup(fieldLoad.getField())); - } else if (obj.getClass() == ComputedIndirectCallTargetNode.FieldLoadIfZero.class) { - ComputedIndirectCallTargetNode.FieldLoadIfZero fieldLoadIfZero = (ComputedIndirectCallTargetNode.FieldLoadIfZero) obj; - newReplacement = new ComputedIndirectCallTargetNode.FieldLoadIfZero(fieldLoadIfZero.getObject(), hUniverse.lookup(fieldLoadIfZero.getField())); - - } else { - /* Check that we do not have a class or package name that relates to the analysis. */ - assert !obj.getClass().getName().toLowerCase().contains("analysis") : "Object " + obj + " of " + obj.getClass() + " in node " + node; - assert !obj.getClass().getName().toLowerCase().contains("pointsto") : "Object " + obj + " of " + obj.getClass() + " in node " + node; - newReplacement = obj; - } - - replacements.put(obj, newReplacement); - return newReplacement; - } - - /** - * The nodes produced by escape analysis need some manual patching: escape analysis requires - * that {@link ResolvedJavaType#getInstanceFields} is stable and uses the index of a field in - * that array also to index its own data structures. But {@link AnalysisType} and - * {@link HostedType} cannot return fields in the same order: Fields that are not seen as - * reachable by the static analysis are removed from the hosted type; and the layout of objects, - * i.e., the field order, is only decided after static analysis. Therefore, we need to fix up - * all the nodes that implicitly use the field index. - */ - protected void transplantEscapeAnalysisState(StructuredGraph graph) { - for (CommitAllocationNode node : graph.getNodes().filter(CommitAllocationNode.class)) { - List values = node.getValues(); - List aValues = new ArrayList<>(values); - values.clear(); - - int aObjectStartIndex = 0; - for (VirtualObjectNode virtualObject : node.getVirtualObjects()) { - transplantVirtualObjectState(virtualObject, aValues, values, aObjectStartIndex); - aObjectStartIndex += virtualObject.entryCount(); - } - assert aValues.size() == aObjectStartIndex; - } - - for (VirtualObjectState node : graph.getNodes().filter(VirtualObjectState.class)) { - List values = node.values(); - List aValues = new ArrayList<>(values); - values.clear(); - - transplantVirtualObjectState(node.object(), aValues, values, 0); - } - - for (VirtualInstanceNode node : graph.getNodes(VirtualInstanceNode.TYPE)) { - AnalysisType aType = (AnalysisType) node.type(); - ResolvedJavaField[] aFields = node.getFields(); - assert Arrays.equals(aFields, aType.getInstanceFields(true)); - HostedField[] hFields = universe.lookup(aType).getInstanceFields(true); - /* - * We cannot directly write the final field `VirtualInstanceNode.fields`. So we rely on - * the NodeClass mechanism, which is also used to transplant all other fields. - */ - Fields nodeClassDataFields = node.getNodeClass().getData(); - for (int i = 0; i < nodeClassDataFields.getCount(); i++) { - if (nodeClassDataFields.get(node, i) == aFields) { - nodeClassDataFields.putObjectChecked(node, i, hFields); - } - } - } - } - - private void transplantVirtualObjectState(VirtualObjectNode virtualObject, List aValues, List hValues, int aObjectStartIndex) { - AnalysisType aType = (AnalysisType) virtualObject.type(); - if (aType.isArray()) { - /* For arrays, there is no change between analysis and hosted elements. */ - for (int i = 0; i < virtualObject.entryCount(); i++) { - hValues.add(aValues.get(aObjectStartIndex + i)); - } - } else { - /* - * For instance fields, we need to add fields in the order of the hosted fields. - * `AnalysisField.getPosition` gives us the index of the field in the analysis-level - * list of field values. - */ - assert virtualObject.entryCount() == aType.getInstanceFields(true).length; - HostedField[] hFields = universe.lookup(aType).getInstanceFields(true); - for (HostedField hField : hFields) { - int aPosition = hField.wrapped.getPosition(); - assert hField.wrapped.equals(aType.getInstanceFields(true)[aPosition]); - hValues.add(aValues.get(aObjectStartIndex + aPosition)); - } - } - } - private final boolean parseOnce = SubstrateOptions.parseOnce(); @SuppressWarnings("try") @@ -1110,7 +817,7 @@ private void defaultParseFunction(DebugContext debug, HostedMethod method, Compi StructuredGraph graph; if (parseOnce) { - graph = transplantGraph(debug, method, reason); + graph = graphTransplanter.transplantGraph(debug, method, reason); } else { graph = method.buildGraph(debug, method, providers, Purpose.AOT_COMPILATION); if (graph == null) { @@ -1239,54 +946,17 @@ protected GraphBuilderConfiguration createHostedGraphBuilderConfiguration(Hosted return gbConf; } - protected boolean containsStackValueNode(HostedMethod method) { - return universe.getBigBang().getHostVM().containsStackValueNode(method.wrapped); - } - protected boolean canBeUsedForInlining(Invoke invoke) { HostedMethod caller = (HostedMethod) invoke.asNode().graph().method(); HostedMethod callee = (HostedMethod) invoke.callTarget().targetMethod(); - if (canDeoptForTesting(caller) && Modifier.isNative(callee.getModifiers())) { - /* - * We must not deoptimize in the stubs for native functions, since they don't have a - * valid bytecode state. - */ - return false; - } - if (canDeoptForTesting(caller) && containsStackValueNode(callee)) { + if (!DeoptimizationUtils.canBeUsedForInlining(universe, caller, callee, invoke.bci(), deoptimizeAll)) { /* - * We must not inline a method that has stack values and can be deoptimized. + * Inlining will violate deoptimization requirements. */ return false; } - if (caller.compilationInfo.isDeoptTarget()) { - if (caller.compilationInfo.isDeoptEntry(invoke.bci(), true, false)) { - /* - * The call can be on the stack for a deoptimization, so we need an actual - * non-inlined invoke to deoptimize too. - * - * We could lift this restriction by providing an explicit deopt entry point (with - * the correct exception handling edges) in addition to the inlined method. - */ - return false; - } - if (CompilationInfoSupport.singleton().isDeoptInliningExclude(callee)) { - /* - * The graphs for runtime compilation have an intrinisic for the callee, which might - * alter the behavior. Be safe and do not inline, otherwise we might optimize too - * aggressively. - * - * For example, the Truffle method CompilerDirectives.inCompiledCode is - * intrinisified to return a constant with the opposite value than returned by the - * method we would inline here, i.e., we would constant-fold away the compiled-code - * only code (which is the code we need deoptimization entry points for). - */ - return false; - } - } - if (callee.getAnnotation(Specialize.class) != null) { return false; } @@ -1423,7 +1093,7 @@ private CompilationResult defaultCompileFunction(DebugContext debug, HostedMetho try (DebugContext.Scope s = debug.scope("Compiling", graph, method, this)) { if (deoptimizeAll && method.compilationInfo.canDeoptForTesting) { - insertDeoptTests(method, graph); + DeoptimizationUtils.insertDeoptTests(method, graph); } method.compilationInfo.numNodesBeforeCompilation = graph.getNodeCount(); method.compilationInfo.numDeoptEntryPoints = graph.getNodes().filter(DeoptEntryNode.class).count(); @@ -1444,7 +1114,7 @@ private CompilationResult defaultCompileFunction(DebugContext debug, HostedMetho method.compilationInfo.numNodesAfterCompilation = graph.getNodeCount(); if (method.compilationInfo.isDeoptTarget()) { - assert verifyDeoptTarget(method, graph, result); + assert DeoptimizationUtils.verifyDeoptTarget(method, graph, result); } ensureCalleesCompiled(method, reason, result); @@ -1494,188 +1164,6 @@ protected final void ensureCompiledForMethodPointerConstants(HostedMethod method } } - protected void removeDeoptTargetOptimizations(Suites suites) { - GraalConfiguration.hostedInstance().removeDeoptTargetOptimizations(suites); - - PhaseSuite highTier = suites.getHighTier(); - highTier.removePhase(PartialEscapePhase.class); - highTier.removePhase(ReadEliminationPhase.class); - highTier.removePhase(BoxNodeOptimizationPhase.class); - PhaseSuite midTier = suites.getMidTier(); - midTier.removePhase(FloatingReadPhase.class); - PhaseSuite lowTier = suites.getLowTier(); - ListIterator> it = lowTier.findPhase(FixReadsPhase.class); - if (it != null) { - FixReadsPhase fixReads = (FixReadsPhase) it.previous(); - it.remove(); - boolean replaceInputsWithConstants = false; - it.add(new FixReadsPhase(replaceInputsWithConstants, fixReads.getSchedulePhase())); - } - } - - private static void removeDeoptTargetOptimizations(LIRSuites lirSuites) { - ListIterator> it = lirSuites.getPostAllocationOptimizationStage().findPhase(RedundantMoveElimination.class); - if (it != null) { - it.remove(); - } - lirSuites.getAllocationStage().findPhaseInstance(RegisterAllocationPhase.class).setNeverSpillConstants(true); - } - - private static boolean verifyDeoptTarget(HostedMethod method, StructuredGraph graph, CompilationResult result) { - Map encodedBciMap = new HashMap<>(); - - /* - * All deopt targets must have a graph. - */ - assert graph != null : "Deopt target must have a graph."; - - /* - * No deopt targets can have a StackValueNode in the graph. - */ - assert graph.getNodes(StackValueNode.TYPE).isEmpty() : "No stack value nodes must be present in deopt target."; - - for (Infopoint infopoint : result.getInfopoints()) { - if (infopoint.debugInfo != null) { - DebugInfo debugInfo = infopoint.debugInfo; - if (!debugInfo.hasFrame()) { - continue; - } - BytecodeFrame topFrame = debugInfo.frame(); - - BytecodeFrame rootFrame = topFrame; - while (rootFrame.caller() != null) { - rootFrame = rootFrame.caller(); - } - assert rootFrame.getMethod().equals(method); - - boolean isDeoptEntry = method.compilationInfo.isDeoptEntry(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException); - if (infopoint instanceof DeoptEntryInfopoint) { - assert isDeoptEntry; - } else if (rootFrame.duringCall && isDeoptEntry) { - assert infopoint instanceof Call || isSingleSteppingInfopoint(infopoint); - } else { - continue; - } - - long encodedBci = FrameInfoEncoder.encodeBci(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException); - if (encodedBciMap.containsKey(encodedBci)) { - assert encodedBciMap.get(encodedBci).equals(rootFrame) : "duplicate encoded bci " + encodedBci + " in deopt target " + method + " with different debug info:\n\n" + rootFrame + - "\n\n" + encodedBciMap.get(encodedBci); - } - encodedBciMap.put(encodedBci, rootFrame); - } - } - - return true; - } - - private static boolean isSingleSteppingInfopoint(Infopoint infopoint) { - return infopoint.reason == InfopointReason.METHOD_START || - infopoint.reason == InfopointReason.METHOD_END || - infopoint.reason == InfopointReason.BYTECODE_POSITION; - } - - /** - * Returns true if a method should be considered as deoptimization source. This is only a - * feature for testing. Note that usually all image compiled methods cannot deoptimize. - */ - protected boolean canDeoptForTesting(HostedMethod method) { - if (method.getName().equals("")) { - /* Cannot deoptimize into static initializers. */ - return false; - } - - if (method.getAnnotation(DeoptTest.class) != null) { - return true; - } - - if (method.isEntryPoint()) { - /* - * Entry points from C have special entry/exit nodes added, so they cannot be - * deoptimized. - */ - return false; - } - if (method.isNative()) { - /* - * Native methods (i.e., the stubs that actually perform the native calls) cannot be - * deoptimized. - */ - return false; - } - if (method.wrapped.isIntrinsicMethod()) { - return false; - } - if (Uninterruptible.Utils.isUninterruptible(method)) { - return false; - } - if (method.getAnnotation(RestrictHeapAccess.class) != null) { - return false; - } - if (StubCallingConvention.Utils.hasStubCallingConvention(method)) { - /* Deoptimization runtime cannot fill the callee saved registers. */ - return false; - } - if (containsStackValueNode(method)) { - return false; - } - - if (deoptimizeAll) { - /* - * The DeoptimizeAll option is set. So we use all methods for deoptimization testing. - * Exclude some "runtime" methods, like the heap code, via this blacklist. Issue GR-1706 - * tracks the bug in DebugValueMap. - */ - String className = method.getDeclaringClass().getName(); - if (className.contains("/svm/core/code/CodeInfoEncoder") || - className.contains("com/oracle/svm/core/thread/JavaThreads") || - className.contains("com/oracle/svm/core/thread/PlatformThreads") || - className.contains("com/oracle/svm/core/heap/") || - className.contains("com/oracle/svm/core/genscavenge/") || - className.contains("com/oracle/svm/core/thread/VMOperationControl") || - className.contains("debug/internal/DebugValueMap") && method.getName().equals("registerTopLevel")) { - return false; - } - /* - * Method without bytecodes, e.g., methods that have a manually constructed graph, are - * usually not deoptimizable. This needs to change as soon as we want to runtime compile - * our synthetic annotation methods. - */ - if (method.getCode() == null) { - return false; - } - - return true; - } else { - return false; - } - } - - /** - * Inserts a call to {@link DeoptTester#deoptTest} right after FixedWithNextNode StateSplits. - * - * @param method method that is being augmented with deopt test calls - * @param graph The graph of a deoptimizable method or the corresponding deopt target method. - */ - private static void insertDeoptTests(HostedMethod method, StructuredGraph graph) { - for (Node node : graph.getNodes()) { - if (node instanceof FixedWithNextNode && node instanceof StateSplit && !(node instanceof InvokeNode) && !(node instanceof ForeignCallNode) && !(node instanceof DeoptTestNode) && - !(method.isSynchronized() && node instanceof StartNode)) { - FixedWithNextNode fixedWithNext = (FixedWithNextNode) node; - FixedNode next = fixedWithNext.next(); - DeoptTestNode testNode = graph.add(new DeoptTestNode()); - fixedWithNext.setNext(null); - testNode.setNext(next); - fixedWithNext.setNext(testNode); - if (((StateSplit) node).hasSideEffect() && ((StateSplit) node).stateAfter() != null) { - testNode.setStateAfter(((StateSplit) node).stateAfter().duplicateWithVirtualState()); - } else { - testNode.setStateAfter(GraphUtil.findLastFrameState((FixedNode) node).duplicateWithVirtualState()); - } - } - } - } - public Map getCompilationResults() { Map result = new TreeMap<>(HostedUniverse.METHOD_COMPARATOR); for (Entry entry : compilations.entrySet()) { 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 new file mode 100644 index 000000000000..9239165dff33 --- /dev/null +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java @@ -0,0 +1,328 @@ +/* + * 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.hosted.code; + +import java.lang.reflect.Modifier; +import java.util.HashMap; +import java.util.ListIterator; +import java.util.Map; + +import org.graalvm.compiler.code.CompilationResult; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.lir.RedundantMoveElimination; +import org.graalvm.compiler.lir.alloc.RegisterAllocationPhase; +import org.graalvm.compiler.lir.phases.LIRPhase; +import org.graalvm.compiler.lir.phases.LIRSuites; +import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase; +import org.graalvm.compiler.nodes.FixedNode; +import org.graalvm.compiler.nodes.FixedWithNextNode; +import org.graalvm.compiler.nodes.InvokeNode; +import org.graalvm.compiler.nodes.StartNode; +import org.graalvm.compiler.nodes.StateSplit; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.extended.ForeignCallNode; +import org.graalvm.compiler.nodes.util.GraphUtil; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.PhaseSuite; +import org.graalvm.compiler.phases.common.BoxNodeOptimizationPhase; +import org.graalvm.compiler.phases.common.FixReadsPhase; +import org.graalvm.compiler.phases.common.FloatingReadPhase; +import org.graalvm.compiler.phases.tiers.HighTierContext; +import org.graalvm.compiler.phases.tiers.LowTierContext; +import org.graalvm.compiler.phases.tiers.MidTierContext; +import org.graalvm.compiler.phases.tiers.Suites; +import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase; +import org.graalvm.compiler.virtual.phases.ea.ReadEliminationPhase; + +import com.oracle.svm.core.Uninterruptible; +import com.oracle.svm.core.code.FrameInfoEncoder; +import com.oracle.svm.core.deopt.DeoptEntryInfopoint; +import com.oracle.svm.core.deopt.DeoptTest; +import com.oracle.svm.core.graal.GraalConfiguration; +import com.oracle.svm.core.graal.code.StubCallingConvention; +import com.oracle.svm.core.graal.nodes.DeoptTestNode; +import com.oracle.svm.core.graal.snippets.DeoptTester; +import com.oracle.svm.core.graal.stackvalue.StackValueNode; +import com.oracle.svm.core.heap.RestrictHeapAccess; +import com.oracle.svm.hosted.meta.HostedMethod; +import com.oracle.svm.hosted.meta.HostedUniverse; + +import jdk.vm.ci.code.BytecodeFrame; +import jdk.vm.ci.code.DebugInfo; +import jdk.vm.ci.code.site.Call; +import jdk.vm.ci.code.site.Infopoint; +import jdk.vm.ci.code.site.InfopointReason; + +class DeoptimizationUtils { + + /** + * Inserts a call to {@link DeoptTester#deoptTest} right after FixedWithNextNode StateSplits. + * + * @param method method that is being augmented with deopt test calls + * @param graph The graph of a deoptimizable method or the corresponding deopt target method. + */ + static void insertDeoptTests(HostedMethod method, StructuredGraph graph) { + for (Node node : graph.getNodes()) { + if (node instanceof FixedWithNextNode && node instanceof StateSplit && !(node instanceof InvokeNode) && !(node instanceof ForeignCallNode) && !(node instanceof DeoptTestNode) && + !(method.isSynchronized() && node instanceof StartNode)) { + FixedWithNextNode fixedWithNext = (FixedWithNextNode) node; + FixedNode next = fixedWithNext.next(); + DeoptTestNode testNode = graph.add(new DeoptTestNode()); + fixedWithNext.setNext(null); + testNode.setNext(next); + fixedWithNext.setNext(testNode); + if (((StateSplit) node).hasSideEffect() && ((StateSplit) node).stateAfter() != null) { + testNode.setStateAfter(((StateSplit) node).stateAfter().duplicateWithVirtualState()); + } else { + testNode.setStateAfter(GraphUtil.findLastFrameState((FixedNode) node).duplicateWithVirtualState()); + } + } + } + } + + private static boolean containsStackValueNode(HostedUniverse universe, HostedMethod method) { + return universe.getBigBang().getHostVM().containsStackValueNode(method.wrapped); + } + + /** + * Returns true if a method should be considered as deoptimization source. This is only a + * feature for testing. Note that usually all image compiled methods cannot deoptimize. + */ + static boolean canDeoptForTesting(HostedUniverse universe, HostedMethod method, boolean deoptimizeAll) { + if (method.getName().equals("")) { + /* Cannot deoptimize into static initializers. */ + return false; + } + + if (method.getAnnotation(DeoptTest.class) != null) { + return true; + } + + if (method.isEntryPoint()) { + /* + * Entry points from C have special entry/exit nodes added, so they cannot be + * deoptimized. + */ + return false; + } + if (method.isNative()) { + /* + * Native methods (i.e., the stubs that actually perform the native calls) cannot be + * deoptimized. + */ + return false; + } + if (method.wrapped.isIntrinsicMethod()) { + return false; + } + if (Uninterruptible.Utils.isUninterruptible(method)) { + return false; + } + if (method.getAnnotation(RestrictHeapAccess.class) != null) { + return false; + } + if (StubCallingConvention.Utils.hasStubCallingConvention(method)) { + /* Deoptimization runtime cannot fill the callee saved registers. */ + return false; + } + if (containsStackValueNode(universe, method)) { + /* + * Stack allocated memory is not seen by the deoptimization code, i.e., it is not copied + * in case of deoptimization. Also, pointers to it can be used for arbitrary address + * arithmetic, so we would not know how to update derived pointers into stack memory + * during deoptimization. Therefore, we cannot allow methods that allocate stack memory + * for runtime compilation. To remove this limitation, we would need to change how we + * handle stack allocated memory in Graal. + */ + return false; + } + + if (deoptimizeAll) { + /* + * The DeoptimizeAll option is set. So we use all methods for deoptimization testing. + * Exclude some "runtime" methods, like the heap code, via this blacklist. Issue GR-1706 + * tracks the bug in DebugValueMap. + */ + String className = method.getDeclaringClass().getName(); + if (className.contains("/svm/core/code/CodeInfoEncoder") || + className.contains("com/oracle/svm/core/thread/JavaThreads") || + className.contains("com/oracle/svm/core/thread/PlatformThreads") || + className.contains("com/oracle/svm/core/heap/") || + className.contains("com/oracle/svm/core/genscavenge/") || + className.contains("com/oracle/svm/core/thread/VMOperationControl") || + className.contains("debug/internal/DebugValueMap") && method.getName().equals("registerTopLevel")) { + return false; + } + /* + * Method without bytecodes, e.g., methods that have a manually constructed graph, are + * usually not deoptimizable. This needs to change as soon as we want to runtime compile + * our synthetic annotation methods. + */ + if (method.getCode() == null) { + return false; + } + + return true; + } else { + return false; + } + } + + static void removeDeoptTargetOptimizations(Suites suites) { + GraalConfiguration.hostedInstance().removeDeoptTargetOptimizations(suites); + + PhaseSuite highTier = suites.getHighTier(); + highTier.removePhase(PartialEscapePhase.class); + highTier.removePhase(ReadEliminationPhase.class); + highTier.removePhase(BoxNodeOptimizationPhase.class); + PhaseSuite midTier = suites.getMidTier(); + midTier.removePhase(FloatingReadPhase.class); + PhaseSuite lowTier = suites.getLowTier(); + ListIterator> it = lowTier.findPhase(FixReadsPhase.class); + if (it != null) { + FixReadsPhase fixReads = (FixReadsPhase) it.previous(); + it.remove(); + boolean replaceInputsWithConstants = false; + it.add(new FixReadsPhase(replaceInputsWithConstants, fixReads.getSchedulePhase())); + } + } + + static void removeDeoptTargetOptimizations(LIRSuites lirSuites) { + ListIterator> it = lirSuites.getPostAllocationOptimizationStage().findPhase(RedundantMoveElimination.class); + if (it != null) { + it.remove(); + } + lirSuites.getAllocationStage().findPhaseInstance(RegisterAllocationPhase.class).setNeverSpillConstants(true); + } + + static boolean verifyDeoptTarget(HostedMethod method, StructuredGraph graph, CompilationResult result) { + Map encodedBciMap = new HashMap<>(); + + /* + * All deopt targets must have a graph. + */ + assert graph != null : "Deopt target must have a graph."; + + /* + * No deopt targets can have a StackValueNode in the graph. + */ + assert graph.getNodes(StackValueNode.TYPE).isEmpty() : "No stack value nodes must be present in deopt target."; + + for (Infopoint infopoint : result.getInfopoints()) { + if (infopoint.debugInfo != null) { + DebugInfo debugInfo = infopoint.debugInfo; + if (!debugInfo.hasFrame()) { + continue; + } + BytecodeFrame topFrame = debugInfo.frame(); + + BytecodeFrame rootFrame = topFrame; + while (rootFrame.caller() != null) { + rootFrame = rootFrame.caller(); + } + assert rootFrame.getMethod().equals(method); + + boolean isDeoptEntry = method.compilationInfo.isDeoptEntry(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException); + if (infopoint instanceof DeoptEntryInfopoint) { + if (!isDeoptEntry) { + System.out.println("curious"); + } + // Temp removed + // assert isDeoptEntry; + } else if (rootFrame.duringCall && isDeoptEntry) { + assert infopoint instanceof Call || isSingleSteppingInfopoint(infopoint); + } else { + continue; + } + + long encodedBci = FrameInfoEncoder.encodeBci(rootFrame.getBCI(), rootFrame.duringCall, rootFrame.rethrowException); + if (encodedBciMap.containsKey(encodedBci)) { + assert encodedBciMap.get(encodedBci).equals(rootFrame) : "duplicate encoded bci " + encodedBci + " in deopt target " + method + " with different debug info:\n\n" + rootFrame + + "\n\n" + encodedBciMap.get(encodedBci); + } + encodedBciMap.put(encodedBci, rootFrame); + } + } + + return true; + } + + static boolean canBeUsedForInlining(HostedUniverse universe, HostedMethod caller, HostedMethod callee, int bci, boolean deoptimizeAll) { + if (DeoptimizationUtils.canDeoptForTesting(universe, caller, deoptimizeAll) && Modifier.isNative(callee.getModifiers())) { + /* + * We must not deoptimize in the stubs for native functions, since they don't have a + * valid bytecode state. + */ + return false; + } + if (DeoptimizationUtils.canDeoptForTesting(universe, caller, deoptimizeAll) && DeoptimizationUtils.containsStackValueNode(universe, callee)) { + /* + * We must not inline a method that has stack values and can be deoptimized. + * + * Stack allocated memory is not seen by the deoptimization code, i.e., it is not copied + * in case of deoptimization. Also, pointers to it can be used for arbitrary address + * arithmetic, so we would not know how to update derived pointers into stack memory + * during deoptimization. Therefore, we cannot allow methods that allocate stack memory + * for runtime compilation. To remove this limitation, we would need to change how we + * handle stack allocated memory in Graal. + */ + return false; + } + + if (caller.isDeoptTarget()) { + if (caller.compilationInfo.isDeoptEntry(bci, true, false)) { + /* + * The call can be on the stack for a deoptimization, so we need an actual + * non-inlined invoke to deoptimize too. + * + * We could lift this restriction by providing an explicit deopt entry point (with + * the correct exception handling edges) in addition to the inlined method. + */ + return false; + } + if (SubstrateCompilationDirectives.singleton().isDeoptInliningExclude(callee)) { + /* + * The graphs for runtime compilation have an intrinisic for the callee, which might + * alter the behavior. Be safe and do not inline, otherwise we might optimize too + * aggressively. + * + * For example, the Truffle method CompilerDirectives.inCompiledCode is + * intrinisified to return a constant with the opposite value than returned by the + * method we would inline here, i.e., we would constant-fold away the compiled-code + * only code (which is the code we need deoptimization entry points for). + */ + return false; + } + } + + return true; + } + + private static boolean isSingleSteppingInfopoint(Infopoint infopoint) { + return infopoint.reason == InfopointReason.METHOD_START || + infopoint.reason == InfopointReason.METHOD_END || + infopoint.reason == InfopointReason.BYTECODE_POSITION; + } +} diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java index f23c0bf614e8..c002a45c3709 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/HostedReplacements.java @@ -58,7 +58,7 @@ * we need to change out all metadata objects (types, methods, fields, ...). This is easy because * the snippets are encoded anyway, so we have a single Object[] array with all objects referenced * from the snippet graphs. The object replacement is done in - * {@link CompileQueue#replaceAnalysisObjects}. + * {@link AnalysisToHostedGraphTransplanter#replaceAnalysisObjects}. */ public class HostedReplacements extends SubstrateReplacements { @@ -82,6 +82,6 @@ public void registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod origin public void encodeSnippets() { /* Copy over all snippets from the analysis replacements, changing out metadata objects. */ IdentityHashMap mapping = new IdentityHashMap<>(); - super.copyFrom(aReplacements, obj -> CompileQueue.replaceAnalysisObjects(obj, null, mapping, hUniverse)); + super.copyFrom(aReplacements, obj -> AnalysisToHostedGraphTransplanter.replaceAnalysisObjects(obj, null, mapping, hUniverse)); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfoSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateCompilationDirectives.java similarity index 97% rename from substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfoSupport.java rename to substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateCompilationDirectives.java index b0590b040c40..8cfe4c96af4c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfoSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/SubstrateCompilationDirectives.java @@ -42,7 +42,7 @@ import jdk.vm.ci.meta.ResolvedJavaMethod; @AutomaticallyRegisteredImageSingleton -public class CompilationInfoSupport { +public class SubstrateCompilationDirectives { /** * Stores the value kinds present at a deoptimization point's (deoptimization source) @@ -135,8 +135,8 @@ public DeoptSourceFrameInfo mergeStateInfo(FrameState state) { private final Map> deoptEntries = new ConcurrentHashMap<>(); private final Set deoptInliningExcludes = ConcurrentHashMap.newKeySet(); - public static CompilationInfoSupport singleton() { - return ImageSingletons.lookup(CompilationInfoSupport.class); + public static SubstrateCompilationDirectives singleton() { + return ImageSingletons.lookup(SubstrateCompilationDirectives.class); } public void registerForcedCompilation(ResolvedJavaMethod method) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java index f5772b12d8a1..e4bd9a171d36 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageCodeCache.java @@ -84,8 +84,8 @@ import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.code.CompilationInfo; -import com.oracle.svm.hosted.code.CompilationInfoSupport; -import com.oracle.svm.hosted.code.CompilationInfoSupport.DeoptSourceFrameInfo; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives; +import com.oracle.svm.hosted.code.SubstrateCompilationDirectives.DeoptSourceFrameInfo; import com.oracle.svm.hosted.code.HostedImageHeapConstantPatch; import com.oracle.svm.hosted.image.NativeImage.NativeTextSectionImpl; import com.oracle.svm.hosted.meta.HostedField; @@ -390,7 +390,7 @@ public void buildRuntimeMetadata(CFunctionPointer firstMethod, UnsignedWord code private void verifyDeoptEntries(CodeInfo codeInfo) { boolean hasError = false; - List>> deoptEntries = new ArrayList<>(CompilationInfoSupport.singleton().getDeoptEntries().entrySet()); + List>> deoptEntries = new ArrayList<>(SubstrateCompilationDirectives.singleton().getDeoptEntries().entrySet()); deoptEntries.sort((e1, e2) -> e1.getKey().format("%H.%n(%p)").compareTo(e2.getKey().format("%H.%n(%p)"))); for (Entry> entry : deoptEntries) { @@ -614,7 +614,7 @@ protected boolean includeLocalValues(ResolvedJavaMethod method, Infopoint infopo } for (BytecodeFrame frame = topFrame; frame != null; frame = frame.caller()) { - if (CompilationInfoSupport.singleton().isFrameInformationRequired(frame.getMethod())) { + if (SubstrateCompilationDirectives.singleton().isFrameInformationRequired(frame.getMethod())) { /* * Somewhere in the inlining hierarchy is a method for which frame information * was explicitly requested. For simplicity, we output frame information for all 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 a47f663b810a..08f2d1219f0c 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 @@ -42,8 +42,8 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.results.StaticAnalysisResults; -import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.AlwaysInline; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.deopt.Deoptimizer; import com.oracle.svm.core.graal.code.StubCallingConvention; import com.oracle.svm.core.meta.MethodPointer; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java index 9d2a86725883..e28e5c8b76d7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedUniverse.java @@ -66,7 +66,6 @@ import com.oracle.svm.hosted.ameta.AnalysisConstantReflectionProvider; import com.oracle.svm.hosted.analysis.Inflation; import com.oracle.svm.hosted.code.CompilationInfo; -import com.oracle.svm.hosted.code.CompileQueue; import com.oracle.svm.hosted.code.FactoryMethod; import com.oracle.svm.hosted.lambda.LambdaSubstitutionType; import com.oracle.svm.hosted.substitute.AnnotationSubstitutionProcessor; @@ -209,12 +208,13 @@ * Having a separate analysis universe and hosted universe complicates some things. For example, * {@link StructuredGraph graphs} parsed for static analysis need to be "transplanted" from the * analysis universe to the hosted universe (see code around - * {@link CompileQueue#replaceAnalysisObjects}). But the separate universes make AOT compilation - * more flexible because elements can be duplicated as necessary. For example, a method can be - * compiled with different optimization levels or for different optimization contexts. One concrete - * example are methods compiled as {@link HostedMethod#isDeoptTarget() deoptimization entry points}. - * Therefore, no code must assume a 1:1 relationship between analysis and hosted elements, but a 1:n - * relationship where there are multiple hosted elements for a single analysis element. + * {@code AnalysisToHostedGraphTransplanter#replaceAnalysisObjects}). But the separate universes + * make AOT compilation more flexible because elements can be duplicated as necessary. For example, + * a method can be compiled with different optimization levels or for different optimization + * contexts. One concrete example are methods compiled as {@link HostedMethod#isDeoptTarget() + * deoptimization entry points}. Therefore, no code must assume a 1:1 relationship between analysis + * and hosted elements, but a 1:n relationship where there are multiple hosted elements for a single + * analysis element. * * In theory, only analysis elements that are found reachable by the static analysis would need a * corresponding hosted element. But in practice, this optimization did not work: for example, 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 afc447579914..7776018635fc 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 @@ -47,7 +47,6 @@ import java.util.function.BiConsumer; import java.util.function.BooleanSupplier; -import com.oracle.svm.core.feature.InternalFeature; import org.graalvm.collections.Pair; import org.graalvm.compiler.api.replacements.SnippetReflectionProvider; import org.graalvm.compiler.nodes.ConstantNode; @@ -71,25 +70,25 @@ import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.util.GraalAccess; +import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.ParsingReason; import com.oracle.svm.core.annotate.Alias; import com.oracle.svm.core.annotate.AnnotateOriginal; import com.oracle.svm.core.annotate.Delete; -import com.oracle.svm.core.NeverInline; import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.RecomputeFieldValue.Kind; import com.oracle.svm.core.annotate.Substitute; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.config.ConfigurationValues; +import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; import com.oracle.svm.core.heap.Pod; import com.oracle.svm.core.reflect.target.ReflectionSubstitutionSupport; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.hosted.GraalObjectReplacer; -import com.oracle.svm.graal.hosted.GraalProviderObjectReplacements; -import com.oracle.svm.graal.hosted.RuntimeGraalSetup; -import com.oracle.svm.graal.hosted.SubstrateRuntimeGraalSetup; +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.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.DuringAnalysisAccessImpl; @@ -173,7 +172,7 @@ public boolean getAsBoolean() { private ClassLoader imageClassLoader; private AnalysisMetaAccess metaAccess; - private GraalObjectReplacer graalObjectReplacer; + private GraalGraphObjectReplacer graalGraphObjectReplacer; private final Set> registeredClasses = new HashSet<>(); private final Map, PossibleReplaceCandidatesSubtypeHandler> subtypeChecks = new HashMap<>(); private boolean profilingEnabled; @@ -312,15 +311,15 @@ public void duringSetup(DuringSetupAccess access) { } ImageSingletons.add(NodeClassSupport.class, new NodeClassSupport()); - if (!ImageSingletons.contains(RuntimeGraalSetup.class)) { - ImageSingletons.add(RuntimeGraalSetup.class, new SubstrateRuntimeGraalSetup()); + if (!ImageSingletons.contains(SubstrateGraalCompilerSetup.class)) { + ImageSingletons.add(SubstrateGraalCompilerSetup.class, new SubstrateGraalCompilerSetup()); } DuringSetupAccessImpl config = (DuringSetupAccessImpl) access; metaAccess = config.getMetaAccess(); - GraalProviderObjectReplacements providerReplacements = ImageSingletons.lookup(RuntimeGraalSetup.class) - .getProviderObjectReplacements(metaAccess); - graalObjectReplacer = new GraalObjectReplacer(config.getUniverse(), metaAccess, providerReplacements); + 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"); @@ -387,7 +386,7 @@ public void duringAnalysis(DuringAnalysisAccess a) { AnalysisType type = access.getMetaAccess().lookupJavaType(clazz); if (type.isInstantiated()) { - graalObjectReplacer.createType(type); + graalGraphObjectReplacer.createType(type); } } @@ -407,8 +406,8 @@ public void duringAnalysis(DuringAnalysisAccess a) { public void afterCompilation(AfterCompilationAccess access) { FeatureImpl.AfterCompilationAccessImpl config = (FeatureImpl.AfterCompilationAccessImpl) access; - graalObjectReplacer.updateSubstrateDataAfterCompilation(config.getUniverse(), config.getProviders().getConstantFieldProvider()); - graalObjectReplacer.registerImmutableObjects(access); + graalGraphObjectReplacer.updateSubstrateDataAfterCompilation(config.getUniverse(), config.getProviders().getConstantFieldProvider()); + graalGraphObjectReplacer.registerImmutableObjects(access); } @SuppressWarnings("deprecation") 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 f24c7c0ae3ca..fd70ab6c6563 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 @@ -144,8 +144,8 @@ import com.oracle.svm.core.stack.JavaStackWalker; import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; -import com.oracle.svm.graal.hosted.GraalFeature; -import com.oracle.svm.graal.hosted.GraalFeature.CallTreeNode; +import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; +import com.oracle.svm.graal.hosted.RuntimeCompilationFeature.CallTreeNode; import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.FeatureImpl.AfterAnalysisAccessImpl; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; @@ -218,10 +218,10 @@ public boolean getAsBoolean() { } private final Set blocklistMethods; - private final Set blocklistViolations; + private final Set blocklistViolations; private final Set warnMethods; - private final Set warnViolations; - private final Set neverPartOfCompilationViolations; + private final Set warnViolations; + private final Set neverPartOfCompilationViolations; Set runtimeCompiledMethods; public TruffleFeature() { @@ -253,7 +253,7 @@ public void registerInvocationPlugins(Providers providers, SnippetReflectionProv @Override public List> getRequiredFeatures() { - return Arrays.asList(GraalFeature.class, TruffleBaseFeature.class); + return Arrays.asList(RuntimeCompilationFeature.class, TruffleBaseFeature.class); } @Override @@ -313,9 +313,9 @@ private boolean handleNeverPartOfCompilation(GraphBuilderContext b, ResolvedJava if (neverPartOfCompilation.stateAfter().getMethod().getDeclaringClass().equals(targetMethod.getDeclaringClass())) { /* Ignore internal use from another method in CompilerAsserts class. */ } else { - GraalFeature.CallTreeNode callerNode = ((GraalFeature.RuntimeBytecodeParser) b).getCallTreeNode(); - GraalFeature.CallTreeNode calleeNode = new GraalFeature.CallTreeNode(targetMethod, targetMethod, callerNode, callerNode.getLevel() + 1, - GraalFeature.buildSourceReference(neverPartOfCompilation.stateAfter())); + RuntimeCompilationFeature.CallTreeNode callerNode = ((RuntimeCompilationFeature.RuntimeBytecodeParser) b).getCallTreeNode(); + RuntimeCompilationFeature.CallTreeNode calleeNode = new RuntimeCompilationFeature.CallTreeNode(targetMethod, targetMethod, callerNode, callerNode.getLevel() + 1, + RuntimeCompilationFeature.buildSourceReference(neverPartOfCompilation.stateAfter())); neverPartOfCompilationViolations.add(calleeNode); } } @@ -337,8 +337,8 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { // register thread local foreign poll as compiled otherwise the stub won't work config.registerAsRoot((AnalysisMethod) SubstrateThreadLocalHandshake.FOREIGN_POLL.findMethod(config.getMetaAccess()), true); - GraalFeature graalFeature = ImageSingletons.lookup(GraalFeature.class); - SnippetReflectionProvider snippetReflection = graalFeature.getHostedProviders().getSnippetReflection(); + RuntimeCompilationFeature runtimeCompilationFeature = ImageSingletons.lookup(RuntimeCompilationFeature.class); + SnippetReflectionProvider snippetReflection = runtimeCompilationFeature.getHostedProviders().getSnippetReflection(); SubstrateTruffleCompiler truffleCompiler = truffleRuntime.initTruffleCompiler(); truffleRuntime.initializeKnownMethods(config.getMetaAccess()); truffleRuntime.initializeHostedKnownMethods(config.getUniverse().getOriginalMetaAccess()); @@ -351,7 +351,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { if (Options.TruffleInlineDuringParsing.getValue()) { graphBuilderConfig.getPlugins().appendInlineInvokePlugin( - new TruffleParsingInlineInvokePlugin(config.getHostVM(), graalFeature.getHostedProviders().getReplacements(), + new TruffleParsingInlineInvokePlugin(config.getHostVM(), runtimeCompilationFeature.getHostedProviders().getReplacements(), graphBuilderConfig.getPlugins().getInvocationPlugins(), partialEvaluator, method -> includeCallee(method, null, null))); } @@ -370,15 +370,15 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { peProviders.getReplacements(), peProviders.getStampProvider(), snippetReflection, - graalFeature.getHostedProviders().getWordTypes(), - graalFeature.getHostedProviders().getPlatformConfigurationProvider(), - graalFeature.getHostedProviders().getMetaAccessExtensionProvider(), - graalFeature.getHostedProviders().getLoopsDataProvider()); + runtimeCompilationFeature.getHostedProviders().getWordTypes(), + runtimeCompilationFeature.getHostedProviders().getPlatformConfigurationProvider(), + runtimeCompilationFeature.getHostedProviders().getMetaAccessExtensionProvider(), + runtimeCompilationFeature.getHostedProviders().getLoopsDataProvider()); newHostedProviders.setGraphBuilderPlugins(graphBuilderConfig.getPlugins()); - graalFeature.initializeRuntimeCompilationConfiguration(newHostedProviders, graphBuilderConfig, this::includeCallee, this::deoptimizeOnException); + runtimeCompilationFeature.initializeRuntimeCompilationConfiguration(newHostedProviders, graphBuilderConfig, this::includeCallee, this::deoptimizeOnException); for (ResolvedJavaMethod method : partialEvaluator.getCompilationRootMethods()) { - graalFeature.prepareMethodForRuntimeCompilation(method, config); + runtimeCompilationFeature.prepareMethodForRuntimeCompilation(method, config); } initializeMethodBlocklist(config.getMetaAccess(), access); @@ -388,7 +388,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { * information available, otherwise SubstrateStackIntrospection cannot visit them. */ for (ResolvedJavaMethod method : truffleRuntime.getAnyFrameMethod()) { - graalFeature.requireFrameInformationForMethod(method); + runtimeCompilationFeature.requireFrameInformationForMethod(method); /* * To avoid corner case errors, we also force compilation of these methods. This only * affects builds where no Truffle language is included, because any real language makes @@ -505,11 +505,11 @@ private static void registerKnownTruffleFields(BeforeAnalysisAccessImpl config, } } - private boolean includeCallee(GraalFeature.CallTreeNode calleeNode, List implementationMethods) { + private boolean includeCallee(RuntimeCompilationFeature.CallTreeNode calleeNode, List implementationMethods) { return includeCallee(calleeNode.getImplementationMethod(), calleeNode, implementationMethods); } - private boolean includeCallee(ResolvedJavaMethod implementationMethod, GraalFeature.CallTreeNode calleeNode, List implementationMethods) { + private boolean includeCallee(ResolvedJavaMethod implementationMethod, RuntimeCompilationFeature.CallTreeNode calleeNode, List implementationMethods) { if (implementationMethod.getAnnotation(CompilerDirectives.TruffleBoundary.class) != null) { return false; } else if (!((SubstrateTruffleRuntime) Truffle.getRuntime()).isInlineable(implementationMethod)) { @@ -517,7 +517,7 @@ private boolean includeCallee(ResolvedJavaMethod implementationMethod, GraalFeat } else if (implementationMethod.getAnnotation(TruffleCallBoundary.class) != null) { return false; } else if (calleeNode != null && implementationMethods.size() > 4 && isBlocklisted(calleeNode.getTargetMethod())) { - blocklistViolations.add(new GraalFeature.CallTreeNode(calleeNode.getTargetMethod(), calleeNode.getTargetMethod(), calleeNode.getParent(), calleeNode.getLevel(), + blocklistViolations.add(new RuntimeCompilationFeature.CallTreeNode(calleeNode.getTargetMethod(), calleeNode.getTargetMethod(), calleeNode.getParent(), calleeNode.getLevel(), calleeNode.getSourceReference())); return false; } else if (isBlocklisted(implementationMethod)) { @@ -708,7 +708,7 @@ private void warnAllMethods(MetaAccessProvider metaAccess, Class clazz) { } } - private static int blocklistViolationComparator(GraalFeature.CallTreeNode n1, GraalFeature.CallTreeNode n2) { + private static int blocklistViolationComparator(RuntimeCompilationFeature.CallTreeNode n1, RuntimeCompilationFeature.CallTreeNode n2) { int result = n1.getTargetMethod().getQualifiedName().compareTo(n2.getTargetMethod().getQualifiedName()); if (result == 0) { result = n1.getSourceReference().compareTo(n2.getSourceReference()); @@ -721,16 +721,16 @@ public void beforeCompilation(BeforeCompilationAccess config) { FeatureImpl.BeforeCompilationAccessImpl access = (FeatureImpl.BeforeCompilationAccessImpl) config; boolean failBlockListViolations = Options.TruffleCheckBlockListMethods.getValue() || Options.TruffleCheckBlackListedMethods.getValue(); - boolean printBlockListViolations = GraalFeature.Options.PrintRuntimeCompileMethods.getValue() || failBlockListViolations; + boolean printBlockListViolations = RuntimeCompilationFeature.Options.PrintRuntimeCompileMethods.getValue() || failBlockListViolations; if (printBlockListViolations && blocklistViolations.size() > 0) { System.out.println(); System.out.println("=== Found " + blocklistViolations.size() + " compilation blocklist violations ==="); System.out.println(); - for (GraalFeature.CallTreeNode node : blocklistViolations) { + for (RuntimeCompilationFeature.CallTreeNode node : blocklistViolations) { System.out.println("Blocklisted method"); System.out.println(node.getImplementationMethod().format(" %H.%n(%p)")); System.out.println("called from"); - for (GraalFeature.CallTreeNode cur = node; cur != null; cur = cur.getParent()) { + for (RuntimeCompilationFeature.CallTreeNode cur = node; cur != null; cur = cur.getParent()) { System.out.println(" " + cur.getSourceReference()); } } @@ -744,11 +744,11 @@ public void beforeCompilation(BeforeCompilationAccess config) { * It is enough to print one warning message with one stack trace. Take the shortest * stack trace. */ - GraalFeature.CallTreeNode printNode = null; + RuntimeCompilationFeature.CallTreeNode printNode = null; int printLength = Integer.MAX_VALUE; - for (GraalFeature.CallTreeNode warnNode : warnViolations) { + for (RuntimeCompilationFeature.CallTreeNode warnNode : warnViolations) { int warnLength = 0; - for (GraalFeature.CallTreeNode cur = warnNode; cur != null; cur = cur.getParent()) { + for (RuntimeCompilationFeature.CallTreeNode cur = warnNode; cur != null; cur = cur.getParent()) { warnLength++; } if (warnLength < printLength) { @@ -758,18 +758,18 @@ public void beforeCompilation(BeforeCompilationAccess config) { } System.out.println("Warning: suspicious method reachable for runtime compilation: " + printNode.getImplementationMethod().format("%H.%n(%p)")); - System.out.println("Check the complete tree of reachable methods using the option " + GraalFeature.Options.PrintRuntimeCompileMethods.getDescriptor().getFieldName()); + System.out.println("Check the complete tree of reachable methods using the option " + RuntimeCompilationFeature.Options.PrintRuntimeCompileMethods.getDescriptor().getFieldName()); System.out.println("Suspicious method is called from"); - for (GraalFeature.CallTreeNode cur = printNode; cur != null; cur = cur.getParent()) { + for (RuntimeCompilationFeature.CallTreeNode cur = printNode; cur != null; cur = cur.getParent()) { System.out.println(" " + cur.getSourceReference()); } } if (neverPartOfCompilationViolations.size() > 0) { System.out.println("Error: CompilerAsserts.neverPartOfCompilation reachable for runtime compilation from " + neverPartOfCompilationViolations.size() + " places:"); - for (GraalFeature.CallTreeNode neverPartOfCompilationNode : neverPartOfCompilationViolations) { + for (RuntimeCompilationFeature.CallTreeNode neverPartOfCompilationNode : neverPartOfCompilationViolations) { System.out.println("called from"); - for (GraalFeature.CallTreeNode cur = neverPartOfCompilationNode; cur != null; cur = cur.getParent()) { + for (RuntimeCompilationFeature.CallTreeNode cur = neverPartOfCompilationNode; cur != null; cur = cur.getParent()) { System.out.println(" " + cur.getSourceReference()); } } @@ -843,7 +843,7 @@ public void afterAnalysis(AfterAnalysisAccess access) { runtimeCompiledMethods.addAll(Arrays.asList(config.getMetaAccess().lookupJavaType(CompilerDirectives.class).getDeclaredMethods())); runtimeCompiledMethods.addAll(Arrays.asList(config.getMetaAccess().lookupJavaType(CompilerAsserts.class).getDeclaredMethods())); - for (CallTreeNode runtimeCompiledMethod : ImageSingletons.lookup(GraalFeature.class).getRuntimeCompiledMethods().values()) { + for (CallTreeNode runtimeCompiledMethod : ImageSingletons.lookup(RuntimeCompilationFeature.class).getRuntimeCompiledMethods().values()) { runtimeCompiledMethods.add(runtimeCompiledMethod.getImplementationMethod()); @@ -874,7 +874,7 @@ private static void printStaticTruffleBoundaries() { HashSet foundBoundaries = new HashSet<>(); int callSiteCount = 0; int calleeCount = 0; - for (CallTreeNode node : ImageSingletons.lookup(GraalFeature.class).getRuntimeCompiledMethods().values()) { + for (CallTreeNode node : ImageSingletons.lookup(RuntimeCompilationFeature.class).getRuntimeCompiledMethods().values()) { StructuredGraph graph = node.getGraph(); for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { ResolvedJavaMethod targetMethod = callTarget.targetMethod(); diff --git a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java index 4c4ac0addc56..1a0fa267190c 100644 --- a/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java +++ b/substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/TruffleSupport.java @@ -50,7 +50,7 @@ import com.oracle.svm.core.graal.code.SubstrateBackend; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.graal.GraalSupport; -import com.oracle.svm.graal.hosted.GraalFeature; +import com.oracle.svm.graal.hosted.RuntimeCompilationFeature; import com.oracle.svm.truffle.api.SubstrateKnownTruffleTypes; import com.oracle.svm.truffle.api.SubstrateOptimizedCallTarget; import com.oracle.svm.truffle.api.SubstrateOptimizedCallTargetInstalledCode; @@ -104,10 +104,10 @@ public SubstrateTruffleCompiler createTruffleCompiler(SubstrateTruffleRuntime ru } protected static TruffleCompilerConfiguration createSubstrateTruffleCompilerConfig(SubstrateTruffleRuntime runtime, String compilerConfigurationName, Method optimizedCallTargetMethod) { - GraalFeature graalFeature = ImageSingletons.lookup(GraalFeature.class); + RuntimeCompilationFeature runtimeCompilationFeature = ImageSingletons.lookup(RuntimeCompilationFeature.class); SubstrateKnownTruffleTypes knownTruffleTypes = new SubstrateKnownTruffleTypes(GraalSupport.getRuntimeConfig().getProviders().getMetaAccess()); - SnippetReflectionProvider snippetReflectionProvider = graalFeature.getHostedProviders().getSnippetReflection(); - final GraphBuilderConfiguration.Plugins graphBuilderPlugins = graalFeature.getHostedProviders().getGraphBuilderPlugins(); + SnippetReflectionProvider snippetReflectionProvider = runtimeCompilationFeature.getHostedProviders().getSnippetReflection(); + final GraphBuilderConfiguration.Plugins graphBuilderPlugins = runtimeCompilationFeature.getHostedProviders().getGraphBuilderPlugins(); SubstrateBackend substrateBackend = GraalSupport.getRuntimeConfig().getBackendForNormalMethod(); substrateBackend.setRuntimeToRuntimeInvokeMethod(optimizedCallTargetMethod); final TruffleTierConfiguration firstTier = new TruffleTierConfiguration(new EconomyPartialEvaluatorConfiguration(), substrateBackend,