diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java index 71835389b83d..f8f0a7ea35d7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionDataBuilder.java @@ -441,7 +441,9 @@ public void registerAllDeclaredConstructorsQuery(ConfigurationCondition conditio @SuppressWarnings("try") private void registerMethods(ConfigurationCondition cnd, boolean queriedOnly, Executable[] reflectExecutables) { for (Executable reflectExecutable : reflectExecutables) { - registerMethod(cnd, queriedOnly, reflectExecutable); + try (var ignored = CausalityExport.pushCause(CausalityEvents.ReflectionRegistration.create(reflectExecutable))) { + registerMethod(cnd, queriedOnly, reflectExecutable); + } } } @@ -449,76 +451,75 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe if (SubstitutionReflectivityFilter.shouldExclude(reflectExecutable, metaAccess, universe)) { return; } - try (var ignored = CausalityExport.pushCause(CausalityEvents.ReflectionRegistration.create(reflectExecutable))) { - AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable); - AnalysisType declaringType = analysisMethod.getDeclaringClass(); - var classMethods = registeredMethods.computeIfAbsent(declaringType, t -> new ConcurrentHashMap<>()); - var shouldRegisterReachabilityHandler = classMethods.isEmpty(); - - boolean registered = false; - ConditionalRuntimeValue conditionalValue = classMethods.get(analysisMethod); + + AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable); + AnalysisType declaringType = analysisMethod.getDeclaringClass(); + var classMethods = registeredMethods.computeIfAbsent(declaringType, t -> new ConcurrentHashMap<>()); + var shouldRegisterReachabilityHandler = classMethods.isEmpty(); + + boolean registered = false; + ConditionalRuntimeValue conditionalValue = classMethods.get(analysisMethod); + if (conditionalValue == null) { + var newConditionalValue = new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectExecutable); + conditionalValue = classMethods.putIfAbsent(analysisMethod, newConditionalValue); if (conditionalValue == null) { - var newConditionalValue = new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectExecutable); - conditionalValue = classMethods.putIfAbsent(analysisMethod, newConditionalValue); - if (conditionalValue == null) { - conditionalValue = newConditionalValue; - registered = true; - } - } - if (!queriedOnly) { - /* queryOnly methods are conditioned by the type itself */ - conditionalValue.getConditions().addCondition(cnd); + conditionalValue = newConditionalValue; + registered = true; } + } + if (!queriedOnly) { + /* queryOnly methods are conditioned by the type itself */ + conditionalValue.getConditions().addCondition(cnd); + } - if (registered) { - registerTypesForMethod(analysisMethod, reflectExecutable); - Class declaringClass = declaringType.getJavaClass(); + if (registered) { + registerTypesForMethod(analysisMethod, reflectExecutable); + Class declaringClass = declaringType.getJavaClass(); + /* + * The image needs to know about subtypes shadowing methods registered for reflection to + * ensure the correctness of run-time reflection queries. + */ + if (shouldRegisterReachabilityHandler) { + analysisAccess.registerSubtypeReachabilityHandler( + (access, subType) -> universe.getBigbang() + .postTask(debug -> checkSubtypeForOverridingMethods(metaAccess.lookupJavaType(subType), registeredMethods.get(declaringType).keySet())), + declaringClass); + } else { /* - * The image needs to know about subtypes shadowing methods registered for reflection to - * ensure the correctness of run-time reflection queries. + * We need to perform the check for already reachable subtypes since the + * reachability handler was already called for them. */ - if (shouldRegisterReachabilityHandler) { - analysisAccess.registerSubtypeReachabilityHandler( - (access, subType) -> universe.getBigbang() - .postTask(debug -> checkSubtypeForOverridingMethods(metaAccess.lookupJavaType(subType), registeredMethods.get(declaringType).keySet())), - declaringClass); - } else { - /* - * We need to perform the check for already reachable subtypes since the - * reachability handler was already called for them. - */ - for (AnalysisType subtype : AnalysisUniverse.reachableSubtypes(declaringType)) { - universe.getBigbang().postTask(debug -> checkSubtypeForOverridingMethods(subtype, Collections.singleton(analysisMethod))); - } - } - - if (declaringType.isAnnotation() && !analysisMethod.isConstructor()) { - processAnnotationMethod(queriedOnly, (Method) reflectExecutable); + for (AnalysisType subtype : AnalysisUniverse.reachableSubtypes(declaringType)) { + universe.getBigbang().postTask(debug -> checkSubtypeForOverridingMethods(subtype, Collections.singleton(analysisMethod))); } + } - if (!throwMissingRegistrationErrors() && declaringClass.isRecord()) { - pendingRecordClasses.computeIfPresent(declaringClass, (clazz, unregisteredAccessors) -> { - if (unregisteredAccessors.remove(reflectExecutable) && unregisteredAccessors.isEmpty()) { - registerRecordComponents(declaringClass); - } - return unregisteredAccessors; - }); - } + if (declaringType.isAnnotation() && !analysisMethod.isConstructor()) { + processAnnotationMethod(queriedOnly, (Method) reflectExecutable); } - /* - * We need to run this even if the method has already been registered, in case it was only - * registered as queried. - */ - if (!queriedOnly) { - methodAccessors.computeIfAbsent(analysisMethod, aMethod -> { - SubstrateAccessor accessor = ImageSingletons.lookup(ReflectionFeature.class).getOrCreateAccessor(reflectExecutable); - universe.getHeapScanner().rescanObject(accessor); - return accessor; + if (!throwMissingRegistrationErrors() && declaringClass.isRecord()) { + pendingRecordClasses.computeIfPresent(declaringClass, (clazz, unregisteredAccessors) -> { + if (unregisteredAccessors.remove(reflectExecutable) && unregisteredAccessors.isEmpty()) { + registerRecordComponents(declaringClass); + } + return unregisteredAccessors; }); } } + + /* + * We need to run this even if the method has already been registered, in case it was only + * registered as queried. + */ + if (!queriedOnly) { + methodAccessors.computeIfAbsent(analysisMethod, aMethod -> { + SubstrateAccessor accessor = ImageSingletons.lookup(ReflectionFeature.class).getOrCreateAccessor(reflectExecutable); + universe.getHeapScanner().rescanObject(accessor); + return accessor; + }); + } } @Override @@ -591,7 +592,9 @@ public void registerAllDeclaredFieldsQuery(ConfigurationCondition condition, boo @SuppressWarnings("try") private void registerFields(ConfigurationCondition cnd, boolean queriedOnly, Field[] reflectFields) { for (Field reflectField : reflectFields) { - registerField(cnd, queriedOnly, reflectField); + try (var ignored = CausalityExport.pushCause(CausalityEvents.ReflectionRegistration.create(reflectField))) { + registerField(cnd, queriedOnly, reflectField); + } } } @@ -599,55 +602,54 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel if (SubstitutionReflectivityFilter.shouldExclude(reflectField, metaAccess, universe)) { return; } - try (var ignored = CausalityExport.pushCause(CausalityEvents.ReflectionRegistration.create(reflectField))) { - AnalysisField analysisField = metaAccess.lookupJavaField(reflectField); - AnalysisType declaringClass = analysisField.getDeclaringClass(); - - var classFields = registeredFields.computeIfAbsent(declaringClass, t -> new ConcurrentHashMap<>()); - boolean exists = classFields.containsKey(analysisField); - boolean shouldRegisterReachabilityHandler = classFields.isEmpty(); - var cndValue = classFields.computeIfAbsent(analysisField, f -> new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectField)); - if (!queriedOnly) { - /* queryOnly methods are conditioned by the type itself */ - cndValue.getConditions().addCondition(cnd); - } - if (!exists) { - registerTypesForField(analysisField, reflectField, true); + AnalysisField analysisField = metaAccess.lookupJavaField(reflectField); + AnalysisType declaringClass = analysisField.getDeclaringClass(); + var classFields = registeredFields.computeIfAbsent(declaringClass, t -> new ConcurrentHashMap<>()); + boolean exists = classFields.containsKey(analysisField); + boolean shouldRegisterReachabilityHandler = classFields.isEmpty(); + var cndValue = classFields.computeIfAbsent(analysisField, f -> new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectField)); + if (!queriedOnly) { + /* queryOnly methods are conditioned by the type itself */ + cndValue.getConditions().addCondition(cnd); + } + + if (!exists) { + registerTypesForField(analysisField, reflectField, true); + + /* + * The image needs to know about subtypes shadowing fields registered for reflection to + * ensure the correctness of run-time reflection queries. + */ + if (shouldRegisterReachabilityHandler) { + analysisAccess.registerSubtypeReachabilityHandler( + (access, subType) -> universe.getBigbang() + .postTask(debug -> checkSubtypeForOverridingFields(metaAccess.lookupJavaType(subType), + registeredFields.get(declaringClass).keySet())), + declaringClass.getJavaClass()); + } else { /* - * The image needs to know about subtypes shadowing fields registered for reflection to - * ensure the correctness of run-time reflection queries. + * We need to perform the check for already reachable subtypes since the + * reachability handler was already called for them. */ - if (shouldRegisterReachabilityHandler) { - analysisAccess.registerSubtypeReachabilityHandler( - (access, subType) -> universe.getBigbang() - .postTask(debug -> checkSubtypeForOverridingFields(metaAccess.lookupJavaType(subType), - registeredFields.get(declaringClass).keySet())), - declaringClass.getJavaClass()); - } else { - /* - * We need to perform the check for already reachable subtypes since the - * reachability handler was already called for them. - */ - for (AnalysisType subtype : AnalysisUniverse.reachableSubtypes(declaringClass)) { - universe.getBigbang().postTask(debug -> checkSubtypeForOverridingFields(subtype, Collections.singleton(analysisField))); - } - } - - if (declaringClass.isAnnotation()) { - processAnnotationField(cnd, reflectField); + for (AnalysisType subtype : AnalysisUniverse.reachableSubtypes(declaringClass)) { + universe.getBigbang().postTask(debug -> checkSubtypeForOverridingFields(subtype, Collections.singleton(analysisField))); } } - /* - * We need to run this even if the method has already been registered, in case it was only - * registered as queried. - */ - if (!queriedOnly) { - registerTypesForField(analysisField, reflectField, false); + if (declaringClass.isAnnotation()) { + processAnnotationField(cnd, reflectField); } } + + /* + * We need to run this even if the method has already been registered, in case it was only + * registered as queried. + */ + if (!queriedOnly) { + registerTypesForField(analysisField, reflectField, false); + } } @Override