Skip to content

Commit d10978a

Browse files
committed
[GR-62940] API for dynamic-access registration based on access conditions
PullRequest: graal/20272
2 parents 82518e3 + 843fd24 commit d10978a

37 files changed

+1582
-70
lines changed

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,10 @@ meth public abstract java.nio.file.Path getImagePath()
10211021
CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$AfterRegistrationAccess
10221022
outer org.graalvm.nativeimage.hosted.Feature
10231023
intf org.graalvm.nativeimage.hosted.Feature$FeatureAccess
1024+
meth public abstract org.graalvm.nativeimage.dynamicaccess.JNIAccess getJNIAccess()
1025+
meth public abstract org.graalvm.nativeimage.dynamicaccess.ReflectiveAccess getReflectiveAccess()
1026+
meth public abstract org.graalvm.nativeimage.dynamicaccess.ResourceAccess getResourceAccess()
1027+
meth public abstract org.graalvm.nativeimage.dynamicaccess.ForeignAccess getForeignAccess()
10241028

10251029
CLSS public abstract interface static org.graalvm.nativeimage.hosted.Feature$BeforeAnalysisAccess
10261030
outer org.graalvm.nativeimage.hosted.Feature
@@ -1161,6 +1165,30 @@ meth public static void addResourceBundle(java.lang.Module,java.lang.String)
11611165
meth public static void addResourceBundle(java.lang.Module,java.lang.String,java.util.Locale[])
11621166
supr java.lang.Object
11631167

1168+
CLSS public abstract interface org.graalvm.nativeimage.dynamicaccess.ReflectiveAccess
1169+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Class<?>[])
1170+
meth public !varargs abstract void registerForUnsafeAllocation(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Class<?>[])
1171+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.reflect.Executable[])
1172+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.reflect.Field[])
1173+
meth public !varargs abstract void registerForSerialization(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Class<?>[])
1174+
meth public !varargs abstract java.lang.Class<?> registerProxy(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Class<?>[])
1175+
1176+
CLSS public abstract interface org.graalvm.nativeimage.dynamicaccess.ResourceAccess
1177+
meth public abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Module,java.lang.String)
1178+
meth public void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.String)
1179+
meth public abstract void registerResourceBundle(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.util.ResourceBundle)
1180+
1181+
CLSS public abstract interface org.graalvm.nativeimage.dynamicaccess.JNIAccess
1182+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Class<?>[])
1183+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.reflect.Executable[])
1184+
meth public !varargs abstract void register(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.reflect.Field[])
1185+
1186+
CLSS public abstract interface org.graalvm.nativeimage.dynamicaccess.ForeignAccess
1187+
meth public !varargs abstract void registerForDirectUpcall(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.invoke.MethodHandle,java.lang.Object,java.lang.Object[])
1188+
meth public !varargs abstract void registerForDowncall(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Object,java.lang.Object[])
1189+
meth public !varargs abstract void registerForUpcall(org.graalvm.nativeimage.dynamicaccess.AccessCondition,java.lang.Object,java.lang.Object[])
1190+
1191+
11641192
CLSS public final org.graalvm.nativeimage.hosted.RuntimeSerialization
11651193
meth public !varargs static void register(java.lang.Class<?>[])
11661194
meth public !varargs static void registerProxyClass(java.lang.Class<?>[])

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/dynamicaccess/AccessCondition.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,15 @@
4444

4545
/**
4646
* A condition that must be satisfied to register elements for dynamic access (i.e., reflection,
47-
* serialization, JNI access, resource access, and foreign access at run time). Conditions should be
48-
* used whenever possible to constrain unnecessary growth of the binary size.
47+
* serialization, JNI access, resource access, and foreign access at run time).
48+
* {@link AccessCondition} is used for programmatic metadata registration in conjunction with:
49+
* <ul>
50+
* <li>{@link ReflectiveAccess}</li>
51+
* <li>{@link ResourceAccess}</li>
52+
* <li>{@link JNIAccess}</li>
53+
* <li>{@link ForeignAccess}</li>
54+
* </ul>
55+
* Conditions should be used whenever possible to constrain unnecessary growth of the binary size.
4956
* <p>
5057
* There are currently two types of conditions:
5158
* <ul>
@@ -101,7 +108,7 @@ static AccessCondition unconditional() {
101108
* // ConditionalType reached (already initialized) => element access allowed
102109
* }
103110
* }
104-
*
111+
*
105112
* class SuperType {
106113
* static {
107114
* // ConditionalType reached (subtype reached) => element access allowed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.nativeimage.dynamicaccess;
42+
43+
import org.graalvm.nativeimage.hosted.Feature;
44+
45+
import java.lang.invoke.MethodHandle;
46+
import java.lang.invoke.MethodType;
47+
48+
/**
49+
* This interface is used to register classes, methods, and fields for foreign access at run time.
50+
* An instance of this interface is acquired via
51+
* {@link Feature.AfterRegistrationAccess#getForeignAccess()}.
52+
* <p>
53+
* All methods in {@link ForeignAccess} require a {@link AccessCondition} as their first parameter.
54+
* Registration for foreign access will happen only if the specified condition is satisfied.
55+
*
56+
* <h3>How to use</h3>
57+
*
58+
* {@link ForeignAccess} should only be used during {@link Feature#afterRegistration}. Any attempt
59+
* to register metadata in any other phase will result in an error.
60+
* <p>
61+
* <strong>Example:</strong>
62+
*
63+
* <pre>{@code @Override
64+
* public void afterRegistration(AfterRegistrationAccess access) {
65+
* ForeignAccess foreignAccess = access.getForeignAccess();
66+
* AccessCondition condition = AccessCondition.typeReached(ConditionType.class);
67+
* foreignAccess.registerForDowncall(condition, java.lang.foreign.ValueLayout.JAVA_INT);
68+
* }
69+
* }</pre>
70+
*
71+
* @since 25.0.1
72+
*/
73+
@SuppressWarnings("all")
74+
public interface ForeignAccess {
75+
76+
/**
77+
* Registers the provided function descriptor and options pair at image build time for downcalls
78+
* into foreign code, if the {@code condition} is satisfied. Required to get a downcall method
79+
* handle using {@link java.lang.foreign.Linker#downcallHandle} for the same descriptor and
80+
* options at run time.
81+
* <p>
82+
* Even though this method is weakly typed for compatibility reasons, run-time checks will be
83+
* performed to ensure that the arguments have the expected type. It will be deprecated in favor
84+
* of strongly typed variant as soon as possible.
85+
*
86+
* @param condition represents the condition that needs to be satisfied in order to access
87+
* target resources.
88+
* @param desc A {@link java.lang.foreign.FunctionDescriptor} to register for downcalls.
89+
* @param options An array of {@link java.lang.foreign.Linker.Option} used for the downcalls.
90+
*
91+
* @since 25.0.1
92+
*/
93+
void registerForDowncall(AccessCondition condition, Object desc, Object... options);
94+
95+
/**
96+
* Registers the provided function descriptor and options pair at image build time for upcalls
97+
* from foreign code, if the {@code condition} is satisfied. Required to get an upcall stub
98+
* function pointer using {@link java.lang.foreign.Linker#upcallStub} for the same descriptor
99+
* and options at run time.
100+
* <p>
101+
* Even though this method is weakly typed for compatibility reasons, run-time checks will be
102+
* performed to ensure that the arguments have the expected type. It will be deprecated in favor
103+
* of strongly typed variant as soon as possible.
104+
*
105+
* @param condition represents the condition that needs to be satisfied in order to access
106+
* target resources.
107+
* @param desc A {@link java.lang.foreign.FunctionDescriptor} to register for upcalls.
108+
* @param options An array of {@link java.lang.foreign.Linker.Option} used for the upcalls.
109+
*
110+
* @since 25.0.1
111+
*/
112+
void registerForUpcall(AccessCondition condition, Object desc, Object... options);
113+
114+
/**
115+
* Registers a specific static method (denoted by a method handle) as a fast upcall target, if
116+
* the {@code condition} is satisfied. This will create a specialized upcall stub that will
117+
* invoke only the specified method, which is much faster than using
118+
* {@link #registerForUpcall(AccessCondition, Object, Object...)}).
119+
* <p>
120+
* The provided method handle must be a direct method handle. Those are most commonly created
121+
* using {@link java.lang.invoke.MethodHandles.Lookup#findStatic(Class, String, MethodType)}.
122+
* However, a strict requirement is that it must be possible to create a non-empty descriptor
123+
* for the method handle using {@link MethodHandle#describeConstable()}. The denoted static
124+
* method will also be registered for reflective access since run-time code will also create a
125+
* method handle to denoted static method.
126+
* </p>
127+
* <p>
128+
* Even though this method is weakly typed for compatibility reasons, run-time checks will be
129+
* performed to ensure that the arguments have the expected type. It will be deprecated in favor
130+
* of strongly typed variant as soon as possible.
131+
* </p>
132+
*
133+
* @param condition represents the condition that needs to be satisfied in order to access
134+
* target resources.
135+
* @param target A direct method handle denoting a static method.
136+
* @param desc A {@link java.lang.foreign.FunctionDescriptor} to register for upcalls.
137+
* @param options An array of {@link java.lang.foreign.Linker.Option} used for the upcalls.
138+
*
139+
* @since 25.0.1
140+
*/
141+
void registerForDirectUpcall(AccessCondition condition, MethodHandle target, Object desc, Object... options);
142+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.nativeimage.dynamicaccess;
42+
43+
import org.graalvm.nativeimage.hosted.Feature;
44+
45+
import java.lang.reflect.Executable;
46+
import java.lang.reflect.Field;
47+
48+
/**
49+
* This interface is used to register classes, methods, and fields for JNI access at runtime. An
50+
* instance of this interface is acquired via
51+
* {@link Feature.AfterRegistrationAccess#getJNIAccess()}.
52+
* <p>
53+
* All methods in {@link JNIAccess} require a {@link AccessCondition} as their first parameter. A
54+
* class and its members will be registered for JNI access only if the specified condition is
55+
* satisfied.
56+
*
57+
* <h3>How to use</h3>
58+
*
59+
* {@link JNIAccess} should only be used during {@link Feature#afterRegistration}. Any attempt to
60+
* register metadata in any other phase will result in an error.
61+
* <p>
62+
* <strong>Example:</strong>
63+
*
64+
* <pre>{@code @Override
65+
* public void afterRegistration(AfterRegistrationAccess access) {
66+
* JNIAccess jniAccess = access.getJNIAccess();
67+
* AccessCondition condition = AccessCondition.typeReached(ConditionType.class);
68+
* jniAccess.register(condition, Foo.class);
69+
* jniAccess.register(condition, Foo.class.getMethod("method"));
70+
* jniAccess.register(condition, Foo.class.getField("field"));
71+
* }
72+
* }</pre>
73+
*
74+
* @see <a href=https://docs.oracle.com/en/java/javase/17/docs/specs/jni/functions.html>Java docs -
75+
* JNI functions</a>
76+
*
77+
* @since 25.0.1
78+
*/
79+
public interface JNIAccess {
80+
/**
81+
* Registers the provided classes for JNI access at run time, if the {@code condition} is
82+
* satisfied.
83+
*
84+
* @since 25.0.1
85+
*/
86+
void register(AccessCondition condition, Class<?>... classes);
87+
88+
/**
89+
* Registers the provided methods for JNI access at run time, if the {@code condition} is
90+
* satisfied.
91+
*
92+
* @since 25.0.1
93+
*/
94+
void register(AccessCondition condition, Executable... methods);
95+
96+
/**
97+
* Registers the provided fields for JNI access at run time, if the {@code condition} is
98+
* satisfied.
99+
*
100+
* @since 25.0.1
101+
*/
102+
void register(AccessCondition condition, Field... fields);
103+
}

0 commit comments

Comments
 (0)