|
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