Skip to content

Commit c0621e1

Browse files
committed
Change configuration to register only invoked methods and allow detailed configuration of included method metadata.
1 parent c19650c commit c0621e1

File tree

25 files changed

+634
-287
lines changed

25 files changed

+634
-287
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,7 @@ meth public !varargs static void register(boolean,java.lang.reflect.Field[])
904904
anno 0 java.lang.Deprecated()
905905
meth public !varargs static void register(java.lang.Class<?>[])
906906
meth public !varargs static void register(java.lang.reflect.Executable[])
907+
meth public !varargs static void registerAsQueried(java.lang.reflect.Executable[])
907908
meth public !varargs static void register(java.lang.reflect.Field[])
908909
meth public !varargs static void registerForReflectiveInstantiation(java.lang.Class<?>[])
909910
supr java.lang.Object

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/hosted/RuntimeReflection.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,19 @@ public static void register(Class<?>... classes) {
8080
* @since 19.0
8181
*/
8282
public static void register(Executable... methods) {
83-
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(ConfigurationCondition.alwaysTrue(), methods);
83+
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(ConfigurationCondition.alwaysTrue(), false, methods);
84+
}
85+
86+
/**
87+
* Makes the provided methods available for reflection queries at run time. The methods will be
88+
* returned by {@link Class#getMethod}, {@link Class#getMethods}, and all the other methods on
89+
* {@link Class} that return a single or a list of methods, but will not be invocable and will
90+
* not be considered reachable.
91+
*
92+
* @since 21.3
93+
*/
94+
public static void registerAsQueried(Executable... methods) {
95+
ImageSingletons.lookup(RuntimeReflectionSupport.class).register(ConfigurationCondition.alwaysTrue(), true, methods);
8496
}
8597

8698
/**

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/ReflectionRegistry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
public interface ReflectionRegistry {
4747
void register(ConfigurationCondition condition, Class<?>... classes);
4848

49-
void register(ConfigurationCondition condition, Executable... methods);
49+
void register(ConfigurationCondition condition, boolean queriedOnly, Executable... methods);
5050

5151
void register(ConfigurationCondition condition, boolean finalIsWritable, Field... fields);
5252

sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/impl/RuntimeReflectionSupport.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
*/
4141
package org.graalvm.nativeimage.impl;
4242

43+
import java.lang.reflect.Executable;
44+
import java.util.Set;
45+
4346
public interface RuntimeReflectionSupport extends ReflectionRegistry {
4447
// specific to java.lang.reflect reflection
48+
Set<Executable> getQueriedOnlyMethods();
4549
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

Lines changed: 135 additions & 17 deletions
Large diffs are not rendered by default.

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgent.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
121121
boolean configurationWithOrigins = false;
122122
int configWritePeriod = -1; // in seconds
123123
int configWritePeriodInitialDelay = 1; // in seconds
124+
boolean trackReflectionMetadata = true;
124125

125126
String[] tokens = !options.isEmpty() ? options.split(",") : new String[0];
126127
for (String token : tokens) {
@@ -189,6 +190,10 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
189190
build = Boolean.parseBoolean(getTokenValue(token));
190191
} else if (token.equals("experimental-configuration-with-origins")) {
191192
configurationWithOrigins = true;
193+
} else if (token.equals("track-reflection-metadata")) {
194+
trackReflectionMetadata = true;
195+
} else if (token.startsWith("track-reflection-metadata=")) {
196+
trackReflectionMetadata = Boolean.parseBoolean(getTokenValue(token));
192197
} else {
193198
return usage(1, "unknown option: '" + token + "'.");
194199
}
@@ -306,7 +311,8 @@ protected int onLoadCallback(JNIJavaVM vm, JvmtiEnv jvmti, JvmtiEventCallbacks c
306311
}
307312

308313
try {
309-
BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier, experimentalClassLoaderSupport, experimentalClassDefineSupport);
314+
BreakpointInterceptor.onLoad(jvmti, callbacks, tracer, this, interceptedStateSupplier,
315+
experimentalClassLoaderSupport, experimentalClassDefineSupport, trackReflectionMetadata);
310316
} catch (Throwable t) {
311317
return error(3, t.toString());
312318
}

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/NativeImageAgentJNIHandleSet.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {
4242

4343
final JNIMethodId javaLangReflectMemberGetName;
4444
final JNIMethodId javaLangReflectMemberGetDeclaringClass;
45+
private JNIMethodId javaLangReflectExecutableGetParameterTypes = WordFactory.nullPointer();
4546

4647
final JNIMethodId javaUtilEnumerationHasMoreElements;
4748

@@ -52,6 +53,8 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {
5253

5354
final JNIMethodId javaLangObjectGetClass;
5455

56+
final JNIObjectHandle javaLangStackOverflowError;
57+
5558
private JNIMethodId javaLangInvokeMethodTypeParameterArray = WordFactory.nullPointer();
5659
private JNIMethodId javaLangInvokeMethodTypeReturnType = WordFactory.nullPointer();
5760
final JNIObjectHandle javaLangIllegalAccessException;
@@ -94,11 +97,21 @@ public class NativeImageAgentJNIHandleSet extends JNIHandleSet {
9497
JNIObjectHandle javaLangObject = findClass(env, "java/lang/Object");
9598
javaLangObjectGetClass = getMethodId(env, javaLangObject, "getClass", "()Ljava/lang/Class;", false);
9699

100+
javaLangStackOverflowError = newClassGlobalRef(env, "java/lang/StackOverflowError");
101+
97102
javaLangIllegalAccessException = newClassGlobalRef(env, "java/lang/IllegalAccessException");
98103
javaLangInvokeWrongMethodTypeException = newClassGlobalRef(env, "java/lang/invoke/WrongMethodTypeException");
99104
javaLangIllegalArgumentException = newClassGlobalRef(env, "java/lang/IllegalArgumentException");
100105
}
101106

107+
JNIMethodId getJavaLangReflectExecutableGetParameterTypes(JNIEnvironment env) {
108+
if (javaLangReflectExecutableGetParameterTypes.isNull()) {
109+
JNIObjectHandle javaLangReflectExecutable = findClass(env, "java/lang/reflect/Executable");
110+
javaLangReflectExecutableGetParameterTypes = getMethodId(env, javaLangReflectExecutable, "getParameterTypes", "()[Ljava/lang/Class;", false);
111+
}
112+
return javaLangReflectExecutableGetParameterTypes;
113+
}
114+
102115
JNIMethodId getJavaLangInvokeMethodTypeReturnType(JNIEnvironment env) {
103116
if (javaLangInvokeMethodTypeReturnType.isNull()) {
104117
JNIObjectHandle javaLangInvokeMethodType = newClassGlobalRef(env, "java/lang/invoke/MethodType");

substratevm/src/com.oracle.svm.configure.test/src/com/oracle/svm/configure/test/config/OmitPreviousConfigTests.java

Lines changed: 37 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@
3939
import org.junit.Assert;
4040
import org.junit.Test;
4141

42-
import com.oracle.svm.configure.config.ConfigurationMemberKind;
42+
import com.oracle.svm.configure.config.ConfigurationMemberInfo;
43+
import com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberAccessibility;
44+
import com.oracle.svm.configure.config.ConfigurationMemberInfo.ConfigurationMemberDeclaration;
4345
import com.oracle.svm.configure.config.ConfigurationMethod;
4446
import com.oracle.svm.configure.config.ConfigurationSet;
4547
import com.oracle.svm.configure.config.ConfigurationType;
@@ -125,13 +127,13 @@ public void testConfigDifference() {
125127
}
126128

127129
private static void doTestGeneratedTypeConfig() {
128-
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestDeclared = new TypeMethodsWithFlagsTest(ConfigurationMemberKind.DECLARED);
130+
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestDeclared = new TypeMethodsWithFlagsTest(ConfigurationMemberDeclaration.DECLARED);
129131
typeMethodsWithFlagsTestDeclared.doTest();
130132

131-
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestPublic = new TypeMethodsWithFlagsTest(ConfigurationMemberKind.PUBLIC);
133+
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestPublic = new TypeMethodsWithFlagsTest(ConfigurationMemberDeclaration.PUBLIC);
132134
typeMethodsWithFlagsTestPublic.doTest();
133135

134-
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestDeclaredPublic = new TypeMethodsWithFlagsTest(ConfigurationMemberKind.DECLARED_AND_PUBLIC);
136+
TypeMethodsWithFlagsTest typeMethodsWithFlagsTestDeclaredPublic = new TypeMethodsWithFlagsTest(ConfigurationMemberDeclaration.DECLARED_AND_PUBLIC);
135137
typeMethodsWithFlagsTestDeclaredPublic.doTest();
136138
}
137139

@@ -152,10 +154,12 @@ private static void doTestExpectedMissingTypes(TypeConfiguration typeConfig) {
152154

153155
private static void doTestTypeFlags(TypeConfiguration typeConfig) {
154156
ConfigurationType flagTestHasDeclaredType = getConfigTypeOrFail(typeConfig, "FlagTestC");
155-
Assert.assertTrue(flagTestHasDeclaredType.haveAllDeclaredClasses() || flagTestHasDeclaredType.haveAllDeclaredFields() || flagTestHasDeclaredType.haveAllDeclaredConstructors());
157+
Assert.assertTrue(flagTestHasDeclaredType.haveAllDeclaredClasses() || flagTestHasDeclaredType.haveAllDeclaredFields() ||
158+
flagTestHasDeclaredType.getAllDeclaredConstructors() == ConfigurationMemberAccessibility.ACCESSED);
156159

157160
ConfigurationType flagTestHasPublicType = getConfigTypeOrFail(typeConfig, "FlagTestD");
158-
Assert.assertTrue(flagTestHasPublicType.haveAllPublicClasses() || flagTestHasPublicType.haveAllPublicFields() || flagTestHasPublicType.haveAllPublicConstructors());
161+
Assert.assertTrue(flagTestHasPublicType.haveAllPublicClasses() || flagTestHasPublicType.haveAllPublicFields() ||
162+
flagTestHasPublicType.getAllPublicConstructors() == ConfigurationMemberAccessibility.ACCESSED);
159163
}
160164

161165
private static void doTestFields(TypeConfiguration typeConfig) {
@@ -226,37 +230,37 @@ class TypeMethodsWithFlagsTest {
226230
static final String INTERNAL_SIGNATURE_ONE = "([Ljava/lang/String;)V";
227231
static final String INTERNAL_SIGNATURE_TWO = "([Ljava/lang/String;Ljava/lang/String;)V";
228232

229-
final ConfigurationMemberKind methodKind;
233+
final ConfigurationMemberDeclaration methodKind;
230234

231-
final Map<ConfigurationMethod, ConfigurationMemberKind> methodsThatMustExist = new HashMap<>();
232-
final Map<ConfigurationMethod, ConfigurationMemberKind> methodsThatMustNotExist = new HashMap<>();
235+
final Map<ConfigurationMethod, ConfigurationMemberDeclaration> methodsThatMustExist = new HashMap<>();
236+
final Map<ConfigurationMethod, ConfigurationMemberDeclaration> methodsThatMustNotExist = new HashMap<>();
233237

234238
final TypeConfiguration previousConfig = new TypeConfiguration();
235239
final TypeConfiguration currentConfig = new TypeConfiguration();
236240

237-
TypeMethodsWithFlagsTest(ConfigurationMemberKind methodKind) {
241+
TypeMethodsWithFlagsTest(ConfigurationMemberDeclaration methodKind) {
238242
this.methodKind = methodKind;
239243
generateTestMethods();
240244
populateConfig();
241245
currentConfig.removeAll(previousConfig);
242246
}
243247

244248
void generateTestMethods() {
245-
Map<ConfigurationMethod, ConfigurationMemberKind> targetMap;
249+
Map<ConfigurationMethod, ConfigurationMemberDeclaration> targetMap;
246250

247-
targetMap = getMethodsMap(ConfigurationMemberKind.DECLARED);
248-
targetMap.put(new ConfigurationMethod("<init>", INTERNAL_SIGNATURE_ONE), ConfigurationMemberKind.DECLARED);
249-
targetMap.put(new ConfigurationMethod("testMethodDeclaredSpecificSignature", INTERNAL_SIGNATURE_ONE), ConfigurationMemberKind.DECLARED);
250-
targetMap.put(new ConfigurationMethod("testMethodDeclaredMatchesAllSignature", null), ConfigurationMemberKind.DECLARED);
251+
targetMap = getMethodsMap(ConfigurationMemberDeclaration.DECLARED);
252+
targetMap.put(new ConfigurationMethod("<init>", INTERNAL_SIGNATURE_ONE), ConfigurationMemberDeclaration.DECLARED);
253+
targetMap.put(new ConfigurationMethod("testMethodDeclaredSpecificSignature", INTERNAL_SIGNATURE_ONE), ConfigurationMemberDeclaration.DECLARED);
254+
targetMap.put(new ConfigurationMethod("testMethodDeclaredMatchesAllSignature", null), ConfigurationMemberDeclaration.DECLARED);
251255

252-
targetMap = getMethodsMap(ConfigurationMemberKind.PUBLIC);
253-
targetMap.put(new ConfigurationMethod("<init>", INTERNAL_SIGNATURE_TWO), ConfigurationMemberKind.PUBLIC);
254-
targetMap.put(new ConfigurationMethod("testMethodPublicSpecificSignature", INTERNAL_SIGNATURE_ONE), ConfigurationMemberKind.PUBLIC);
255-
targetMap.put(new ConfigurationMethod("testMethodPublicMatchesAllSignature", null), ConfigurationMemberKind.PUBLIC);
256+
targetMap = getMethodsMap(ConfigurationMemberDeclaration.PUBLIC);
257+
targetMap.put(new ConfigurationMethod("<init>", INTERNAL_SIGNATURE_TWO), ConfigurationMemberDeclaration.PUBLIC);
258+
targetMap.put(new ConfigurationMethod("testMethodPublicSpecificSignature", INTERNAL_SIGNATURE_ONE), ConfigurationMemberDeclaration.PUBLIC);
259+
targetMap.put(new ConfigurationMethod("testMethodPublicMatchesAllSignature", null), ConfigurationMemberDeclaration.PUBLIC);
256260
}
257261

258-
Map<ConfigurationMethod, ConfigurationMemberKind> getMethodsMap(ConfigurationMemberKind otherKind) {
259-
if (methodKind.equals(otherKind) || methodKind.equals(ConfigurationMemberKind.DECLARED_AND_PUBLIC)) {
262+
Map<ConfigurationMethod, ConfigurationMemberDeclaration> getMethodsMap(ConfigurationMemberDeclaration otherKind) {
263+
if (methodKind.equals(otherKind) || methodKind.equals(ConfigurationMemberDeclaration.DECLARED_AND_PUBLIC)) {
260264
return methodsThatMustNotExist;
261265
}
262266
return methodsThatMustExist;
@@ -268,26 +272,26 @@ void populateConfig() {
268272
previousConfig.add(oldType);
269273

270274
ConfigurationType newType = new ConfigurationType(ConfigurationCondition.alwaysTrue(), getTypeName());
271-
for (Map.Entry<ConfigurationMethod, ConfigurationMemberKind> methodEntry : methodsThatMustExist.entrySet()) {
275+
for (Map.Entry<ConfigurationMethod, ConfigurationMemberDeclaration> methodEntry : methodsThatMustExist.entrySet()) {
272276
newType.addMethod(methodEntry.getKey().getName(), methodEntry.getKey().getInternalSignature(), methodEntry.getValue());
273277
}
274-
for (Map.Entry<ConfigurationMethod, ConfigurationMemberKind> methodEntry : methodsThatMustNotExist.entrySet()) {
278+
for (Map.Entry<ConfigurationMethod, ConfigurationMemberDeclaration> methodEntry : methodsThatMustNotExist.entrySet()) {
275279
newType.addMethod(methodEntry.getKey().getName(), methodEntry.getKey().getInternalSignature(), methodEntry.getValue());
276280
}
277281
currentConfig.add(newType);
278282
}
279283

280284
void setFlags(ConfigurationType config) {
281-
if (methodKind.equals(ConfigurationMemberKind.DECLARED) || methodKind.equals(ConfigurationMemberKind.DECLARED_AND_PUBLIC)) {
285+
if (methodKind.equals(ConfigurationMemberDeclaration.DECLARED) || methodKind.equals(ConfigurationMemberDeclaration.DECLARED_AND_PUBLIC)) {
282286
config.setAllDeclaredClasses();
283-
config.setAllDeclaredConstructors();
284-
config.setAllDeclaredMethods();
287+
config.setAllDeclaredConstructors(ConfigurationMemberAccessibility.ACCESSED);
288+
config.setAllDeclaredMethods(ConfigurationMemberAccessibility.ACCESSED);
285289
config.setAllDeclaredFields();
286290
}
287-
if (methodKind.equals(ConfigurationMemberKind.PUBLIC) || methodKind.equals(ConfigurationMemberKind.DECLARED_AND_PUBLIC)) {
291+
if (methodKind.equals(ConfigurationMemberDeclaration.PUBLIC) || methodKind.equals(ConfigurationMemberDeclaration.DECLARED_AND_PUBLIC)) {
288292
config.setAllPublicClasses();
289-
config.setAllPublicConstructors();
290-
config.setAllPublicMethods();
293+
config.setAllPublicConstructors(ConfigurationMemberAccessibility.ACCESSED);
294+
config.setAllPublicMethods(ConfigurationMemberAccessibility.ACCESSED);
291295
config.setAllPublicFields();
292296
}
293297
}
@@ -304,13 +308,13 @@ void doTest() {
304308
} else {
305309
Assert.assertNotNull("Generated configuration type " + name + " does not exist. Has the test code changed?", configurationType);
306310

307-
for (Map.Entry<ConfigurationMethod, ConfigurationMemberKind> methodEntry : methodsThatMustExist.entrySet()) {
308-
ConfigurationMemberKind kind = configurationType.getMethodKindIfPresent(methodEntry.getKey());
311+
for (Map.Entry<ConfigurationMethod, ConfigurationMemberDeclaration> methodEntry : methodsThatMustExist.entrySet()) {
312+
ConfigurationMemberDeclaration kind = configurationType.getMethodKindIfPresent(methodEntry.getKey()).getMemberKind();
309313
Assert.assertNotNull("Method " + methodEntry.getKey() + " unexpectedly NOT found in the new configuration.", kind);
310314
Assert.assertEquals("Method " + methodEntry.getKey() + " contains a different kind than expected in the new configuration.", kind, methodEntry.getValue());
311315
}
312-
for (Map.Entry<ConfigurationMethod, ConfigurationMemberKind> methodEntry : methodsThatMustNotExist.entrySet()) {
313-
ConfigurationMemberKind kind = configurationType.getMethodKindIfPresent(methodEntry.getKey());
316+
for (Map.Entry<ConfigurationMethod, ConfigurationMemberDeclaration> methodEntry : methodsThatMustNotExist.entrySet()) {
317+
ConfigurationMemberInfo kind = configurationType.getMethodKindIfPresent(methodEntry.getKey());
314318
Assert.assertNull("Method " + methodEntry.getKey() + " unexpectedly found in the new configuration.", kind);
315319
}
316320
}

0 commit comments

Comments
 (0)