From 5e3ab9f8aed2402ad7d30e8c93e65230ce364d45 Mon Sep 17 00:00:00 2001
From: Foivos Zakkak <fzakkak@redhat.com>
Date: Thu, 27 Apr 2023 02:19:21 +0300
Subject: [PATCH 1/2] Add opt-in link-at-build-time option to fail fast on
 NoClassDefFound

Works around #6253 till a proper JVCMI fix is available.
---
 .../com/oracle/svm/hosted/LinkAtBuildTimeSupport.java | 11 ++++++++++-
 .../svm/hosted/phases/SharedGraphBuilderPhase.java    | 11 ++++++++---
 2 files changed, 18 insertions(+), 4 deletions(-)

diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LinkAtBuildTimeSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LinkAtBuildTimeSupport.java
index 1b2344ac3c27..9d61f7cf755b 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LinkAtBuildTimeSupport.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/LinkAtBuildTimeSupport.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024, 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
@@ -51,6 +51,11 @@ static final class Options {
         @APIOption(name = "link-at-build-time-paths")//
         @Option(help = "file:doc-files/LinkAtBuildTimePathsHelp.txt")//
         public static final HostedOptionKey<AccumulatingLocatableMultiOptionValue.Strings> LinkAtBuildTimePaths = new HostedOptionKey<>(AccumulatingLocatableMultiOptionValue.Strings.build());
+
+        // FIXME: Remove once we have a proper way to handle missing classes through JVMCI (see
+        // https://github.com/oracle/graal/issues/6253)
+        @Option(help = "Fail fast in case of missing classes when linking at build time.") //
+        public static final HostedOptionKey<Boolean> LinkAtBuildTimeFailFast = new HostedOptionKey<>(false);
     }
 
     private final ClassLoaderSupport classLoaderSupport;
@@ -118,4 +123,8 @@ private String linkAtBuildTimeReason(Class<?> clazz) {
         Set<OptionOrigin> origins = (Set<OptionOrigin>) reason;
         return origins.stream().map(OptionOrigin::toString).collect(Collectors.joining(" and "));
     }
+
+    public static boolean failFast() {
+        return Options.LinkAtBuildTimeFailFast.getValue();
+    }
 }
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
index d2c35b12c883..fee5d738c5fc 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/SharedGraphBuilderPhase.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2024, 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
@@ -287,7 +287,12 @@ protected void maybeEagerlyResolve(int cpi, int bytecode) {
             try {
                 super.maybeEagerlyResolve(cpi, bytecode);
             } catch (UnresolvedElementException e) {
-                if (e.getCause() instanceof LambdaConversionException || e.getCause() instanceof LinkageError || e.getCause() instanceof IllegalAccessError) {
+                Throwable cause = e.getCause();
+                if (cause instanceof NoClassDefFoundError && linkAtBuildTime && LinkAtBuildTimeSupport.failFast()) {
+                    String message = "Error during parsing of method " + method.format("%H.%n(%P)") + ". " +
+                                    LinkAtBuildTimeSupport.singleton().errorMessageFor(method.getDeclaringClass());
+                    throw new UnresolvedElementException(message, cause);
+                } else if (cause instanceof LambdaConversionException || cause instanceof LinkageError) {
                     /*
                      * Ignore LinkageError, LambdaConversionException or IllegalAccessError if
                      * thrown from eager resolution attempt. This is usually followed by a call to
@@ -1081,7 +1086,7 @@ private Object loadConstantDynamic(int cpi, int opcode) {
                      * Therefore, we cannot just treat it as "safe at build time". The class
                      * initialization is also completely useless because the invoking class must be
                      * already initialized by the time the boostrap method is executed.
-                     * 
+                     *
                      * We replicate the implementation of the bootstrap method here without doing
                      * the class initialization.
                      */

From dc4077bab48dfb65471770c237cc0f9039d59687 Mon Sep 17 00:00:00 2001
From: Foivos Zakkak <fzakkak@redhat.com>
Date: Thu, 10 Oct 2024 15:04:03 +0300
Subject: [PATCH 2/2] Only print "Detailed message" when there is one

---
 .../graal/pointsto/constraints/UnsupportedFeatures.java     | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/constraints/UnsupportedFeatures.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/constraints/UnsupportedFeatures.java
index 61a9b54a7310..85f71121b68b 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/constraints/UnsupportedFeatures.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/constraints/UnsupportedFeatures.java
@@ -121,11 +121,13 @@ public void report(BigBang bb) {
             printStream.close();
 
             String unsupportedFeaturesMessage;
+            String output = outputStream.toString();
+            String detailedMessage = output.isEmpty() ? "" : "\nDetailed message:\n" + output;
             if (singleEntry) {
-                unsupportedFeaturesMessage = entries.get(0).message + "\nDetailed message:\n" + outputStream.toString();
+                unsupportedFeaturesMessage = entries.get(0).message + detailedMessage;
                 throw new UnsupportedFeatureException(unsupportedFeaturesMessage, entries.get(0).originalException);
             } else {
-                unsupportedFeaturesMessage = "Unsupported features in " + entries.size() + " methods" + "\nDetailed message:\n" + outputStream.toString();
+                unsupportedFeaturesMessage = "Unsupported features in " + entries.size() + " methods" + detailedMessage;
                 throw new UnsupportedFeatureException(unsupportedFeaturesMessage);
             }