Skip to content

Commit 9d301f0

Browse files
committed
Fix preserved elements support with complete reflection types
1 parent 96a968b commit 9d301f0

File tree

3 files changed

+66
-39
lines changed

3 files changed

+66
-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: 63 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,29 @@ 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+
if (methodData == null || (methodData.queriedOnly() && !queriedOnly)) {
471+
/*
472+
* The dynamic access metadata needs to be reset when registering a queried-only
473+
* element as accessed.
474+
*/
475+
return new RegisteredMemberData<>(new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectExecutable), queriedOnly);
476+
} else {
477+
if (!preserved && methodData.queriedOnly() == queriedOnly) {
478+
var value = methodData.member();
479+
value.getDynamicAccessMetadata().setNotPreserved();
480+
}
481+
return methodData;
476482
}
477-
} else if (!preserved) {
478-
conditionalValue.getDynamicAccessMetadata().setNotPreserved();
479-
}
483+
}).member();
484+
480485
if (!queriedOnly) {
481486
/* queryOnly methods are conditioned by the type itself */
482487
conditionalValue.getDynamicAccessMetadata().addCondition(cnd);
483488
}
484489

485-
if (registered) {
490+
if (!exists) {
486491
registerTypesForMethod(analysisMethod, reflectExecutable);
487492
Class<?> declaringClass = declaringType.getJavaClass();
488493

@@ -641,12 +646,24 @@ private void registerField(AccessCondition cnd, boolean queriedOnly, boolean pre
641646
var classFields = registeredFields.computeIfAbsent(declaringClass, _ -> new ConcurrentHashMap<>());
642647
boolean exists = classFields.containsKey(analysisField);
643648
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();
649+
650+
ConditionalRuntimeValue<Field> cndValue = classFields.compute(analysisField, (_, fieldData) -> {
651+
if (fieldData == null || (fieldData.queriedOnly() && !queriedOnly)) {
652+
/*
653+
* The dynamic access metadata needs to be reset when registering an element as
654+
* accessed
655+
*/
656+
return new RegisteredMemberData<>(new ConditionalRuntimeValue<>(RuntimeDynamicAccessMetadata.emptySet(preserved), reflectField), queriedOnly);
657+
} else {
658+
if (!preserved && fieldData.queriedOnly() == queriedOnly) {
659+
var value = fieldData.member();
660+
value.getDynamicAccessMetadata().setNotPreserved();
661+
}
662+
return fieldData;
648663
}
649-
} else {
664+
}).member();
665+
666+
if (!exists) {
650667
registerTypesForField(analysisField, reflectField, queriedOnly);
651668

652669
/*
@@ -1267,13 +1284,23 @@ public int getEnabledReflectionQueries(Class<?> clazz) {
12671284
@Override
12681285
public Map<AnalysisType, Map<AnalysisField, ConditionalRuntimeValue<Field>>> getReflectionFields() {
12691286
assert isSealed();
1270-
return Collections.unmodifiableMap(registeredFields);
1287+
return filterRegisteredMemberData(registeredFields);
12711288
}
12721289

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

12791306
@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)