Skip to content

Commit 7b72dd4

Browse files
committed
Fix preserved elements support with complete reflection types
1 parent 0e3788b commit 7b72dd4

File tree

3 files changed

+68
-39
lines changed

3 files changed

+68
-39
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/InternalReflectiveAccess.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public static InternalReflectiveAccess singleton() {
5555
public void register(AccessCondition condition, Class<?>... classes) {
5656
for (Class<?> clazz : classes) {
5757
rrsInstance.register(condition, clazz);
58-
rrsInstance.registerClassMetadata(condition, clazz);
58+
rrsInstance.registerClassMetadata(condition, clazz, false);
5959
}
6060
}
6161

@@ -89,7 +89,7 @@ public void register(AccessCondition condition, Field... fields) {
8989
public void registerForSerialization(AccessCondition condition, Class<?>... classes) {
9090
RuntimeSerializationSupport.singleton().register(condition, classes);
9191
for (Class<?> clazz : classes) {
92-
rrsInstance.registerClassMetadata(condition, clazz);
92+
rrsInstance.registerClassMetadata(condition, clazz, false);
9393
}
9494
}
9595

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
import com.oracle.graal.pointsto.meta.AnalysisMethod;
8787
import com.oracle.graal.pointsto.meta.AnalysisType;
8888
import com.oracle.graal.pointsto.meta.AnalysisUniverse;
89-
import com.oracle.svm.core.FutureDefaultsOptions;
9089
import com.oracle.svm.core.MissingRegistrationUtils;
9190
import com.oracle.svm.core.configure.ConditionalRuntimeValue;
9291
import com.oracle.svm.core.configure.RuntimeDynamicAccessMetadata;
@@ -149,12 +148,15 @@ public class ReflectionDataBuilder extends ConditionalConfigurationRegistry impl
149148
*/
150149
private final Map<Class<?>, Set<Class<?>>> innerClasses = new ConcurrentHashMap<>();
151150
private final Map<Class<?>, Integer> enabledQueriesFlags = new ConcurrentHashMap<>();
152-
private final Map<AnalysisType, Map<AnalysisField, ConditionalRuntimeValue<Field>>> registeredFields = new ConcurrentHashMap<>();
151+
private final Map<AnalysisType, Map<AnalysisField, RegisteredMemberData<Field>>> registeredFields = new ConcurrentHashMap<>();
153152
private final Set<AnalysisField> hidingFields = ConcurrentHashMap.newKeySet();
154-
private final Map<AnalysisType, Map<AnalysisMethod, ConditionalRuntimeValue<Executable>>> registeredMethods = new ConcurrentHashMap<>();
153+
private final Map<AnalysisType, Map<AnalysisMethod, RegisteredMemberData<Executable>>> registeredMethods = new ConcurrentHashMap<>();
155154
private final Map<AnalysisMethod, Object> methodAccessors = new ConcurrentHashMap<>();
156155
private final Set<AnalysisMethod> hidingMethods = ConcurrentHashMap.newKeySet();
157156

157+
private record RegisteredMemberData<T extends AnnotatedElement>(ConditionalRuntimeValue<T> member, boolean queriedOnly) {
158+
}
159+
158160
// Heap reflection data
159161
private final Set<DynamicHub> heapDynamicHubs = ConcurrentHashMap.newKeySet();
160162
private final Map<AnalysisField, Field> heapFields = new ConcurrentHashMap<>();
@@ -221,9 +223,7 @@ public void register(AccessCondition condition, boolean preserved, Class<?> claz
221223
Objects.requireNonNull(clazz, () -> nullErrorMessage("class", "reflection"));
222224
runConditionalInAnalysisTask(condition, (cnd) -> {
223225
registerClass(cnd, clazz, true, preserved);
224-
if (FutureDefaultsOptions.completeReflectionTypes()) {
225-
registerClassMetadata(cnd, clazz);
226-
}
226+
registerClassMetadata(cnd, clazz, preserved);
227227
});
228228
}
229229

@@ -245,18 +245,18 @@ public void registerAllClassesQuery(AccessCondition condition, boolean preserved
245245
});
246246
}
247247

248-
public void registerClassMetadata(AccessCondition condition, Class<?> clazz) {
249-
registerAllDeclaredFieldsQuery(condition, true, false, clazz);
250-
registerAllFieldsQuery(condition, true, false, clazz);
251-
registerAllDeclaredMethodsQuery(condition, true, false, clazz);
252-
registerAllMethodsQuery(condition, true, false, clazz);
253-
registerAllDeclaredConstructorsQuery(condition, true, false, clazz);
254-
registerAllConstructorsQuery(condition, true, false, clazz);
255-
registerAllDeclaredClassesQuery(condition, false, clazz);
256-
registerAllClassesQuery(condition, false, clazz);
248+
public void registerClassMetadata(AccessCondition condition, Class<?> clazz, boolean preserved) {
249+
registerAllDeclaredFieldsQuery(condition, true, preserved, clazz);
250+
registerAllFieldsQuery(condition, true, preserved, clazz);
251+
registerAllDeclaredMethodsQuery(condition, true, preserved, clazz);
252+
registerAllMethodsQuery(condition, true, preserved, clazz);
253+
registerAllDeclaredConstructorsQuery(condition, true, preserved, clazz);
254+
registerAllConstructorsQuery(condition, true, preserved, clazz);
255+
registerAllDeclaredClassesQuery(condition, preserved, clazz);
256+
registerAllClassesQuery(condition, preserved, clazz);
257257
registerAllRecordComponentsQuery(condition, clazz);
258-
registerAllPermittedSubclassesQuery(condition, false, clazz);
259-
registerAllNestMembersQuery(condition, false, clazz);
258+
registerAllPermittedSubclassesQuery(condition, preserved, clazz);
259+
registerAllNestMembersQuery(condition, preserved, clazz);
260260
registerAllSignersQuery(condition, clazz);
261261
}
262262

@@ -465,24 +465,30 @@ private void registerMethod(AccessCondition cnd, boolean queriedOnly, boolean pr
465465
var classMethods = registeredMethods.computeIfAbsent(declaringType, _ -> new ConcurrentHashMap<>());
466466
var shouldRegisterReachabilityHandler = classMethods.isEmpty();
467467

468-
boolean registered = false;
469-
ConditionalRuntimeValue<Executable> conditionalValue = classMethods.get(analysisMethod);
470-
if (conditionalValue == null) {
471-
var newConditionalValue = new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectExecutable);
472-
conditionalValue = classMethods.putIfAbsent(analysisMethod, newConditionalValue);
473-
if (conditionalValue == null) {
474-
conditionalValue = newConditionalValue;
475-
registered = true;
468+
boolean exists = classMethods.containsKey(analysisMethod);
469+
ConditionalRuntimeValue<Executable> conditionalValue = classMethods.compute(analysisMethod, (_, methodData) -> {
470+
boolean registeredAsQueriedOnly = methodData != null ? methodData.queriedOnly() : queriedOnly;
471+
if (methodData == null || (registeredAsQueriedOnly && !queriedOnly)) {
472+
/*
473+
* The dynamic access metadata needs to be reset when registering a queried-only
474+
* element as accessed.
475+
*/
476+
return new RegisteredMemberData<>(new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectExecutable), queriedOnly);
477+
} else {
478+
if (!preserved && registeredAsQueriedOnly == queriedOnly) {
479+
var value = methodData.member();
480+
value.getDynamicAccessMetadata().setNotPreserved();
481+
}
482+
return methodData;
476483
}
477-
} else if (!preserved) {
478-
conditionalValue.getDynamicAccessMetadata().setNotPreserved();
479-
}
484+
}).member();
485+
480486
if (!queriedOnly) {
481487
/* queryOnly methods are conditioned by the type itself */
482488
conditionalValue.getDynamicAccessMetadata().addCondition(cnd);
483489
}
484490

485-
if (registered) {
491+
if (!exists) {
486492
registerTypesForMethod(analysisMethod, reflectExecutable);
487493
Class<?> declaringClass = declaringType.getJavaClass();
488494

@@ -641,12 +647,25 @@ private void registerField(AccessCondition cnd, boolean queriedOnly, boolean pre
641647
var classFields = registeredFields.computeIfAbsent(declaringClass, _ -> new ConcurrentHashMap<>());
642648
boolean exists = classFields.containsKey(analysisField);
643649
boolean shouldRegisterReachabilityHandler = classFields.isEmpty();
644-
var cndValue = classFields.computeIfAbsent(analysisField, _ -> new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectField));
645-
if (exists) {
646-
if (!preserved) {
647-
cndValue.getDynamicAccessMetadata().setNotPreserved();
650+
651+
ConditionalRuntimeValue<Field> cndValue = classFields.compute(analysisField, (_, fieldData) -> {
652+
boolean registeredAsQueriedOnly = fieldData != null ? fieldData.queriedOnly() : queriedOnly;
653+
if (fieldData == null || (registeredAsQueriedOnly && !queriedOnly)) {
654+
/*
655+
* The dynamic access metadata needs to be reset when registering an element as
656+
* accessed
657+
*/
658+
return new RegisteredMemberData<>(new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectField), queriedOnly);
659+
} else {
660+
if (!preserved && registeredAsQueriedOnly == queriedOnly) {
661+
var value = fieldData.member();
662+
value.getDynamicAccessMetadata().setNotPreserved();
663+
}
664+
return fieldData;
648665
}
649-
} else {
666+
}).member();
667+
668+
if (!exists) {
650669
registerTypesForField(analysisField, reflectField, queriedOnly);
651670

652671
/*
@@ -1267,13 +1286,23 @@ public int getEnabledReflectionQueries(Class<?> clazz) {
12671286
@Override
12681287
public Map<AnalysisType, Map<AnalysisField, ConditionalRuntimeValue<Field>>> getReflectionFields() {
12691288
assert isSealed();
1270-
return Collections.unmodifiableMap(registeredFields);
1289+
return filterRegisteredMemberData(registeredFields);
12711290
}
12721291

12731292
@Override
12741293
public Map<AnalysisType, Map<AnalysisMethod, ConditionalRuntimeValue<Executable>>> getReflectionExecutables() {
12751294
assert isSealed();
1276-
return Collections.unmodifiableMap(registeredMethods);
1295+
return filterRegisteredMemberData(registeredMethods);
1296+
}
1297+
1298+
private static <A, R extends AnnotatedElement> Map<AnalysisType, Map<A, ConditionalRuntimeValue<R>>> filterRegisteredMemberData(Map<AnalysisType, Map<A, RegisteredMemberData<R>>> map) {
1299+
/*
1300+
* Return only the ConditionalRuntimeValue, the queriedOnly boolean is not relevant once the
1301+
* builder is sealed.
1302+
*/
1303+
return map.entrySet().stream().collect(
1304+
Collectors.toUnmodifiableMap(Map.Entry::getKey, e -> e.getValue().entrySet().stream().collect(
1305+
Collectors.toUnmodifiableMap(Map.Entry::getKey, e2 -> e2.getValue().member()))));
12771306
}
12781307

12791308
@Override

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ public void afterRegistration(AfterRegistrationAccess access) {
318318
* Querying Object members is allowed to enable these accesses on array classes, since those
319319
* don't define any additional members.
320320
*/
321-
reflectionData.registerClassMetadata(AccessCondition.unconditional(), Object.class);
321+
reflectionData.registerClassMetadata(AccessCondition.unconditional(), Object.class, false);
322322
}
323323

324324
@Override

0 commit comments

Comments
 (0)