diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/ParallelExecutionException.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/ParallelExecutionException.java index 3a4d7ea42599..f74abef431f5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/ParallelExecutionException.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/util/ParallelExecutionException.java @@ -38,6 +38,7 @@ public class ParallelExecutionException extends RuntimeException { private final List exceptions; ParallelExecutionException(List exceptions) { + super(exceptions.getFirst().getMessage()); this.exceptions = exceptions; } diff --git a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64SuitesCreatorProvider.java b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64SuitesCreatorProvider.java index 634e46e722a1..3e2cbb1b038b 100644 --- a/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64SuitesCreatorProvider.java +++ b/substratevm/src/com.oracle.svm.core.graal.aarch64/src/com/oracle/svm/core/graal/aarch64/SubstrateAArch64SuitesCreatorProvider.java @@ -32,6 +32,6 @@ public class SubstrateAArch64SuitesCreatorProvider extends SubstrateSuitesCreatorProvider { public SubstrateAArch64SuitesCreatorProvider() { super(new AArch64SubstrateSuitesCreator(getHostedCompilerConfiguration()), - new AArch64SubstrateSuitesCreator(new EconomyCompilerConfiguration())); + new AArch64SubstrateSuitesCreator(new EconomyCompilerConfiguration()), new AArch64SubstrateSuitesCreator(getFallbackCompilerConfiguration())); } } diff --git a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64SuitesCreatorProvider.java b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64SuitesCreatorProvider.java index d13ed11b4ed0..32cefd1e630f 100644 --- a/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64SuitesCreatorProvider.java +++ b/substratevm/src/com.oracle.svm.core.graal.amd64/src/com/oracle/svm/core/graal/amd64/SubstrateAMD64SuitesCreatorProvider.java @@ -31,6 +31,6 @@ public class SubstrateAMD64SuitesCreatorProvider extends SubstrateSuitesCreatorProvider { public SubstrateAMD64SuitesCreatorProvider() { super(new AMD64SubstrateSuitesCreator(getHostedCompilerConfiguration()), - new AMD64SubstrateSuitesCreator(new EconomyCompilerConfiguration())); + new AMD64SubstrateSuitesCreator(new EconomyCompilerConfiguration()), new AMD64SubstrateSuitesCreator(getFallbackCompilerConfiguration())); } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java index b6a7c7e8a903..447fff356021 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/SubstrateOptions.java @@ -1697,4 +1697,19 @@ protected void onValueUpdate(EconomicMap, Object> values, Boolean o } } }; + + @Option(help = "Fallback to economy mode in case a compilation during native image generation fails.")// + public static final HostedOptionKey EnableFallbackCompilation = new HostedOptionKey<>(false, SubstrateOptions::validateEnableFallbackCompilation); + + private static void validateEnableFallbackCompilation(HostedOptionKey optionKey) { + if (optionKey.getValue() && SubstrateOptions.useEconomyCompilerConfig()) { + throw UserError.invalidOptionValue(optionKey, true, + String.format("Combining the option %s with %s is not supported", SubstrateOptionsParser.commandArgument(SubstrateOptions.EnableFallbackCompilation, "+"), + SubstrateOptionsParser.commandArgument(SubstrateOptions.Optimize, "b"))); + } + } + + public static boolean canEnableFallbackCompilation() { + return !EnableFallbackCompilation.getValue() && !useEconomyCompilerConfig(); + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/InternalFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/InternalFeature.java index 1d0ce4195676..ff179df398b7 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/InternalFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/feature/InternalFeature.java @@ -95,8 +95,9 @@ default void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues * @param suites The Graal compilation suites to add to. * @param hosted True if registering for ahead-of-time compilation, false if registering for * runtime compilation. + * @param fallback True if registering for fallback compilation, false otherwise. */ - default void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { + default void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java index 2ef5b1c056b1..e32cb3d5da3f 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/GraalConfiguration.java @@ -124,6 +124,10 @@ public Suites createFirstTierSuites(OptionValues options, @SuppressWarnings("unu return ImageSingletons.lookup(SubstrateSuitesCreatorProvider.class).getFirstTierSuitesCreator().createSuites(options, arch); } + public Suites createFallbackSuites(OptionValues options, @SuppressWarnings("unused") boolean hosted, Architecture arch) { + return ImageSingletons.lookup(SubstrateSuitesCreatorProvider.class).getFallbackSuitesCreator().createSuites(options, arch); + } + public LIRSuites createLIRSuites(OptionValues options) { return ImageSingletons.lookup(SubstrateSuitesCreatorProvider.class).getSuitesCreator().createLIRSuites(options); } @@ -132,6 +136,10 @@ public LIRSuites createFirstTierLIRSuites(OptionValues options) { return ImageSingletons.lookup(SubstrateSuitesCreatorProvider.class).getFirstTierSuitesCreator().createLIRSuites(options); } + public LIRSuites createFallbackLIRSuites(OptionValues options) { + return ImageSingletons.lookup(SubstrateSuitesCreatorProvider.class).getFallbackSuitesCreator().createLIRSuites(options); + } + public String getCompilerConfigurationName() { return COMPILER_CONFIGURATION_NAME; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreatorProvider.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreatorProvider.java index c747af4e74b0..7a04ed9f2a0a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreatorProvider.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/code/SubstrateSuitesCreatorProvider.java @@ -25,18 +25,20 @@ */ package com.oracle.svm.core.graal.code; +import com.oracle.svm.core.SubstrateOptions; + import jdk.graal.compiler.core.phases.CommunityCompilerConfiguration; import jdk.graal.compiler.core.phases.EconomyCompilerConfiguration; import jdk.graal.compiler.phases.tiers.CompilerConfiguration; import jdk.graal.compiler.phases.tiers.SuitesCreator; -import com.oracle.svm.core.SubstrateOptions; - public class SubstrateSuitesCreatorProvider { private final SuitesCreator suitesCreator; private final SuitesCreator firstTierSuitesCreator; + private final SuitesCreator fallbackSuitesCreator; + protected static CompilerConfiguration getHostedCompilerConfiguration() { if (SubstrateOptions.useEconomyCompilerConfig()) { return new EconomyCompilerConfiguration(); @@ -45,13 +47,23 @@ protected static CompilerConfiguration getHostedCompilerConfiguration() { } } - protected SubstrateSuitesCreatorProvider(SuitesCreator suitesCreator, SuitesCreator firstTierSuitesCreator) { + protected static CompilerConfiguration getFallbackCompilerConfiguration() { + return new EconomyCompilerConfiguration(); + } + + protected SubstrateSuitesCreatorProvider(SuitesCreator suitesCreator, SuitesCreator firstTierSuitesCreator, SuitesCreator fallbackSuitesCreator) { this.suitesCreator = suitesCreator; this.firstTierSuitesCreator = firstTierSuitesCreator; + this.fallbackSuitesCreator = fallbackSuitesCreator; + } + + protected SubstrateSuitesCreatorProvider(SuitesCreator suitesCreator, SuitesCreator firstTierSuitesCreator) { + this(suitesCreator, firstTierSuitesCreator, new SubstrateSuitesCreator(getFallbackCompilerConfiguration())); } public SubstrateSuitesCreatorProvider() { - this(new SubstrateSuitesCreator(getHostedCompilerConfiguration()), new SubstrateSuitesCreator(new EconomyCompilerConfiguration())); + this(new SubstrateSuitesCreator(getHostedCompilerConfiguration()), new SubstrateSuitesCreator(new EconomyCompilerConfiguration()), + new SubstrateSuitesCreator(getFallbackCompilerConfiguration())); } public final SuitesCreator getSuitesCreator() { @@ -61,4 +73,8 @@ public final SuitesCreator getSuitesCreator() { public final SuitesCreator getFirstTierSuitesCreator() { return firstTierSuitesCreator; } + + public final SuitesCreator getFallbackSuitesCreator() { + return fallbackSuitesCreator; + } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckFeature.java index e826308f24a9..3388c695fb13 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/snippets/StackOverflowCheckFeature.java @@ -66,7 +66,7 @@ public void afterRegistration(AfterRegistrationAccess access) { } @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { /* * There is no need to have the stack overflow check in the graph throughout most of the * compilation pipeline. Inserting it before the mid-tier lowering is done for pragmatic diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueFeature.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueFeature.java index 4450027dc8c9..61c977192986 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueFeature.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/stackvalue/StackValueFeature.java @@ -49,7 +49,7 @@ @AutomaticallyRegisteredFeature public class StackValueFeature implements InternalFeature { @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { ListIterator> midTierPos = suites.getMidTier().findPhase(FrameStateAssignmentPhase.class); midTierPos.previous(); midTierPos.add(new StackValueRecursionDepthPhase()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java index 5a84c79908b6..bf7c2f0c1ea7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGenerator.java @@ -1578,7 +1578,7 @@ public static Suites createSuites(FeatureHandler featureHandler, RuntimeConfigur } else { suites = GraalConfiguration.runtimeInstance().createSuites(optionsToUse == null ? RuntimeOptionValues.singleton() : optionsToUse, hosted, ConfigurationValues.getTarget().arch); } - return modifySuites(backend, suites, featureHandler, hosted, false); + return modifySuites(backend, suites, featureHandler, hosted, false, false); } public static Suites createSuites(FeatureHandler featureHandler, RuntimeConfiguration runtimeConfig, boolean hosted) { @@ -1593,18 +1593,34 @@ public static Suites createFirstTierSuites(FeatureHandler featureHandler, Runtim } else { suites = GraalConfiguration.runtimeInstance().createFirstTierSuites(RuntimeOptionValues.singleton(), hosted, ConfigurationValues.getTarget().arch); } - return modifySuites(backend, suites, featureHandler, hosted, true); + return modifySuites(backend, suites, featureHandler, hosted, true, false); + } + + /** + * Creates a fallback set of {@link Suites} for the given environment and configuration. These + * suites contain fewer optimizations and can be used as a fallback for problematic + * compilations. + */ + public static Suites createFallbackSuites(FeatureHandler featureHandler, RuntimeConfiguration runtimeConfig, boolean hosted) { + SubstrateBackend backend = runtimeConfig.getBackendForNormalMethod(); + Suites suites; + if (hosted) { + suites = GraalConfiguration.hostedInstance().createFallbackSuites(HostedOptionValues.singleton(), hosted, ConfigurationValues.getTarget().arch); + } else { + suites = GraalConfiguration.runtimeInstance().createFallbackSuites(RuntimeOptionValues.singleton(), hosted, ConfigurationValues.getTarget().arch); + } + return modifySuites(backend, suites, featureHandler, hosted, false, true); } private static Suites modifySuites(SubstrateBackend backend, Suites suites, FeatureHandler featureHandler, - boolean hosted, boolean firstTier) { + boolean hosted, boolean firstTier, boolean fallback) { Providers runtimeCallProviders = backend.getProviders(); PhaseSuite highTier = suites.getHighTier(); PhaseSuite midTier = suites.getMidTier(); PhaseSuite lowTier = suites.getLowTier(); - final boolean economy = firstTier || SubstrateOptions.useEconomyCompilerConfig(); + final boolean economy = firstTier || fallback || SubstrateOptions.useEconomyCompilerConfig(); ListIterator> position; if (hosted) { @@ -1665,7 +1681,7 @@ private static Suites modifySuites(SubstrateBackend backend, Suites suites, Feat } } - featureHandler.forEachGraalFeature(feature -> feature.registerGraalPhases(runtimeCallProviders, suites, hosted)); + featureHandler.forEachGraalFeature(feature -> feature.registerGraalPhases(runtimeCallProviders, suites, hosted, fallback)); if (hosted && ImageBuildStatistics.Options.CollectImageBuildStatistics.getValue(HostedOptionValues.singleton())) { highTier.prependPhase(new ImageBuildStatisticsCounterPhase(ImageBuildStatistics.CheckCountLocation.BEFORE_HIGH_TIER)); @@ -1735,6 +1751,21 @@ public static LIRSuites createFirstTierLIRSuites(FeatureHandler featureHandler, return lirSuites; } + @SuppressWarnings("unused") + public static LIRSuites createFallbackLIRSuites(FeatureHandler featureHandler, Providers providers, boolean hosted) { + LIRSuites lirSuites; + if (hosted) { + lirSuites = GraalConfiguration.hostedInstance().createFallbackLIRSuites(HostedOptionValues.singleton()); + lirSuites.getFinalCodeAnalysisStage().appendPhase(new VerifyCFunctionReferenceMapsLIRPhase()); + } else { + lirSuites = GraalConfiguration.runtimeInstance().createFallbackLIRSuites(RuntimeOptionValues.singleton()); + } + + /* Add phases that just perform assertion checking. */ + assert addAssertionLIRPhases(lirSuites, hosted); + return lirSuites; + } + private static boolean addAssertionLIRPhases(LIRSuites lirSuites, boolean hosted) { if (hosted) { lirSuites.getFinalCodeAnalysisStage().appendPhase(new VerifyDeoptLIRFrameStatesPhase()); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java index 1dc6402d7135..a35453c85e52 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageGeneratorRunner.java @@ -60,6 +60,7 @@ import com.oracle.svm.core.FallbackExecutor; import com.oracle.svm.core.JavaMainWrapper; import com.oracle.svm.core.JavaMainWrapper.JavaMainSupport; +import com.oracle.svm.core.JavaVersionUtil; import com.oracle.svm.core.OS; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.option.HostedOptionKey; @@ -81,7 +82,6 @@ import com.oracle.svm.util.ReflectionUtil.ReflectionUtilError; import jdk.graal.compiler.options.OptionValues; -import com.oracle.svm.core.JavaVersionUtil; import jdk.vm.ci.aarch64.AArch64; import jdk.vm.ci.amd64.AMD64; import jdk.vm.ci.code.Architecture; @@ -587,15 +587,9 @@ private int buildImage(ImageClassLoader classLoader) { hasUserError = true; } } - if (hasUserError) { - return ExitStatus.BUILDER_ERROR.getValue(); - } - if (pee.getExceptions().size() > 1) { - System.out.println(pee.getExceptions().size() + " fatal errors detected:"); - } - for (Throwable exception : pee.getExceptions()) { - NativeImageGeneratorRunner.reportFatalError(exception); + if (!hasUserError) { + unhandledThrowable = pee; } return ExitStatus.BUILDER_ERROR.getValue(); } catch (Throwable e) { 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 96a0c6790820..c76973a53e8c 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 @@ -66,6 +66,7 @@ import com.oracle.svm.core.meta.MethodRef; import com.oracle.svm.core.meta.SubstrateMethodOffsetConstant; import com.oracle.svm.core.meta.SubstrateMethodPointerConstant; +import com.oracle.svm.core.option.SubstrateOptionsParser; import com.oracle.svm.core.util.InterruptImageBuilding; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.FeatureHandler; @@ -81,6 +82,7 @@ import com.oracle.svm.hosted.phases.ImageBuildStatisticsCounterPhase; import com.oracle.svm.hosted.phases.ImplicitAssertionsPhase; import com.oracle.svm.util.ImageBuildStatistics; +import com.oracle.svm.util.LogUtils; import jdk.graal.compiler.api.replacements.Fold; import jdk.graal.compiler.asm.Assembler; @@ -175,8 +177,12 @@ protected PhaseSuite getAfterParseSuite() { protected final MetaAccessProvider metaAccess; private Suites regularSuites = null; private Suites deoptTargetSuites = null; + private Suites fallbackSuites = null; + private Suites fallbackDeoptTargetSuites = null; private LIRSuites regularLIRSuites = null; private LIRSuites deoptTargetLIRSuites = null; + private LIRSuites fallbackLIRSuites = null; + private LIRSuites fallbackDeoptTargetLIRSuites = null; protected final FeatureHandler featureHandler; protected final GlobalMetrics metricValues = new GlobalMetrics(); @@ -189,6 +195,9 @@ protected PhaseSuite getAfterParseSuite() { private final boolean optionAOTTrivialInline = SubstrateOptions.AOTTrivialInline.getValue(); private final boolean allowFoldMethods = NativeImageOptions.AllowFoldMethods.getValue(); + private final boolean fallbackCompilation = SubstrateOptions.EnableFallbackCompilation.getValue(); + private final boolean canEnableFallbackCompilation = SubstrateOptions.canEnableFallbackCompilation(); + private final ResolvedJavaType generatedFoldInvocationPluginType; public record UnpublishedTrivialMethods(CompilationGraph unpublishedGraph, boolean newlyTrivial) { @@ -478,7 +487,8 @@ protected void checkRestrictHeapAnnotations(DebugContext debug) { } private boolean suitesNotCreated() { - return regularSuites == null && deoptTargetLIRSuites == null && regularLIRSuites == null && deoptTargetSuites == null; + return regularSuites == null && deoptTargetLIRSuites == null && fallbackSuites == null && fallbackDeoptTargetSuites == null && regularLIRSuites == null && deoptTargetSuites == null && + fallbackLIRSuites == null && fallbackDeoptTargetLIRSuites == null; } protected void createSuites() { @@ -486,9 +496,15 @@ protected void createSuites() { modifyRegularSuites(regularSuites); deoptTargetSuites = createDeoptTargetSuites(); removeDeoptTargetOptimizations(deoptTargetSuites); + fallbackSuites = createFallbackSuites(); + fallbackDeoptTargetSuites = createFallbackDeoptTargetSuites(); + removeDeoptTargetFallbackOptimizations(fallbackDeoptTargetSuites); regularLIRSuites = createLIRSuites(); deoptTargetLIRSuites = createDeoptTargetLIRSuites(); removeDeoptTargetOptimizations(deoptTargetLIRSuites); + fallbackLIRSuites = createFallbackLIRSuites(); + fallbackDeoptTargetLIRSuites = createFallbackDeoptTargetLIRSuites(); + removeDeoptTargetFallbackOptimizations(fallbackDeoptTargetLIRSuites); } protected Suites createRegularSuites() { @@ -499,6 +515,14 @@ protected Suites createDeoptTargetSuites() { return NativeImageGenerator.createSuites(featureHandler, runtimeConfig, true); } + protected Suites createFallbackSuites() { + return NativeImageGenerator.createFallbackSuites(featureHandler, runtimeConfig, true); + } + + protected Suites createFallbackDeoptTargetSuites() { + return NativeImageGenerator.createFallbackSuites(featureHandler, runtimeConfig, true); + } + protected LIRSuites createLIRSuites() { return NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), true); } @@ -507,6 +531,14 @@ protected LIRSuites createDeoptTargetLIRSuites() { return NativeImageGenerator.createLIRSuites(featureHandler, runtimeConfig.getProviders(), true); } + protected LIRSuites createFallbackLIRSuites() { + return NativeImageGenerator.createFallbackLIRSuites(featureHandler, runtimeConfig.getProviders(), true); + } + + protected LIRSuites createFallbackDeoptTargetLIRSuites() { + return NativeImageGenerator.createFallbackLIRSuites(featureHandler, runtimeConfig.getProviders(), true); + } + protected void modifyRegularSuites(@SuppressWarnings("unused") Suites suites) { } @@ -1296,15 +1328,37 @@ public CompilationResultBuilder createBuilder(CoreProviders providers, } protected final CompilationResult doCompile(DebugContext debug, final HostedMethod method, CompilationIdentifier compilationIdentifier, CompileReason reason) { - CompileFunction fun = method.compilationInfo.getCustomCompileFunction(); - if (fun == null) { - fun = this::defaultCompileFunction; + CompileFunction customFunction = method.compilationInfo.getCustomCompileFunction(); + if (customFunction != null) { + return customFunction.compile(debug, method, compilationIdentifier, reason, runtimeConfig); + } + try { + return defaultCompileFunction(debug, method, compilationIdentifier, reason, runtimeConfig, false); + } catch (RuntimeException | Error t) { + if (fallbackCompilation) { + // print a warning and fall back + LogUtils.warning("Failed to compile %s, retrying in fallback mode due to '%s'. To report the issue please consider disabling the fallback.", + method.format("%r %H.%n(%p)"), SubstrateOptionsParser.commandArgument(SubstrateOptions.EnableFallbackCompilation, "+")); + return defaultCompileFunction(debug, method, compilationIdentifier, reason, runtimeConfig, true); + } else { + // ensure error is fatal + if (canEnableFallbackCompilation) { + // fallback option can be enabled so include a hint + throw VMError.shouldNotReachHere(String.format( + "The native image process failed due to a compilation problem. As a workaround, try using the '%s' option to retry problematic compilations with fewer optimizations.", + SubstrateOptionsParser.commandArgument(SubstrateOptions.EnableFallbackCompilation, "+")), + t); + } else { + throw t; + } + + } } - return fun.compile(debug, method, compilationIdentifier, reason, runtimeConfig); } @SuppressWarnings("try") - private CompilationResult defaultCompileFunction(DebugContext debug, HostedMethod method, CompilationIdentifier compilationIdentifier, CompileReason reason, RuntimeConfiguration config) { + private CompilationResult defaultCompileFunction(DebugContext debug, HostedMethod method, CompilationIdentifier compilationIdentifier, CompileReason reason, RuntimeConfiguration config, + boolean fallback) { if (NativeImageOptions.PrintAOTCompilation.getValue()) { TTY.println(String.format("[CompileQueue] Compiling [idHash=%10d] %s Reason: %s", System.identityHashCode(method), method.format("%r %H.%n(%p)"), reason)); @@ -1347,8 +1401,25 @@ private CompilationResult defaultCompileFunction(DebugContext debug, HostedMetho method.compilationInfo.numDuringCallEntryPoints = graph.getNodes(MethodCallTargetNode.TYPE).snapshot().stream().map(MethodCallTargetNode::invoke).filter( invoke -> method.compilationInfo.isDeoptEntry(invoke.bci(), FrameState.StackState.AfterPop)).count(); - Suites suites = method.isDeoptTarget() ? deoptTargetSuites : createSuitesForRegularCompile(graph, regularSuites); - LIRSuites lirSuites = method.isDeoptTarget() ? deoptTargetLIRSuites : regularLIRSuites; + Suites suites; + LIRSuites lirSuites; + if (method.isDeoptTarget()) { + if (fallback) { + suites = fallbackDeoptTargetSuites; + lirSuites = fallbackDeoptTargetLIRSuites; + } else { + suites = deoptTargetSuites; + lirSuites = deoptTargetLIRSuites; + } + } else { + if (fallback) { + suites = fallbackSuites; + lirSuites = fallbackLIRSuites; + } else { + suites = createSuitesForRegularCompile(graph, regularSuites); + lirSuites = regularLIRSuites; + } + } CompilationResult result = backend.newCompilationResult(compilationIdentifier, method.getQualifiedName()); @@ -1440,6 +1511,14 @@ protected void removeDeoptTargetOptimizations(LIRSuites lirSuites) { DeoptimizationUtils.removeDeoptTargetOptimizations(lirSuites); } + protected void removeDeoptTargetFallbackOptimizations(Suites suites) { + DeoptimizationUtils.removeDeoptTargetFallbackOptimizations(suites); + } + + protected void removeDeoptTargetFallbackOptimizations(LIRSuites lirSuites) { + DeoptimizationUtils.removeDeoptTargetFallbackOptimizations(lirSuites); + } + protected final void ensureCompiledForMethodRefConstants(HostedMethod method, CompileReason reason, CompilationResult result) { for (DataPatch dataPatch : result.getDataPatches()) { if (dataPatch.reference instanceof ConstantReference constantRef) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java index e2f6e38b3f48..974f513fd64c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/DeoptimizationUtils.java @@ -219,21 +219,13 @@ static boolean canDeoptForTesting(HostedUniverse universe, HostedMethod method, 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())); - } + replaceFixReadsPhase(suites); } static void removeDeoptTargetOptimizations(LIRSuites lirSuites) { @@ -241,9 +233,37 @@ static void removeDeoptTargetOptimizations(LIRSuites lirSuites) { if (it != null) { it.remove(); } + setNeverSpillConstants(lirSuites); + } + + static void removeDeoptTargetFallbackOptimizations(@SuppressWarnings("unused") Suites suites) { + replaceFixReadsPhase(suites); + } + + static void removeDeoptTargetFallbackOptimizations(LIRSuites lirSuites) { + setNeverSpillConstants(lirSuites); + } + + /** + * At deoptimization entry points we need to be able to recreate the stack from the + * {@code LIRFrameState}. As constants are not part of the state, we must not spill them. See + * {@code VerifyDeoptLIRFrameStatesPhase#doState}. + */ + private static void setNeverSpillConstants(LIRSuites lirSuites) { lirSuites.getAllocationStage().findPhaseInstance(RegisterAllocationPhase.class).setNeverSpillConstants(true); } + private static void replaceFixReadsPhase(Suites suites) { + 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())); + } + } + public static boolean isDeoptEntry(HostedMethod method, CompilationResult compilation, Infopoint infopoint) { BytecodeFrame topFrame = infopoint.debugInfo.frame(); BytecodeFrame rootFrame = topFrame; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ReduceImplicitExceptionStackTraceInformationPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ReduceImplicitExceptionStackTraceInformationPhase.java index bd72185bdb76..9cd53053f373 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ReduceImplicitExceptionStackTraceInformationPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ReduceImplicitExceptionStackTraceInformationPhase.java @@ -62,8 +62,8 @@ @AutomaticallyRegisteredFeature class ReduceImplicitExceptionStackTraceInformationFeature implements InternalFeature { @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { - if (hosted && SubstrateOptions.ReduceImplicitExceptionStackTraceInformation.getValue()) { + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { + if (hosted && !fallback && SubstrateOptions.ReduceImplicitExceptionStackTraceInformation.getValue()) { /* * Add as late as possible, before the final canonicalization. A canonicalization is * necessary because this phase can make other nodes unreachable, and the canonicalizer 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 3a7d03cecdec..e2eaa77ec461 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 @@ -788,7 +788,7 @@ public void duringAnalysis(DuringAnalysisAccess a) { } @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { /* * Please keep this code in sync with the HotSpot configuration in * TruffleCommunityCompilerConfiguration. 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 6599ca8dfac2..167cc3ce1864 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 @@ -1049,7 +1049,7 @@ private static void printStaticTruffleBoundaries(CallTreeInfo treeInfo) { } @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { /* * Please keep this code in sync with the HotSpot configuration in * TruffleCommunityCompilerConfiguration. diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageDelegateFeature.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageDelegateFeature.java index 65a99f00cc7d..7913022a0e31 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageDelegateFeature.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/WebImageDelegateFeature.java @@ -164,8 +164,8 @@ public void registerLowerings(RuntimeConfiguration runtimeConfig, OptionValues o } @Override - public void registerGraalPhases(Providers providers, Suites suites, boolean hosted) { - delegate.registerGraalPhases(providers, suites, hosted); + public void registerGraalPhases(Providers providers, Suites suites, boolean hosted, boolean fallback) { + delegate.registerGraalPhases(providers, suites, hosted, fallback); } @Override diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/code/WebImageCompileQueue.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/code/WebImageCompileQueue.java index ef0fefc15084..1307ed2128bf 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/code/WebImageCompileQueue.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/code/WebImageCompileQueue.java @@ -109,6 +109,16 @@ protected Suites createDeoptTargetSuites() { return null; } + @Override + protected Suites createFallbackSuites() { + return GraalConfiguration.hostedInstance().createFallbackSuites(HostedOptionValues.singleton(), true, null); + } + + @Override + protected Suites createFallbackDeoptTargetSuites() { + return null; + } + @Override protected LIRSuites createLIRSuites() { return null; @@ -119,6 +129,16 @@ protected LIRSuites createDeoptTargetLIRSuites() { return null; } + @Override + protected LIRSuites createFallbackLIRSuites() { + return null; + } + + @Override + protected LIRSuites createFallbackDeoptTargetLIRSuites() { + return null; + } + @Override protected void modifyRegularSuites(Suites suites) { // In Web Image, no suite modifications are necessary since it uses its own phase suites. @@ -129,11 +149,21 @@ protected void removeDeoptTargetOptimizations(Suites suites) { // In Web Image, no suite modifications are necessary since it uses its own phase suites. } + @Override + protected void removeDeoptTargetFallbackOptimizations(Suites suites) { + // In Web Image, no suite modifications are necessary since it uses its own phase suites. + } + @Override protected void removeDeoptTargetOptimizations(LIRSuites lirSuites) { // In Web Image, no suite modifications are necessary since it uses its own phase suites. } + @Override + protected void removeDeoptTargetFallbackOptimizations(LIRSuites lirSuites) { + // In Web Image, no suite modifications are necessary since it uses its own phase suites. + } + /** * WebImage-specific compile task that collects compilation metrics. */ diff --git a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmLMCompileQueue.java b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmLMCompileQueue.java index 57c169ca7254..943792798442 100644 --- a/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmLMCompileQueue.java +++ b/web-image/src/com.oracle.svm.hosted.webimage/src/com/oracle/svm/hosted/webimage/wasm/WebImageWasmLMCompileQueue.java @@ -47,7 +47,7 @@ protected Suites createRegularSuites() { suites.getLowTier().replacePlaceholder(AddressLoweringPhase.class, backend.newAddressLoweringPhase(backend.getCodeCache())); - featureHandler.forEachGraalFeature(feature -> feature.registerGraalPhases(backend.getProviders(), suites, true)); + featureHandler.forEachGraalFeature(feature -> feature.registerGraalPhases(backend.getProviders(), suites, true, false)); return suites; } }