From a89a95f743f295cd0883c41ed4e698b2881c4981 Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Thu, 23 May 2024 18:59:26 +0200 Subject: [PATCH] Remove abstractions over different conditions --- .../core/code/RuntimeMetadataDecoderImpl.java | 9 +- .../core/configure/ConfigurationFiles.java | 3 + .../core/configure/ConfigurationParser.java | 7 +- .../ConfigurationTypeDescriptor.java | 2 +- .../NamedConfigurationTypeDescriptor.java | 10 +- .../ProxyConfigurationTypeDescriptor.java | 2 +- .../ReflectionConfigurationParser.java | 2 +- .../svm/core/configure/RuntimeCondition.java | 76 ------------- .../core/configure/RuntimeConditionSet.java | 102 +++++++++++------- .../SerializationConfigurationParser.java | 2 +- .../core/configure/TypeReachedCondition.java | 75 ------------- .../svm/core/hub/ClassForNameSupport.java | 3 +- .../reflect/proxy/DynamicProxySupport.java | 2 +- ...et_java_lang_reflect_AccessibleObject.java | 9 +- .../ClassInitializationSupport.java | 2 +- .../code/RuntimeMetadataEncoderImpl.java | 16 +-- .../config/ConfigurationParserUtils.java | 1 + .../hosted/reflect/ReflectionDataBuilder.java | 11 +- .../svm/hosted/reflect/ReflectionFeature.java | 3 - 19 files changed, 107 insertions(+), 230 deletions(-) delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeCondition.java delete mode 100644 substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/TypeReachedCondition.java diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java index 9b264865ddbf8..283428b0b9a72 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/RuntimeMetadataDecoderImpl.java @@ -33,8 +33,6 @@ import java.lang.reflect.Parameter; import java.lang.reflect.RecordComponent; import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; import java.util.function.Function; import org.graalvm.nativeimage.ImageSingletons; @@ -43,7 +41,6 @@ import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.c.NonmovableArrays; -import com.oracle.svm.core.configure.RuntimeCondition; import com.oracle.svm.core.configure.RuntimeConditionSet; import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton; import com.oracle.svm.core.hub.DynamicHub; @@ -381,11 +378,7 @@ private static Object decodeField(UnsafeArrayTypeReader buf, Class declaringC private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) { var conditionTypes = decodeArray(buf, Class.class, i -> decodeType(buf)); - Set runtimeConditions = new HashSet<>(conditionTypes.length); - for (Class conditionType : conditionTypes) { - runtimeConditions.add(RuntimeCondition.createTypeReachedCondition(conditionType)); - } - return RuntimeConditionSet.createRuntime(runtimeConditions); + return RuntimeConditionSet.createDecoded(conditionTypes); } /** diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java index 9e6d1cd313ad3..a65e0ae46da8a 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationFiles.java @@ -128,6 +128,9 @@ public static final class Options { @Option(help = "Testing flag: the typeReachable condition is treated as typeReached so the semantics of programs can change.")// public static final HostedOptionKey TreatAllTypeReachableConditionsAsTypeReached = new HostedOptionKey<>(false); + @Option(help = "Testing flag: the name is treated as type to test what happens.")// + public static final HostedOptionKey TreatAllNameEntriesAsType = new HostedOptionKey<>(false); + @Option(help = "Testing flag: the typeReached condition is always satisfied however it prints the stack traces where it would not be satisfied.")// public static final HostedOptionKey TrackUnsatisfiedTypeReachedConditions = new HostedOptionKey<>(false); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java index fd689650bb950..22bb8445c0081 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationParser.java @@ -24,6 +24,7 @@ */ package com.oracle.svm.core.configure; +import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllNameEntriesAsType; import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllTypeReachableConditionsAsTypeReached; import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHABLE_KEY; import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHED_KEY; @@ -215,7 +216,7 @@ protected UnresolvedConfigurationCondition parseCondition(EconomicMap parseTypeOrName(EconomicM if (typeObject != null) { return parseTypeContents(typeObject); } else if (name != null) { - return Optional.of(new NamedConfigurationTypeDescriptor(asString(name))); + return Optional.of(new NamedConfigurationTypeDescriptor(asString(name), TreatAllNameEntriesAsType.getValue())); } else { throw failOnSchemaError("must have type or name specified for an element"); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationTypeDescriptor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationTypeDescriptor.java index 1793ba2962012..b62249e7e57de 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationTypeDescriptor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ConfigurationTypeDescriptor.java @@ -73,5 +73,5 @@ static String checkQualifiedJavaName(String javaName) { return canonicalizeTypeName(javaName); } - boolean isType(); + boolean definedAsType(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java index 31137cae88762..56a50350b0b77 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/NamedConfigurationTypeDescriptor.java @@ -30,20 +30,20 @@ import com.oracle.svm.core.util.json.JsonWriter; -public record NamedConfigurationTypeDescriptor(String name, boolean type) implements ConfigurationTypeDescriptor { +public record NamedConfigurationTypeDescriptor(String name, boolean definedAsType) implements ConfigurationTypeDescriptor { public NamedConfigurationTypeDescriptor(String name) { this(name, false); } - public NamedConfigurationTypeDescriptor(String name, boolean type) { + public NamedConfigurationTypeDescriptor(String name, boolean definedAsType) { this.name = ConfigurationTypeDescriptor.checkQualifiedJavaName(name); - this.type = type; + this.definedAsType = definedAsType; } @Override - public boolean isType() { - return type; + public boolean definedAsType() { + return definedAsType; } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java index 72da3452124cd..25ac6a0240137 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ProxyConfigurationTypeDescriptor.java @@ -65,7 +65,7 @@ public int compareTo(ConfigurationTypeDescriptor other) { } @Override - public boolean isType() { + public boolean definedAsType() { return true; } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java index 8dcaec3870d4b..7ab9be944cc99 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/ReflectionConfigurationParser.java @@ -84,7 +84,7 @@ private void parseClass(EconomicMap data) { if (type.isEmpty()) { return; } - boolean isType = type.get().isType(); + boolean isType = type.get().definedAsType(); UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, isType); TypeResult conditionResult = conditionResolver.resolveCondition(unresolvedCondition); diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeCondition.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeCondition.java deleted file mode 100644 index e4a757cd7d156..0000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeCondition.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.core.configure; - -import java.util.Set; -import java.util.WeakHashMap; - -import org.graalvm.nativeimage.Platform; -import org.graalvm.nativeimage.Platforms; -import org.graalvm.nativeimage.impl.ConfigurationCondition; - -import com.oracle.svm.core.util.VMError; - -/** - * Represents a super-type for all metadata conditions that are checked at runtime. It is created - * from {@link ConfigurationCondition}s that represent the build-time conditions. - *

- * {@link RuntimeCondition}s can be stored into the heap or encoded into the image for space - * reduction ({@link #getTypesForEncoding()}. All conditions are cached in the - * {@link #runtimeConditionCache} to save space in the image heap and hence they must implement - * {@link Object#equals(Object)} and {@link Object#hashCode()}. {@link RuntimeCondition} is most - * often used in groups that are stored in {@link RuntimeConditionSet}. - */ -public sealed interface RuntimeCondition permits TypeReachedCondition { - - WeakHashMap runtimeConditionCache = new WeakHashMap<>(); - - static RuntimeCondition create(ConfigurationCondition cnd) { - if (cnd.isAlwaysTrue() || !cnd.isRuntimeChecked()) { - throw VMError.shouldNotReachHere("We should never create run-time conditions from conditions that are always true at build time. Condition: " + cnd); - } - return createTypeReachedCondition(cnd.getType()); - } - - static RuntimeCondition createTypeReachedCondition(Class type) { - TypeReachedCondition typeReachedCondition = new TypeReachedCondition(type); - synchronized (runtimeConditionCache) { - if (runtimeConditionCache.containsKey(typeReachedCondition)) { - return runtimeConditionCache.get(typeReachedCondition); - } else { - runtimeConditionCache.put(typeReachedCondition, typeReachedCondition); - return typeReachedCondition; - } - } - } - - /** - * @return true if the condition has been satisfied at run time. - */ - boolean isSatisfied(); - - @Platforms(Platform.HOSTED_ONLY.class) - Set> getTypesForEncoding(); -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java index 67c7b8b3a3f56..d403da2152bc2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/RuntimeConditionSet.java @@ -30,43 +30,40 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; import org.graalvm.nativeimage.Platform; import org.graalvm.nativeimage.Platforms; import org.graalvm.nativeimage.impl.ConfigurationCondition; +import com.oracle.svm.core.hub.DynamicHub; import com.oracle.svm.core.util.VMError; import com.oracle.svm.util.LogUtils; /** - * Represents a group of {@link RuntimeCondition}s that guard a value. + * Represents a group of {@link #conditions} that guard a value. The conditions are encoded *

* If any of the {@link #conditions} is satisfied then the whole set becomes also * {@link #satisfied}. {@link RuntimeConditionSet}s can be created at build time - * {@link #createHosted(ConfigurationCondition...)} and stored to the image heap, or it can be - * encoded ({@link #getTypesForEncoding()} and later decoded at run time - * ({@link #createRuntime(Set)}. The current implementation does not cache {@link #conditions}, - * although this will be implemented in the future (GR-49526) + * {@link #createHosted(ConfigurationCondition)} and stored to the image heap, or it can be encoded + * ({@link #getTypesForEncoding()} and later decoded at run time ({@link #createDecoded(Object[])}. + * The current implementation does not cache {@link #conditions}, although this will be implemented + * in the future (GR-49526) */ public class RuntimeConditionSet { - private RuntimeCondition[] conditions; + private Object[] conditions; private boolean satisfied; @Platforms(Platform.HOSTED_ONLY.class) - public static RuntimeConditionSet createHosted(ConfigurationCondition... conditions) { - var conditionSet = new RuntimeConditionSet(Set.of()); - for (ConfigurationCondition condition : conditions) { - conditionSet.addCondition(condition); - } - return conditionSet; + public static RuntimeConditionSet emptySet() { + return new RuntimeConditionSet(new Object[0]); } @Platforms(Platform.HOSTED_ONLY.class) - public static RuntimeConditionSet unmodifiableEmptySet() { - return UnmodifiableRuntimeConditionSet.UNMODIFIABLE_EMPTY_SET; + public static RuntimeConditionSet createHosted(ConfigurationCondition condition) { + var conditionSet = new RuntimeConditionSet(new Object[0]); + conditionSet.addCondition(condition); + return conditionSet; } @Platforms(Platform.HOSTED_ONLY.class) @@ -80,10 +77,10 @@ public synchronized void addCondition(ConfigurationCondition cnd) { return; } - RuntimeCondition newRuntimeCondition = RuntimeCondition.create(cnd); - Stream existingConditions = conditions == null ? Stream.empty() : Arrays.stream(conditions); - setConditions(Stream.concat(existingConditions, Stream.of(newRuntimeCondition)) - .collect(Collectors.toSet())); + Object newRuntimeCondition = createRuntimeCondition(cnd); + Set existingConditions = conditions == null ? new HashSet<>() : new HashSet<>(Arrays.asList(conditions)); + existingConditions.add(newRuntimeCondition); + setConditions(existingConditions.toArray()); } @Platforms(Platform.HOSTED_ONLY.class) @@ -92,28 +89,19 @@ public Set> getTypesForEncoding() { return Set.of(); } else { Set> types = new HashSet<>(); - for (RuntimeCondition condition : conditions) { - types.addAll(condition.getTypesForEncoding()); + for (Object condition : conditions) { + types.addAll(getTypesForEncoding(condition)); } return types; } } - public static RuntimeConditionSet createRuntime(Set conditions) { - return new RuntimeConditionSet(conditions); - } - - private RuntimeConditionSet(Set conditions) { - setConditions(conditions); + public static RuntimeConditionSet unmodifiableEmptySet() { + return UnmodifiableRuntimeConditionSet.UNMODIFIABLE_EMPTY_SET; } - private void setConditions(Set conditions) { - if (conditions.isEmpty()) { - this.conditions = null; - } else { - this.conditions = conditions.toArray(RuntimeCondition[]::new); - } - satisfied = false; + public static RuntimeConditionSet createDecoded(Object[] conditions) { + return new RuntimeConditionSet(conditions); } /** @@ -133,8 +121,8 @@ public boolean satisfied() { if (localConditions == null) { result = true; } else { - for (RuntimeCondition condition : localConditions) { - if (condition.isSatisfied()) { + for (Object condition : localConditions) { + if (isSatisfied(condition)) { conditions = null; satisfied = result = true; break; @@ -158,10 +146,46 @@ public String toString() { return conditionsString + " = " + satisfied; } + private RuntimeConditionSet(Object[] conditions) { + setConditions(conditions); + } + + private void setConditions(Object[] conditions) { + if (conditions.length == 0) { + this.conditions = null; + } else { + this.conditions = conditions; + } + satisfied = false; + } + + private static Object createRuntimeCondition(ConfigurationCondition cnd) { + if (cnd.isAlwaysTrue() || !cnd.isRuntimeChecked()) { + throw VMError.shouldNotReachHere("We should never create run-time conditions from conditions that are always true at build time. Condition: " + cnd); + } + return cnd.getType(); + } + + private static boolean isSatisfied(Object condition) { + if (condition instanceof Class typeReachedCondition) { + return DynamicHub.fromClass(typeReachedCondition).isReached(); + } else { + throw VMError.shouldNotReachHere("Only typeReached condition is supported."); + } + } + + private static Set> getTypesForEncoding(Object condition) { + if (condition instanceof Class res) { + return Set.of(res); + } else { + throw VMError.shouldNotReachHere("Only typeReached condition is supported."); + } + } + public static final class UnmodifiableRuntimeConditionSet extends RuntimeConditionSet { - private static final RuntimeConditionSet UNMODIFIABLE_EMPTY_SET = new UnmodifiableRuntimeConditionSet(Set.of()); + private static final RuntimeConditionSet UNMODIFIABLE_EMPTY_SET = new UnmodifiableRuntimeConditionSet(new Object[0]); - private UnmodifiableRuntimeConditionSet(Set conditions) { + private UnmodifiableRuntimeConditionSet(Object[] conditions) { super(conditions); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java index c987d657382e8..8ee158c14f4b0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/SerializationConfigurationParser.java @@ -105,7 +105,7 @@ private void parseSerializationDescriptorObject(EconomicMap data return; } - UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, targetSerializationClass.get().isType()); + UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, targetSerializationClass.get().definedAsType()); var condition = conditionResolver.resolveCondition(unresolvedCondition); if (!condition.isPresent()) { return; diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/TypeReachedCondition.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/TypeReachedCondition.java deleted file mode 100644 index 2242db7ec4364..0000000000000 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/configure/TypeReachedCondition.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.oracle.svm.core.configure; - -import java.util.Objects; -import java.util.Set; - -import com.oracle.svm.core.hub.DynamicHub; - -/** - * This condition allows a runtime value to be access if {@link #type} is reached at run time. - */ -public final class TypeReachedCondition implements RuntimeCondition { - final Class type; - - TypeReachedCondition(Class type) { - this.type = type; - } - - @Override - public boolean isSatisfied() { - return DynamicHub.fromClass(type).isReached(); - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - TypeReachedCondition that = (TypeReachedCondition) o; - return Objects.equals(type, that.type); - } - - @Override - public int hashCode() { - return Objects.hashCode(type); - } - - @Override - public Set> getTypesForEncoding() { - return Set.of(type); - } - - @Override - public String toString() { - return type.getName(); - } -} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java index 1910250a15d0d..2e3dccc75dad2 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/hub/ClassForNameSupport.java @@ -27,7 +27,6 @@ import static com.oracle.svm.core.MissingRegistrationUtils.throwMissingRegistrationErrors; import java.util.Objects; -import java.util.Set; import org.graalvm.collections.EconomicMap; import org.graalvm.nativeimage.ImageSingletons; @@ -190,7 +189,7 @@ public RuntimeConditionSet getConditionFor(Class jClass) { Objects.requireNonNull(jClass); ConditionalRuntimeValue conditionalClass = knownClasses.get(jClass.getName()); if (conditionalClass == null) { - return RuntimeConditionSet.createRuntime(Set.of()); + return RuntimeConditionSet.unmodifiableEmptySet(); } else { return conditionalClass.getConditions(); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java index a20aa5ed64cf7..43d25b8661c83 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/proxy/DynamicProxySupport.java @@ -100,7 +100,7 @@ public synchronized void addProxyClass(ConfigurationCondition condition, Class(RuntimeConditionSet.createHosted(), createProxyClass(intfs))); + proxyCache.put(key, new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), createProxyClass(intfs))); } proxyCache.get(key).getConditions().addCondition(condition); } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_AccessibleObject.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_AccessibleObject.java index 0c904ce390743..95bbfe1de8e40 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_AccessibleObject.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/target/Target_java_lang_reflect_AccessibleObject.java @@ -33,6 +33,7 @@ import com.oracle.svm.core.annotate.RecomputeFieldValue; import com.oracle.svm.core.annotate.TargetClass; import com.oracle.svm.core.configure.RuntimeConditionSet; +import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; @TargetClass(value = AccessibleObject.class) public final class Target_java_lang_reflect_AccessibleObject { @@ -61,10 +62,16 @@ public Object transform(Object receiver, Object originalValue) { } } - static class SatisfiedConditionComputer extends ReflectionMetadataComputer { + static class SatisfiedConditionComputer implements FieldValueTransformerWithAvailability { @Override public Object transform(Object receiver, Object originalValue) { return RuntimeConditionSet.unmodifiableEmptySet(); } + + @Override + public final ValueAvailability valueAvailability() { + return ValueAvailability.BeforeAnalysis; + } + } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java index b4561f2cd4d67..fc06c960ee337 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationSupport.java @@ -494,7 +494,7 @@ private static void addAllInterfaces(Class clazz, EconomicSet> resul } public void addForTypeReachedTracking(Class clazz) { - if (TrackTypeReachedOnInterfaces.getValue() && clazz.isInterface() && metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) { + if (TrackTypeReachedOnInterfaces.getValue() && clazz.isInterface() && !metaAccess.lookupJavaType(clazz).declaresDefaultMethods()) { LogUtils.info("Detected 'typeReached' on interface type without default methods: " + clazz); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RuntimeMetadataEncoderImpl.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RuntimeMetadataEncoderImpl.java index d35dd7bbaec50..e6beea0422b5f 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RuntimeMetadataEncoderImpl.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/RuntimeMetadataEncoderImpl.java @@ -574,7 +574,7 @@ public void addHidingFieldMetadata(AnalysisField analysisField, HostedType decla encoders.classes.addObject(type.getJavaClass()); addType(declaringType); - registerField(declaringType, analysisField, new FieldMetadata(RuntimeConditionSet.createHosted(), declaringType, name, type, modifiers)); + registerField(declaringType, analysisField, new FieldMetadata(RuntimeConditionSet.emptySet(), declaringType, name, type, modifiers)); } @Override @@ -587,7 +587,7 @@ public void addHidingMethodMetadata(AnalysisMethod analysisMethod, HostedType de encoders.classes.addObject(returnType.getJavaClass()); addType(declaringType); - registerMethod(declaringType, analysisMethod, new MethodMetadata(RuntimeConditionSet.createHosted(), declaringType, name, parameterTypes, modifiers, returnType)); + registerMethod(declaringType, analysisMethod, new MethodMetadata(RuntimeConditionSet.emptySet(), declaringType, name, parameterTypes, modifiers, returnType)); } @Override @@ -598,7 +598,7 @@ public void addReachableFieldMetadata(HostedField field) { /* Fill encoders with the necessary values. */ encoders.memberNames.addObject(name); - registerField(declaringType, field, new FieldMetadata(RuntimeConditionSet.createHosted(), declaringType, name, false)); + registerField(declaringType, field, new FieldMetadata(RuntimeConditionSet.emptySet(), declaringType, name, false)); } @Override @@ -617,16 +617,16 @@ public void addReachableExecutableMetadata(HostedMethod executable) { } if (isMethod) { - registerMethod(declaringType, executable, new MethodMetadata(RuntimeConditionSet.createHosted(), declaringType, name, parameterTypeNames)); + registerMethod(declaringType, executable, new MethodMetadata(RuntimeConditionSet.emptySet(), declaringType, name, parameterTypeNames)); } else { - registerConstructor(declaringType, executable, new ConstructorMetadata(RuntimeConditionSet.createHosted(), declaringType, parameterTypeNames)); + registerConstructor(declaringType, executable, new ConstructorMetadata(RuntimeConditionSet.emptySet(), declaringType, parameterTypeNames)); } } @Override public void addNegativeFieldQueryMetadata(HostedType declaringClass, String fieldName) { encoders.memberNames.addObject(fieldName); - registerField(declaringClass, fieldName, new FieldMetadata(RuntimeConditionSet.createHosted(), declaringClass, fieldName, true)); + registerField(declaringClass, fieldName, new FieldMetadata(RuntimeConditionSet.emptySet(), declaringClass, fieldName, true)); } @Override @@ -635,7 +635,7 @@ public void addNegativeMethodQueryMetadata(HostedType declaringClass, String met for (HostedType parameterType : parameterTypes) { encoders.classes.addObject(parameterType.getJavaClass()); } - registerMethod(declaringClass, Pair.create(methodName, parameterTypes), new MethodMetadata(RuntimeConditionSet.createHosted(), declaringClass, methodName, parameterTypes)); + registerMethod(declaringClass, Pair.create(methodName, parameterTypes), new MethodMetadata(RuntimeConditionSet.emptySet(), declaringClass, methodName, parameterTypes)); } @Override @@ -643,7 +643,7 @@ public void addNegativeConstructorQueryMetadata(HostedType declaringClass, Hoste for (HostedType parameterType : parameterTypes) { encoders.classes.addObject(parameterType.getJavaClass()); } - registerConstructor(declaringClass, parameterTypes, new ConstructorMetadata(RuntimeConditionSet.createHosted(), declaringClass, parameterTypes)); + registerConstructor(declaringClass, parameterTypes, new ConstructorMetadata(RuntimeConditionSet.emptySet(), declaringClass, parameterTypes)); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java index 400dced8dab3e..28dd710b611de 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/config/ConfigurationParserUtils.java @@ -138,6 +138,7 @@ private static void doParseAndRegister(ConfigurationParser parser, String featur if (errorMessage == null || errorMessage.isEmpty()) { errorMessage = e.toString(); } + e.printStackTrace(); throw UserError.abort( "Error parsing %s configuration in %s:%n%s%nVerify that the configuration matches the corresponding schema at " + "https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/assets/", 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 193172e7e4433..2584825ea35cc 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 @@ -37,6 +37,7 @@ import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.ALL_PERMITTED_SUBCLASSES_FLAG; import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.ALL_RECORD_COMPONENTS_FLAG; import static com.oracle.svm.core.code.RuntimeMetadataDecoderImpl.ALL_SIGNERS_FLAG; +import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllTypeReachableConditionsAsTypeReached; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Executable; @@ -86,8 +87,8 @@ import com.oracle.svm.core.util.UserError; import com.oracle.svm.core.util.VMError; import com.oracle.svm.hosted.ConditionalConfigurationRegistry; -import com.oracle.svm.hosted.LinkAtBuildTimeSupport; import com.oracle.svm.hosted.FeatureImpl.BeforeAnalysisAccessImpl; +import com.oracle.svm.hosted.LinkAtBuildTimeSupport; import com.oracle.svm.hosted.annotation.AnnotationMemberValue; import com.oracle.svm.hosted.annotation.AnnotationValue; import com.oracle.svm.hosted.annotation.SubstrateAnnotationExtractor; @@ -218,7 +219,9 @@ public void registerAllClassesQuery(ConfigurationCondition condition, Class c */ @SuppressWarnings("unused") private static void guaranteeNotRuntimeConditionForQueries(ConfigurationCondition cnd, boolean queriedOnly) { - VMError.guarantee(!queriedOnly || cnd.isAlwaysTrue() || !cnd.isRuntimeChecked(), "Bulk queries can only be set with 'name' which does not allow run-time conditions."); + if (!TreatAllTypeReachableConditionsAsTypeReached.getValue()) { + VMError.guarantee(!queriedOnly || cnd.isAlwaysTrue() || !cnd.isRuntimeChecked(), "Bulk queries can only be set with 'name' which does not allow run-time conditions."); + } } @Override @@ -413,7 +416,7 @@ private void registerMethod(ConfigurationCondition cnd, boolean queriedOnly, Exe AnalysisMethod analysisMethod = metaAccess.lookupJavaMethod(reflectExecutable); var exists = registeredMethods.containsKey(analysisMethod); - var conditionalValue = registeredMethods.computeIfAbsent(analysisMethod, (t) -> new ConditionalRuntimeValue<>(RuntimeConditionSet.createHosted(), reflectExecutable)); + var conditionalValue = registeredMethods.computeIfAbsent(analysisMethod, (t) -> new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectExecutable)); if (!queriedOnly) { /* queryOnly methods are conditioned by the type itself */ conditionalValue.getConditions().addCondition(cnd); @@ -555,7 +558,7 @@ private void registerField(ConfigurationCondition cnd, boolean queriedOnly, Fiel } } - var cndValue = registeredFields.computeIfAbsent(analysisField, f -> new ConditionalRuntimeValue<>(RuntimeConditionSet.createHosted(), reflectField)); + var cndValue = registeredFields.computeIfAbsent(analysisField, f -> new ConditionalRuntimeValue<>(RuntimeConditionSet.emptySet(), reflectField)); cndValue.getConditions().addCondition(cnd); /* diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java index 530c1eefb6312..e0a42e10d1875 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/reflect/ReflectionFeature.java @@ -55,7 +55,6 @@ import com.oracle.svm.core.configure.ConfigurationFile; import com.oracle.svm.core.configure.ConfigurationFiles; import com.oracle.svm.core.configure.ReflectionConfigurationParser; -import com.oracle.svm.core.configure.RuntimeConditionSet; import com.oracle.svm.core.feature.AutomaticallyRegisteredFeature; import com.oracle.svm.core.feature.InternalFeature; import com.oracle.svm.core.fieldvaluetransformer.FieldValueTransformerWithAvailability; @@ -335,8 +334,6 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { /* Make sure array classes don't need to be registered for reflection. */ RuntimeReflection.register(Object.class.getDeclaredMethods()); - - access.registerAsInHeap(RuntimeConditionSet.UnmodifiableRuntimeConditionSet.class); } @Override