From 5e3ab9f8aed2402ad7d30e8c93e65230ce364d45 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Thu, 27 Apr 2023 02:19:21 +0300 Subject: [PATCH] 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 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 LinkAtBuildTimeFailFast = new HostedOptionKey<>(false); } private final ClassLoaderSupport classLoaderSupport; @@ -118,4 +123,8 @@ private String linkAtBuildTimeReason(Class clazz) { Set origins = (Set) 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. */