|
46 | 46 | import java.util.ListIterator; |
47 | 47 | import java.util.Locale; |
48 | 48 | import java.util.Map; |
| 49 | +import java.util.Optional; |
49 | 50 | import java.util.ServiceLoader; |
50 | 51 | import java.util.Set; |
51 | 52 | import java.util.concurrent.atomic.AtomicBoolean; |
|
167 | 168 | import com.oracle.svm.core.option.RuntimeOptionValues; |
168 | 169 | import com.oracle.svm.core.option.SubstrateOptionsParser; |
169 | 170 | import com.oracle.svm.core.snippets.SnippetRuntime; |
| 171 | +import com.oracle.svm.core.util.ExitStatus; |
170 | 172 | import com.oracle.svm.core.util.InterruptImageBuilding; |
171 | 173 | import com.oracle.svm.core.util.LayeredHostedImageHeapMapCollector; |
172 | 174 | import com.oracle.svm.core.util.LayeredImageHeapMapStore; |
@@ -568,7 +570,7 @@ protected void doRun(Map<Method, CEntryPointData> entryPoints, JavaMainSupport j |
568 | 570 |
|
569 | 571 | try (DebugContext debug = new Builder(options, new GraalDebugHandlersFactory(GraalAccess.getOriginalSnippetReflection())).build(); |
570 | 572 | DebugCloseable featureCleanup = () -> featureHandler.forEachFeature(Feature::cleanup)) { |
571 | | - setupNativeImage(options, entryPoints, javaMainSupport, harnessSubstitutions, debug); |
| 573 | + setupNativeImage(options, entryPoints, javaMainSupport, imageName, harnessSubstitutions, debug); |
572 | 574 |
|
573 | 575 | boolean returnAfterAnalysis = runPointsToAnalysis(imageName, options, debug); |
574 | 576 | if (returnAfterAnalysis) { |
@@ -923,9 +925,10 @@ protected boolean verifyAssignableTypes() { |
923 | 925 |
|
924 | 926 | @SuppressWarnings("try") |
925 | 927 | protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointData> entryPoints, JavaMainSupport javaMainSupport, |
926 | | - SubstitutionProcessor harnessSubstitutions, DebugContext debug) { |
| 928 | + String imageName, SubstitutionProcessor harnessSubstitutions, DebugContext debug) { |
927 | 929 | try (Indent ignored = debug.logAndIndent("setup native-image builder")) { |
928 | 930 | try (StopTimer ignored1 = TimerCollection.createTimerAndStart(TimerCollection.Registry.SETUP)) { |
| 931 | + installDefaultExceptionHandler(options, imageName); |
929 | 932 | SubstrateTargetDescription target = createTarget(); |
930 | 933 | ImageSingletons.add(Platform.class, loader.platform); |
931 | 934 | ImageSingletons.add(SubstrateTargetDescription.class, target); |
@@ -1121,6 +1124,30 @@ protected void setupNativeImage(OptionValues options, Map<Method, CEntryPointDat |
1121 | 1124 | } |
1122 | 1125 | } |
1123 | 1126 |
|
| 1127 | + /** |
| 1128 | + * We install a default uncaught exception handler to make sure that the image build terminates |
| 1129 | + * if an uncaught exception is encountered on <b>any</b> thread. As an unexpectedly failing |
| 1130 | + * thread could theoretically cause a deadlock if another thread was waiting for its result, we |
| 1131 | + * preventively terminate the build via {@link System#exit}. |
| 1132 | + */ |
| 1133 | + private void installDefaultExceptionHandler(OptionValues options, String imageName) { |
| 1134 | + /* |
| 1135 | + * A flag to make sure we run the reporting only once even if multiple uncaught exceptions |
| 1136 | + * are encountered. |
| 1137 | + */ |
| 1138 | + var reportStarted = new AtomicBoolean(); |
| 1139 | + Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> { |
| 1140 | + if (reportStarted.compareAndSet(false, true)) { |
| 1141 | + /* |
| 1142 | + * Call into the ProgressReporter to provide error reporting as if the throwable was |
| 1143 | + * thrown on the main thread. |
| 1144 | + */ |
| 1145 | + reporter.printEpilog(Optional.of(imageName), Optional.of(NativeImageGenerator.this), loader, NativeImageGeneratorRunner.BuildOutcome.FAILED, Optional.of(throwable), options); |
| 1146 | + System.exit(ExitStatus.BUILDER_ERROR.getValue()); |
| 1147 | + } |
| 1148 | + }); |
| 1149 | + } |
| 1150 | + |
1124 | 1151 | protected void registerEntryPointStubs(Map<Method, CEntryPointData> entryPoints) { |
1125 | 1152 | entryPoints.forEach((method, entryPointData) -> CEntryPointCallStubSupport.singleton().registerStubForMethod(method, () -> entryPointData)); |
1126 | 1153 | } |
|
0 commit comments