Skip to content

Commit 448bb0e

Browse files
committed
[GR-64619] Make missing registration errors subclass LinkageError
PullRequest: graal/20677
2 parents a30b6b6 + e8eed17 commit 448bb0e

File tree

10 files changed

+111
-15
lines changed

10 files changed

+111
-15
lines changed

sdk/src/org.graalvm.nativeimage/snapshot.sigtest

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ cons public init(java.lang.Throwable)
3939
supr java.lang.Throwable
4040
hfds serialVersionUID
4141

42+
CLSS public java.lang.LinkageError
43+
cons public init()
44+
cons public init(java.lang.String)
45+
cons public init(java.lang.String,java.lang.Throwable)
46+
supr java.lang.Error
47+
hfds serialVersionUID
48+
4249
CLSS public java.lang.Exception
4350
cons protected init(java.lang.String,java.lang.Throwable,boolean,boolean)
4451
cons public init()
@@ -230,7 +237,7 @@ meth public java.lang.Class<?> getDeclaringClass()
230237
meth public java.lang.Class<?> getElementType()
231238
meth public java.lang.String getElementName()
232239
meth public java.lang.String getSignature()
233-
supr java.lang.Error
240+
supr java.lang.LinkageError
234241
hfds declaringClass,elementName,elementType,serialVersionUID,signature
235242

236243
CLSS public final org.graalvm.nativeimage.MissingReflectionRegistrationError
@@ -239,7 +246,7 @@ meth public java.lang.Class<?> getDeclaringClass()
239246
meth public java.lang.Class<?> getElementType()
240247
meth public java.lang.Class<?>[] getParameterTypes()
241248
meth public java.lang.String getElementName()
242-
supr java.lang.Error
249+
supr java.lang.LinkageError
243250
hfds declaringClass,elementName,elementType,parameterTypes,serialVersionUID
244251

245252
CLSS public abstract interface org.graalvm.nativeimage.ObjectHandle

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/MissingJNIRegistrationError.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -74,7 +74,7 @@
7474
*
7575
* @since 24.1
7676
*/
77-
public final class MissingJNIRegistrationError extends Error {
77+
public final class MissingJNIRegistrationError extends LinkageError {
7878
@Serial private static final long serialVersionUID = -8940056537864516986L;
7979

8080
private final Class<?> elementType;

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/MissingReflectionRegistrationError.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -91,7 +91,7 @@
9191
*
9292
* @since 23.0
9393
*/
94-
public final class MissingReflectionRegistrationError extends Error {
94+
public final class MissingReflectionRegistrationError extends LinkageError {
9595
@Serial private static final long serialVersionUID = 2764341882856270640L;
9696

9797
private final Class<?> elementType;

substratevm/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ This changelog summarizes major changes to GraalVM Native Image.
2626
* (GR-60208) Adds the Tracing Agent support for applications using the Foreign Function & Memory (FFM) API. The agent generates FFM configuration in _foreign-config.json_. Additionally, support for FFM configurations has been added to the `native-image-configure` tool.
2727
* (GR-64787) Enable `--install-exit-handlers` by default for executables and deprecate the option. If shared libraries were using this flag, the same functionality can be restored by using `-H:+InstallJavaExitHandlersForSharedLibrary`.
2828
* (GR-47881) Remove the total number of loaded types, fields, and methods from the build output, deprecated these metrics in the build output schema, and removed already deprecated build output metrics.
29+
* (GR-64619) Missing registration errors are now subclasses of `LinkageError`
2930

3031
## GraalVM for JDK 24 (Internal Version 24.2.0)
3132
* (GR-59717) Added `DuringSetupAccess.registerObjectReachabilityHandler` to allow registering a callback that is executed when an object of a specified type is marked as reachable during heap scanning.

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/MissingRegistrationUtils.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,10 @@
2828
import java.util.Set;
2929
import java.util.concurrent.ConcurrentHashMap;
3030
import java.util.concurrent.atomic.AtomicReference;
31+
import java.util.function.Supplier;
3132

3233
import com.oracle.svm.core.util.ExitStatus;
34+
import com.oracle.svm.core.util.VMError;
3335

3436
public final class MissingRegistrationUtils {
3537

@@ -46,7 +48,7 @@ public static SubstrateOptions.ReportingMode missingRegistrationReportingMode()
4648
private static final AtomicReference<Set<String>> seenOutputs = new AtomicReference<>(null);
4749

4850
public static void report(Error exception, StackTraceElement responsibleClass) {
49-
if (responsibleClass != null && !MissingRegistrationSupport.singleton().reportMissingRegistrationErrors(responsibleClass)) {
51+
if (missingRegistrationErrorsSuspended.get() || (responsibleClass != null && !MissingRegistrationSupport.singleton().reportMissingRegistrationErrors(responsibleClass))) {
5052
return;
5153
}
5254
switch (missingRegistrationReportingMode()) {
@@ -104,6 +106,25 @@ public static void report(Error exception, StackTraceElement responsibleClass) {
104106
}
105107
}
106108

109+
private static final ThreadLocal<Boolean> missingRegistrationErrorsSuspended = ThreadLocal.withInitial(() -> false);
110+
111+
/**
112+
* Code executing inside this function will temporarily revert to throwing JDK exceptions like
113+
* ({@code ClassNotFoundException} when encountering a situation that would normally cause a
114+
* missing registration error. This is currently required during resource bundle lookups, where
115+
* encountering an unregistered class can mean that the corresponding locale isn't included in
116+
* the image, and is not a reason to abort the lookup completely.
117+
*/
118+
public static <T> T runIgnoringMissingRegistrations(Supplier<T> callback) {
119+
VMError.guarantee(!missingRegistrationErrorsSuspended.get());
120+
try {
121+
missingRegistrationErrorsSuspended.set(true);
122+
return callback.get();
123+
} finally {
124+
missingRegistrationErrorsSuspended.set(false);
125+
}
126+
}
127+
107128
private static void printLine(StringBuilder sb, Object object) {
108129
sb.append(" ").append(object).append(System.lineSeparator());
109130
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/invoke/Target_java_lang_invoke_MemberName.java

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,16 @@
2727
import java.lang.invoke.MethodType;
2828
import java.lang.reflect.Member;
2929

30+
import org.graalvm.nativeimage.MissingReflectionRegistrationError;
31+
3032
import com.oracle.svm.core.annotate.Alias;
3133
import com.oracle.svm.core.annotate.Inject;
3234
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3335
import com.oracle.svm.core.annotate.Substitute;
3436
import com.oracle.svm.core.annotate.TargetClass;
37+
import com.oracle.svm.core.methodhandles.Target_java_lang_invoke_MethodHandleNatives;
38+
import com.oracle.svm.core.util.BasedOnJDKFile;
39+
import com.oracle.svm.core.util.VMError;
3540

3641
@TargetClass(className = "java.lang.invoke.MemberName")
3742
public final class Target_java_lang_invoke_MemberName {
@@ -81,7 +86,57 @@ public final class Target_java_lang_invoke_MemberName {
8186

8287
@SuppressWarnings("static-method")
8388
@Substitute
84-
private boolean vminfoIsConsistent() {
89+
boolean vminfoIsConsistent() {
8590
return true; /* The substitution class doesn't use the same internals as the JDK */
8691
}
92+
93+
@Alias
94+
@Override
95+
protected native Target_java_lang_invoke_MemberName clone();
96+
97+
@Alias
98+
native void ensureTypeVisible(Class<?> refc);
99+
100+
@Alias
101+
public native boolean isResolved();
102+
103+
@Alias
104+
native boolean referenceKindIsConsistent();
105+
106+
@Alias
107+
native void initResolved(boolean isResolved);
108+
}
109+
110+
@TargetClass(className = "java.lang.invoke.MemberName", innerClass = "Factory")
111+
final class Target_java_lang_invoke_MemberName_Factory {
112+
@Substitute
113+
@SuppressWarnings("static-method")
114+
@BasedOnJDKFile("https://github.com/openjdk/jdk/blob/b685ea54081fcf54a6567dddb49b63435a6e1ea4/src/java.base/share/classes/java/lang/invoke/MemberName.java#L937-L973")
115+
private Target_java_lang_invoke_MemberName resolve(byte refKind, Target_java_lang_invoke_MemberName ref, Class<?> lookupClass, int allowedModes,
116+
boolean speculativeResolve) {
117+
Target_java_lang_invoke_MemberName m = ref.clone();
118+
assert (refKind == m.getReferenceKind());
119+
try {
120+
m = Target_java_lang_invoke_MethodHandleNatives.resolve(m, lookupClass, allowedModes, speculativeResolve);
121+
if (m == null) {
122+
VMError.guarantee(speculativeResolve, "non-speculative resolution should return member name or throw");
123+
return null;
124+
}
125+
m.ensureTypeVisible(m.getDeclaringClass());
126+
m.resolution = null;
127+
} catch (ClassNotFoundException | LinkageError ex) {
128+
if (ex instanceof MissingReflectionRegistrationError e) {
129+
/* Bypass the LinkageError catch below */
130+
throw e;
131+
}
132+
VMError.guarantee(m != null, "speculative resolution should not throw");
133+
assert (!m.isResolved());
134+
m.resolution = ex;
135+
return m;
136+
}
137+
assert (m.referenceKindIsConsistent());
138+
m.initResolved(true);
139+
assert (m.vminfoIsConsistent());
140+
return m;
141+
}
87142
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/substitutions/Target_java_util_ResourceBundle.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,11 @@
2828
import java.util.ResourceBundle;
2929
import java.util.concurrent.ConcurrentHashMap;
3030
import java.util.concurrent.ConcurrentMap;
31+
import java.util.function.Supplier;
3132

3233
import org.graalvm.nativeimage.ImageSingletons;
3334

35+
import com.oracle.svm.core.MissingRegistrationUtils;
3436
import com.oracle.svm.core.annotate.Alias;
3537
import com.oracle.svm.core.annotate.RecomputeFieldValue;
3638
import com.oracle.svm.core.annotate.Substitute;
@@ -115,7 +117,12 @@ private static ResourceBundle getBundleImpl(String baseName,
115117
if (!ImageSingletons.lookup(LocalizationSupport.class).isRegisteredBundleLookup(baseName, locale, control)) {
116118
MissingResourceRegistrationUtils.missingResourceBundle(baseName);
117119
}
118-
return getBundleImpl(callerModule, callerModule, baseName, locale, control);
120+
return MissingRegistrationUtils.runIgnoringMissingRegistrations(new Supplier<ResourceBundle>() {
121+
@Override
122+
public ResourceBundle get() {
123+
return getBundleImpl(callerModule, callerModule, baseName, locale, control);
124+
}
125+
});
119126
}
120127

121128
// find resource bundles from unnamed module of given class loader
@@ -129,7 +136,12 @@ private static ResourceBundle getBundleImpl(String baseName,
129136
if (!ImageSingletons.lookup(LocalizationSupport.class).isRegisteredBundleLookup(baseName, locale, control)) {
130137
MissingResourceRegistrationUtils.missingResourceBundle(baseName);
131138
}
132-
return getBundleImpl(callerModule, unnamedModule, baseName, locale, control);
139+
return MissingRegistrationUtils.runIgnoringMissingRegistrations(new Supplier<ResourceBundle>() {
140+
@Override
141+
public ResourceBundle get() {
142+
return getBundleImpl(callerModule, unnamedModule, baseName, locale, control);
143+
}
144+
});
133145
}
134146

135147
@Alias

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/methodhandles/Target_java_lang_invoke_MethodHandleNatives.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
*/
6666
@SuppressWarnings("unused")
6767
@TargetClass(className = "java.lang.invoke.MethodHandleNatives")
68-
final class Target_java_lang_invoke_MethodHandleNatives {
68+
public final class Target_java_lang_invoke_MethodHandleNatives {
6969

7070
/*
7171
* MemberName native constructor. We need to resolve the actual type and flags of the member and
@@ -209,7 +209,7 @@ private static Object getMemberVMInfo(Target_java_lang_invoke_MemberName self) {
209209
static native String refKindName(byte refKind);
210210

211211
@Substitute
212-
static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class<?> caller, int lookupMode, boolean speculativeResolve)
212+
public static Target_java_lang_invoke_MemberName resolve(Target_java_lang_invoke_MemberName self, Class<?> caller, int lookupMode, boolean speculativeResolve)
213213
throws LinkageError, ClassNotFoundException {
214214
Class<?> declaringClass = self.getDeclaringClass();
215215
Target_java_lang_invoke_MemberName resolved = Util_java_lang_invoke_MethodHandleNatives.resolve(self, caller, speculativeResolve);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/serialize/MissingSerializationRegistrationError.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* The purpose of this exception is to easily discover unregistered elements and to assure that all
3535
* serialization or deserialization operations have expected behavior.
3636
*/
37-
public final class MissingSerializationRegistrationError extends Error {
37+
public final class MissingSerializationRegistrationError extends LinkageError {
3838
@Serial private static final long serialVersionUID = 2764341882856270641L;
3939
private final Class<?> culprit;
4040

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/substitute/AnnotationSubstitutionProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ private void handleAliasClass(Class<?> annotatedClass, Class<?> originalClass, T
396396
}
397397

398398
private void handleMethodInAliasClass(Executable annotatedMethod, Class<?> originalClass) {
399-
if (skipExcludedPlatform(annotatedMethod)) {
399+
if (skipExcludedPlatform(annotatedMethod) || annotatedMethod.isSynthetic()) {
400400
return;
401401
}
402402

@@ -482,7 +482,7 @@ private boolean skipExcludedPlatform(AnnotatedElement annotatedMethod) {
482482
}
483483

484484
private void handleFieldInAliasClass(Field annotatedField, Class<?> originalClass) {
485-
if (skipExcludedPlatform(annotatedField)) {
485+
if (skipExcludedPlatform(annotatedField) || annotatedField.isSynthetic()) {
486486
return;
487487
}
488488

0 commit comments

Comments
 (0)